Signed-off-by: Nikolai Barybin <nikolai.bary...@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

Reply via email to