]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
bhyve: implement the virDomainRename API
authorRoman Bogorodskiy <bogorodskiy@gmail.com>
Sat, 4 Jul 2026 05:26:57 +0000 (07:26 +0200)
committerRoman Bogorodskiy <bogorodskiy@gmail.com>
Fri, 10 Jul 2026 16:36:33 +0000 (18:36 +0200)
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 <bogorodskiy@gmail.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
src/bhyve/bhyve_domain.c
src/bhyve/bhyve_domain.h
src/bhyve/bhyve_driver.c

index 86e4de1fd816ad9b73e4c3ba5379965f600ee1f9..d5bb22501cfdd6935b25122ef52aa72ed16c654e 100644 (file)
@@ -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;
+}
index 888ef2f84bbcea44ee64c1be5dfe1e1d7a1ce9d5..fa7a685d59edd4946ee723e0e1b6ca1f0008f458 100644 (file)
@@ -54,3 +54,4 @@ extern virXMLNamespace virBhyveDriverDomainXMLNamespace;
 
 int virBhyveDomainObjStartWorker(virDomainObj *dom);
 void virBhyveDomainObjStopWorker(virDomainObj *dom);
+int bhyveDomainNamePathsCleanup(const char *name, bool bestEffort);
index 45e8aad5b5277269a4608a1f0cf7e114cc5e5d9d..668e46ad372bf64916a00e2befcb57d54f126c61 100644 (file)
@@ -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 */
 };