From: Roman Bogorodskiy Date: Sat, 4 Jul 2026 05:26:57 +0000 (+0200) Subject: bhyve: implement the virDomainRename API X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0526e5f5f5a070e5396399f004c4e252cb65ac2c;p=thirdparty%2Flibvirt.git bhyve: implement the virDomainRename API 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 Reviewed-by: Peter Krempa --- 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..668e46ad37 100644 --- a/src/bhyve/bhyve_driver.c +++ b/src/bhyve/bhyve_driver.c @@ -2683,6 +2683,130 @@ 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 = g_steal_pointer(&vm->def->name); + vm->def->name = g_steal_pointer(&new_dom_name); + + 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 (ret < 0) { + if (old_dom_name) { + new_dom_name = vm->def->name; + vm->def->name = old_dom_name; + old_dom_name = NULL; + } + + virErrorPreserveLast(&err); + bhyveDomainNamePathsCleanup(new_dom_name, true); + } else { + bhyveDomainNamePathsCleanup(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 +2884,7 @@ static virHypervisorDriver bhyveHypervisorDriver = { .domainSetUserPassword = bhyveDomainSetUserPassword, /* 12.6.0 */ .domainAuthorizedSSHKeysGet = bhyveDomainAuthorizedSSHKeysGet, /* 12.6.0 */ .domainAuthorizedSSHKeysSet = bhyveDomainAuthorizedSSHKeysSet, /* 12.6.0 */ + .domainRename = bhyveDomainRename, /* 12.6.0 */ };