Implementation is fairly similar to the one found in the test and qemu drivers. Lack of checkpoint and snapshot support in the bhyve driver makes the implementation a bit simpler.
Signed-off-by: Roman Bogorodskiy <[email protected]> --- src/bhyve/bhyve_domain.c | 27 +++++++++ src/bhyve/bhyve_domain.h | 1 + src/bhyve/bhyve_driver.c | 122 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+) diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 86e4de1fd8..d5bb22501c 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -703,3 +703,30 @@ virBhyveDomainObjStopWorker(virDomainObj *dom) g_object_unref(eventThread); virObjectLock(dom); } + +int +bhyveDomainNamePathsCleanup(const char *name, + bool bestEffort) +{ + g_autofree char *cfg_file = NULL; + g_autofree char *autostart_link = NULL; + + cfg_file = virDomainConfigFile(BHYVE_CONFIG_DIR, name); + autostart_link = virDomainConfigFile(BHYVE_AUTOSTART_DIR, name); + + if (virFileExists(cfg_file) && + unlink(cfg_file) < 0) { + virReportSystemError(errno, _("Failed to unlink '%1$s'"), cfg_file); + if (!bestEffort) + return -1; + } + + if (virFileIsLink(autostart_link) == 1 && + unlink(autostart_link) < 0) { + virReportSystemError(errno, _("Failed to unlink '%1$s'"), autostart_link); + if (!bestEffort) + return -1; + } + + return 0; +} diff --git a/src/bhyve/bhyve_domain.h b/src/bhyve/bhyve_domain.h index 888ef2f84b..fa7a685d59 100644 --- a/src/bhyve/bhyve_domain.h +++ b/src/bhyve/bhyve_domain.h @@ -54,3 +54,4 @@ extern virXMLNamespace virBhyveDriverDomainXMLNamespace; int virBhyveDomainObjStartWorker(virDomainObj *dom); void virBhyveDomainObjStopWorker(virDomainObj *dom); +int bhyveDomainNamePathsCleanup(const char *name, bool bestEffort); diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c index 45e8aad5b5..37a7617346 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -2683,6 +2683,127 @@ bhyveDomainAuthorizedSSHKeysSet(virDomainPtr domain, return rv; } +static int +bhyveDomainRenameCallback(virDomainObj *vm, + const char *new_name, + unsigned int flags, + void *opaque) +{ + struct _bhyveConn *privconn = opaque; + virObjectEvent *event_new = NULL; + virObjectEvent *event_old = NULL; + int ret = -1; + virErrorPtr err = NULL; + g_autofree char *new_dom_name = NULL; + g_autofree char *old_dom_name = NULL; + g_autofree char *new_dom_cfg_file = NULL; + g_autofree char *new_dom_autostart_link = NULL; + + virCheckFlags(0, ret); + + if (strchr(new_name, '/')) { + virReportError(VIR_ERR_XML_ERROR, + _("name %1$s cannot contain '/'"), new_name); + return -1; + } + + new_dom_name = g_strdup(new_name); + + new_dom_cfg_file = virDomainConfigFile(BHYVE_CONFIG_DIR, new_dom_name); + + if (bhyveDomainNamePathsCleanup(new_name, false) < 0) + goto cleanup; + + if (vm->autostart) { + new_dom_autostart_link = virDomainConfigFile(BHYVE_AUTOSTART_DIR, new_dom_name); + + if (symlink(new_dom_cfg_file, new_dom_autostart_link) < 0) { + virReportSystemError(errno, + _("Failed to create symlink '%1$s' to '%2$s'"), + new_dom_autostart_link, new_dom_cfg_file); + return -1; + } + } + + /* Switch name in domain definition. */ + old_dom_name = vm->def->name; + vm->def->name = new_dom_name; + new_dom_name = NULL; + + if (virDomainDefSave(vm->def, privconn->xmlopt, BHYVE_CONFIG_DIR) < 0) + goto cleanup; + + event_old = virDomainEventLifecycleNew(vm->def->id, old_dom_name, vm->def->uuid, + VIR_DOMAIN_EVENT_UNDEFINED, + VIR_DOMAIN_EVENT_UNDEFINED_RENAMED); + event_new = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_DEFINED, + VIR_DOMAIN_EVENT_DEFINED_RENAMED); + virObjectEventStateQueue(privconn->domainEventState, event_old); + virObjectEventStateQueue(privconn->domainEventState, event_new); + ret = 0; + + cleanup: + if (old_dom_name && ret < 0) { + new_dom_name = vm->def->name; + vm->def->name = old_dom_name; + old_dom_name = NULL; + } + + if (ret < 0) + virErrorPreserveLast(&err); + bhyveDomainNamePathsCleanup(ret < 0 ? new_dom_name : old_dom_name, true); + virErrorRestore(&err); + return ret; +} + +static int +bhyveDomainRename(virDomainPtr domain, + const char *new_name, + unsigned int flags) +{ + struct _bhyveConn *privconn = domain->conn->privateData; + virDomainObj *vm = NULL; + int ret = -1; + + virCheckFlags(0, ret); + + if (!(vm = bhyveDomObjFromDomain(domain))) + goto cleanup; + + if (virDomainRenameEnsureACL(domain->conn, vm->def) < 0) + goto cleanup; + + if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) + goto cleanup; + + if (!vm->persistent) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cannot rename a transient domain")); + goto endjob; + } + + if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_SHUTOFF) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain has to be shutoff before renaming")); + goto endjob; + } + + if (virDomainObjListRename(privconn->domains, vm, new_name, flags, + bhyveDomainRenameCallback, privconn) < 0) + goto endjob; + + /* Success, domain has been renamed. */ + ret = 0; + + endjob: + virDomainObjEndJob(vm); + + cleanup: + virDomainObjEndAPI(&vm); + return ret; +} + static virHypervisorDriver bhyveHypervisorDriver = { .name = "bhyve", .connectURIProbe = bhyveConnectURIProbe, @@ -2760,6 +2881,7 @@ static virHypervisorDriver bhyveHypervisorDriver = { .domainSetUserPassword = bhyveDomainSetUserPassword, /* 12.6.0 */ .domainAuthorizedSSHKeysGet = bhyveDomainAuthorizedSSHKeysGet, /* 12.6.0 */ .domainAuthorizedSSHKeysSet = bhyveDomainAuthorizedSSHKeysSet, /* 12.6.0 */ + .domainRename = bhyveDomainRename, /* 12.6.0 */ }; -- 2.52.0
