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

Reply via email to