[PATCH 3/3] tools: virsh: introduce blockrebase-params cmd

Nikolai Barybin via Devel posted 3 patches 1 week, 2 days ago
[PATCH 3/3] tools: virsh: introduce blockrebase-params cmd
Posted by Nikolai Barybin via Devel 1 week, 2 days ago
Signed-off-by: Nikolai Barybin <nikolai.barybin@virtuozzo.com>
---
 docs/manpages/virsh.rst |  39 ++++++++++
 tools/virsh-domain.c    | 160 ++++++++++++++++++++++++++++++++++++++++
 tools/vsh.c             |  14 ++++
 tools/vsh.h             |   2 +
 4 files changed, 215 insertions(+)

diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
index bcb5495ed9..16c4f5d28d 100644
--- a/docs/manpages/virsh.rst
+++ b/docs/manpages/virsh.rst
@@ -1626,6 +1626,45 @@ on the *bandwidth* argument see the corresponding section for the ``blockjob``
 command.
 
 
+blockrebase-params
+------------------
+
+**Syntax:**
+
+::
+
+   blockrebase-params domain path [bandwidth] [base]
+      [--wait [--verbose] [--timeout seconds] [--async]]
+      [--keep-relative]
+
+Populate a disk from its backing image chain. By default, this command
+flattens the entire chain; but if *base* is specified, containing the
+name of one of the backing files in the chain, then that file becomes
+the new backing file and only the intermediate portion of the chain is
+pulled.  Once all requested data from the backing image chain has been
+pulled, the disk no longer depends on that portion of the backing chain.
+
+By default, this command returns as soon as possible, and data for
+the entire disk is pulled in the background; the progress of the
+operation can be checked with ``blockjob``.  However, if *--wait* is
+specified, then this command will block until the operation completes,
+or cancel the operation if the optional *timeout* in seconds elapses
+or SIGINT is sent (usually with ``Ctrl-C``).  Using *--verbose* along
+with *--wait* will produce periodic status updates.  If job cancellation
+is triggered, *--async* will return control to the user as fast as
+possible, otherwise the command may continue to block a little while
+longer until the job is done cleaning up.
+
+Using the *--keep-relative* flag will keep the backing chain names
+relative.
+
+*path* specifies fully-qualified path of the disk; it corresponds
+to a unique target name (<target dev='name'/>) or source file (<source
+file='name'/>) for one of the disk devices attached to *domain* (see
+also ``domblklist`` for listing these names).
+*bandwidth* specifies copying bandwidth limit in Bytes/s.
+
+
 blockresize
 -----------
 
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 6e18d195e6..9023f8f72d 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -3306,6 +3306,160 @@ cmdBlockpull(vshControl *ctl, const vshCmd *cmd)
     return ret;
 }
 
+/*
+ * "blockrebase-params" command
+ */
+static const vshCmdInfo info_blockrebase_params = {
+    .help = N_("Populate a disk from its backing image."),
+    .desc = N_("Populate a disk from its backing image."),
+};
+
+static const vshCmdOptDef opts_blockrebase_params[] = {
+    VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
+    {.name = "path",
+     .type = VSH_OT_STRING,
+     .positional = true,
+     .required = true,
+     .completer = virshDomainDiskTargetCompleter,
+     .help = N_("fully-qualified path of disk")
+    },
+    {.name = "bandwidth",
+     .type = VSH_OT_INT,
+     .unwanted_positional = true,
+     .help = N_("bandwidth limit in bytes/s")
+    },
+    {.name = "base",
+     .type = VSH_OT_STRING,
+     .unwanted_positional = true,
+     .completer = virshDomainBlockjobBaseTopCompleter,
+     .help = N_("path of backing file in chain specifying a new base")
+    },
+    {.name = "wait",
+     .type = VSH_OT_BOOL,
+     .help = N_("wait for job to finish")
+    },
+    {.name = "verbose",
+     .type = VSH_OT_BOOL,
+     .help = N_("with --wait, display the progress")
+    },
+    {.name = "timeout",
+     .type = VSH_OT_INT,
+     .unwanted_positional = true,
+     .help = N_("with --wait, abort if rebase exceeds timeout (in seconds)")
+    },
+    {.name = "async",
+     .type = VSH_OT_BOOL,
+     .help = N_("with --wait, don't wait for cancel to finish")
+    },
+    {.name = "keep-relative",
+     .type = VSH_OT_BOOL,
+     .help = N_("keep the backing chain relatively referenced")
+    },
+    {.name = NULL}
+};
+
+static bool
+cmdBlockrebaseParams(vshControl *ctl, const vshCmd *cmd)
+{
+    g_autoptr(virshDomain) dom = NULL;
+    bool ret = false;
+    bool blocking = vshCommandOptBool(cmd, "wait");
+    bool verbose = vshCommandOptBool(cmd, "verbose");
+    bool async = vshCommandOptBool(cmd, "async");
+    int timeout = 0;
+    const char *path = NULL;
+    const char *base = NULL;
+    unsigned long long bandwidth = 0;
+    unsigned int flags = 0;
+    virshBlockJobWaitData *bjWait = NULL;
+    int nparams = 0;
+    int maxparams = 0;
+    virTypedParameterPtr params = NULL;
+
+    VSH_REQUIRE_OPTION("verbose", "wait");
+    VSH_REQUIRE_OPTION("async", "wait");
+
+    if (vshCommandOptString(ctl, cmd, "path", &path) < 0)
+        return false;
+
+    if (vshCommandOptString(ctl, cmd, "base", &base) < 0)
+        return false;
+
+    if (vshBlockRebaseParamsOptionBandwidth(cmd, &bandwidth) < 0)
+        return false;
+
+    if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
+        return false;
+
+    if (vshCommandOptBool(cmd, "keep-relative"))
+        flags |= VIR_DOMAIN_BLOCK_REBASE_PARAMS_RELATIVE;
+
+    if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
+        return false;
+
+    if (blocking &&
+        !(bjWait = virshBlockJobWaitInit(ctl, dom, path, _("Block Rebase Params"),
+                                         verbose, timeout, async)))
+        goto cleanup;
+
+    if (base &&
+        virTypedParamsAddString(&params, &nparams, &maxparams,
+                                VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE,
+                                base) < 0) {
+        vshError(ctl, _("failed to add param %1$s:%2$s to params list"),
+                 VIR_DOMAIN_BLOCK_REBASE_PARAM_BASE, base);
+        goto cleanup;
+    }
+
+    if (bandwidth > 0 &&
+        virTypedParamsAddULLong(&params, &nparams, &maxparams,
+                                VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH,
+                                bandwidth) < 0) {
+        vshError(ctl, _("failed to add param %1$s:%2$llu to params list"),
+                 VIR_DOMAIN_BLOCK_REBASE_PARAM_BANDWIDTH, bandwidth);
+        goto cleanup;
+    }
+
+    if (virDomainBlockRebaseParams(dom, path, params, nparams, flags) < 0)
+        goto cleanup;
+
+    if (!blocking) {
+        vshPrintExtra(ctl, "%s", _("Block Rebase started"));
+        ret = true;
+        goto cleanup;
+    }
+
+    /* Execution continues here only if --wait or friends were specified */
+    switch (virshBlockJobWait(bjWait)) {
+        case -1:
+            goto cleanup;
+
+        case VIR_DOMAIN_BLOCK_JOB_CANCELED:
+            vshPrintExtra(ctl, "\n%s", _("Rebase aborted"));
+            goto cleanup;
+            break;
+
+        case VIR_DOMAIN_BLOCK_JOB_FAILED:
+            vshPrintExtra(ctl, "\n%s", _("Rebase failed"));
+            goto cleanup;
+            break;
+
+        case VIR_DOMAIN_BLOCK_JOB_READY:
+        case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
+            vshPrintExtra(ctl, "\n%s", _("Rebase complete"));
+            break;
+    }
+
+    ret = true;
+
+ cleanup:
+    virshBlockJobWaitFree(bjWait);
+    virTypedParamsFree(params, nparams);
+    params = NULL;
+    nparams = 0;
+    return ret;
+}
+
 /*
  * "blockresize" command
  */
@@ -13976,6 +14130,12 @@ const vshCmdDef domManagementCmds[] = {
      .info = &info_blockpull,
      .flags = 0
     },
+    {.name = "blockrebase-params",
+     .handler = cmdBlockrebaseParams,
+     .opts = opts_blockrebase_params,
+     .info = &info_blockrebase_params,
+     .flags = 0
+    },
     {.name = "blockresize",
      .handler = cmdBlockresize,
      .opts = opts_blockresize,
diff --git a/tools/vsh.c b/tools/vsh.c
index 4aacc5feac..480b54b572 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -1346,6 +1346,20 @@ vshBlockJobOptionBandwidth(vshControl *ctl,
 }
 
 
+int
+vshBlockRebaseParamsOptionBandwidth(const vshCmd *cmd,
+                                    unsigned long long *bandwidth)
+{
+    vshCmdOpt *arg;
+    int ret;
+
+    if ((ret = vshCommandOpt(cmd, "bandwidth", &arg, true)) <= 0)
+        return ret;
+
+    return virStrToLong_ull(arg->data, NULL, 10, bandwidth);
+}
+
+
 /**
  * vshCommandRun:
  * @ctl: virt shell data
diff --git a/tools/vsh.h b/tools/vsh.h
index bd2494e899..0f79c32d41 100644
--- a/tools/vsh.h
+++ b/tools/vsh.h
@@ -287,6 +287,8 @@ int vshBlockJobOptionBandwidth(vshControl *ctl,
                                const vshCmd *cmd,
                                bool bytes,
                                unsigned long *bandwidth);
+int vshBlockRebaseParamsOptionBandwidth(const vshCmd *cmd,
+                                        unsigned long long *bandwidth);
 bool vshCommandOptBool(const vshCmd *cmd, const char *name);
 int vshCommandRun(vshControl *ctl, const vshCmd *cmd);
 bool vshCommandStringParse(vshControl *ctl, char *cmdstr,
-- 
2.43.5
Re: [PATCH 3/3] tools: virsh: introduce blockrebase-params cmd
Posted by Ján Tomko via Devel 1 week, 1 day ago
On a Thursday in 2025, Nikolai Barybin via Devel wrote:
>Signed-off-by: Nikolai Barybin <nikolai.barybin@virtuozzo.com>
>---
> docs/manpages/virsh.rst |  39 ++++++++++
> tools/virsh-domain.c    | 160 ++++++++++++++++++++++++++++++++++++++++
> tools/vsh.c             |  14 ++++
> tools/vsh.h             |   2 +
> 4 files changed, 215 insertions(+)
>
>diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst
>index bcb5495ed9..16c4f5d28d 100644
>--- a/docs/manpages/virsh.rst
>+++ b/docs/manpages/virsh.rst
>@@ -1626,6 +1626,45 @@ on the *bandwidth* argument see the corresponding section for the ``blockjob``
> command.
>
>
>+blockrebase-params

The -params suffix is not of any help for the virsh users.
We only use the Params suffix when we need to add a new API with
parameter support which has an older alternative without them
(we need to keep the older one because we maintain ABI compatibility).

For virsh, the latest version can be used to remotely connect to older
versions of libvirt, so if whatever the user asked for can be satisfied
with the usage of the older API, virsh tries that instead of the new
one.

If the functionality is sufficiently similar to the blockpull command,
I suggest you put it there and only call the new API when the user
requested the extra stuff.

Jano