[libvirt] [PATCHv3.5 40/43] snapshot: wire up disk-only flag to snapshot-create

Eric Blake eblake at redhat.com
Thu Sep 1 19:08:04 UTC 2011


Expose the disk-only flag through virsh.  Additionally, make
virsh snapshot-create-as take an arbitrary number of diskspecs,
which can be used to build up the xml for <domainsnapshot>.

* tools/virsh.c (cmdSnapshotCreate): Add --disk-only.
(cmdSnapshotCreateAs): Likewise, and add argv diskspec.
(vshParseSnapshotDiskspec): New helper function.
(vshCmddefGetOption): Allow naming of argv field.
* tools/virsh.pod (snapshot-create, snapshot-create-as): Document
them.
* tests/virsh-optparse: Test snapshot-create-as parsing.
---

I went ahead and implemented a decent solution to the snapshot-create-as
needing to provide multiple disk specs when generating xml.

 tests/virsh-optparse |   20 +++++++++++
 tools/virsh.c        |   88 +++++++++++++++++++++++++++++++++++++++++++------
 tools/virsh.pod      |   28 ++++++++++++++--
 3 files changed, 122 insertions(+), 14 deletions(-)

diff --git a/tests/virsh-optparse b/tests/virsh-optparse
index 7b3a25d..cd5e3eb 100755
--- a/tests/virsh-optparse
+++ b/tests/virsh-optparse
@@ -67,6 +67,26 @@ for args in \
   virsh -d0 -c $test_url setvcpus $args >out 2>>err || fail=1
   LC_ALL=C sort out | compare - exp-out || fail=1
 done
+
+# Another complex parsing example
+cat <<\EOF > exp-out || framework_failure
+<domainsnapshot>
+  <description>1<2</description>
+  <disks>
+    <disk name='vda' snapshot='external'>
+      <source file='a&b,c'/>
+    </disk>
+    <disk name='vdb'/>
+  </disks>
+</domainsnapshot>
+
+
+EOF
+virsh -c $test_url snapshot-create-as --print-xml test \
+  --diskspec 'vda,file=a&b,,c,snapshot=external' --description '1<2' \
+  --diskspec vdb >out 2>>err || fail=1
+compare out exp-out || fail=1
+
 test -s err && fail=1

 (exit $fail); exit $fail
diff --git a/tools/virsh.c b/tools/virsh.c
index 648e62c..c430cfb 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -12153,6 +12153,7 @@ static const vshCmdOptDef opts_snapshot_create[] = {
     {"current", VSH_OT_BOOL, 0, N_("with redefine, set current snapshot")},
     {"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")},
     {"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")},
+    {"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")},
     {NULL, 0, 0, NULL}
 };

@@ -12173,6 +12174,8 @@ cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
         flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
     if (vshCommandOptBool(cmd, "halt"))
         flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
+    if (vshCommandOptBool(cmd, "disk-only"))
+        flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;

     if (!vshConnectionUsability(ctl, ctl->conn))
         goto cleanup;
@@ -12211,6 +12214,62 @@ cleanup:
 /*
  * "snapshot-create-as" command
  */
+static int
+vshParseSnapshotDiskspec(vshControl *ctl, virBufferPtr buf, const char *str)
+{
+    int ret = -1;
+    char *name = NULL;
+    char *snapshot = NULL;
+    char *driver = NULL;
+    char *file = NULL;
+    char *spec = vshStrdup(ctl, str);
+    char *tmp = spec;
+    size_t len = strlen(str);
+
+    if (*str == ',')
+        goto cleanup;
+    name = tmp;
+    while ((tmp = strchr(tmp, ','))) {
+        if (tmp[1] == ',') {
+            /* Recognize ,, as an escape for a literal comma */
+            memmove(&tmp[1], &tmp[2], len - (tmp - spec) + 2);
+            len--;
+            tmp++;
+            continue;
+        }
+        /* Terminate previous string, look for next recognized one */
+        *tmp++ = '\0';
+        if (!snapshot && STRPREFIX(tmp, "snapshot="))
+            snapshot = tmp + strlen("snapshot=");
+        else if (!driver && STRPREFIX(tmp, "driver="))
+            driver = tmp + strlen("driver=");
+        else if (!file && STRPREFIX(tmp, "file="))
+            file = tmp + strlen("file=");
+        else
+            goto cleanup;
+    }
+
+    virBufferEscapeString(buf, "    <disk name='%s'", name);
+    if (snapshot)
+        virBufferAsprintf(buf, " snapshot='%s'", snapshot);
+    if (driver || file) {
+        virBufferAddLit(buf, ">\n");
+        if (driver)
+            virBufferAsprintf(buf, "      <driver type='%s'/>\n", driver);
+        if (file)
+            virBufferEscapeString(buf, "      <source file='%s'/>\n", file);
+        virBufferAddLit(buf, "    </disk>\n");
+    } else {
+        virBufferAddLit(buf, "/>\n");
+    }
+    ret = 0;
+cleanup:
+    if (ret < 0)
+        vshError(ctl, _("unable to parse diskspec: %s"), str);
+    VIR_FREE(spec);
+    return ret;
+}
+
 static const vshCmdInfo info_snapshot_create_as[] = {
     {"help", N_("Create a snapshot from a set of args")},
     {"desc", N_("Create a snapshot (disk and RAM) from arguments")},
@@ -12224,6 +12283,9 @@ static const vshCmdOptDef opts_snapshot_create_as[] = {
     {"print-xml", VSH_OT_BOOL, 0, N_("print XML document rather than create")},
     {"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")},
     {"halt", VSH_OT_BOOL, 0, N_("halt domain after snapshot is created")},
+    {"disk-only", VSH_OT_BOOL, 0, N_("capture disk state but not vm state")},
+    {"diskspec", VSH_OT_ARGV, 0,
+     N_("disk attributes: disk[,snapshot=type][,driver=type][,file=name]")},
     {NULL, 0, 0, NULL}
 };

@@ -12237,11 +12299,14 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
     const char *desc = NULL;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     unsigned int flags = 0;
+    const vshCmdOpt *opt = NULL;

     if (vshCommandOptBool(cmd, "no-metadata"))
         flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
     if (vshCommandOptBool(cmd, "halt"))
         flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
+    if (vshCommandOptBool(cmd, "disk-only"))
+        flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;

     if (!vshConnectionUsability(ctl, ctl->conn))
         goto cleanup;
@@ -12261,6 +12326,16 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
         virBufferEscapeString(&buf, "  <name>%s</name>\n", name);
     if (desc)
         virBufferEscapeString(&buf, "  <description>%s</description>\n", desc);
+    if (vshCommandOptBool(cmd, "diskspec")) {
+        virBufferAddLit(&buf, "  <disks>\n");
+        while ((opt = vshCommandOptArgv(cmd, opt))) {
+            if (vshParseSnapshotDiskspec(ctl, &buf, opt->data) < 0) {
+                virBufferFreeAndReset(&buf);
+                goto cleanup;
+            }
+        }
+        virBufferAddLit(&buf, "  </disks>\n");
+    }
     virBufferAddLit(&buf, "</domainsnapshot>\n");

     buffer = virBufferContentAndReset(&buf);
@@ -12270,11 +12345,6 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
     }

     if (vshCommandOptBool(cmd, "print-xml")) {
-        if (vshCommandOptBool(cmd, "halt")) {
-            vshError(ctl, "%s",
-                     _("--print-xml and --halt are mutually exclusive"));
-            goto cleanup;
-        }
         vshPrint(ctl, "%s\n",  buffer);
         ret = true;
         goto cleanup;
@@ -13327,12 +13397,8 @@ vshCmddefGetOption(vshControl *ctl, const vshCmdDef *cmd, const char *name,
                 vshError(ctl, _("option --%s already seen"), name);
                 return NULL;
             }
-            if (opt->type == VSH_OT_ARGV) {
-                vshError(ctl, _("variable argument <%s> "
-                         "should not be used with --<%s>"), name, name);
-                return NULL;
-            }
-            *opts_seen |= 1 << i;
+            if (opt->type != VSH_OT_ARGV)
+                *opts_seen |= 1 << i;
             return opt;
         }
     }
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 0d1ddd1..e0b9bef 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1706,11 +1706,12 @@ used to represent properties of snapshots.
 =over 4

 =item B<snapshot-create> I<domain> [I<xmlfile>] {[I<--redefine> [I<--current>]]
-| [I<--no-metadata>] [I<--halt>]}
+| [I<--no-metadata>] [I<--halt>] [I<--disk-only>]}

 Create a snapshot for domain I<domain> with the properties specified in
 I<xmlfile>.  Normally, the only properties settable for a domain snapshot
-are the <name> and <description> elements; the rest of the fields are
+are the <name> and <description> elements, as well as <disks> if
+I<--disk-only> is given; the rest of the fields are
 ignored, and automatically filled in by libvirt.  If I<xmlfile> is
 completely omitted, then libvirt will choose a value for all fields.
 The new snapshot will become current, as listed by B<snapshot-current>.
@@ -1718,6 +1719,14 @@ The new snapshot will become current, as listed by B<snapshot-current>.
 If I<--halt> is specified, the domain will be left in an inactive state
 after the snapshot is created.

+If I<--disk-only> is specified, the snapshot will only include disk
+state rather than the usual system checkpoint with vm state.  Disk
+snapshots are faster than full system checkpoints, but reverting to a
+disk snapshot may require fsck or journal replays, since it is like
+the disk state at the point when the power cord is abruptly pulled;
+and mixing I<--halt> and I<--disk-only> loses any data that was not
+flushed to disk at the time.
+
 If I<--redefine> is specified, then all XML elements produced by
 B<snapshot-dumpxml> are valid; this can be used to migrate snapshot
 hierarchy from one machine to another, to recreate hierarchy for the
@@ -1741,13 +1750,26 @@ by command such as B<destroy> or by internal guest action).

 =item B<snapshot-create-as> I<domain> {[I<--print-xml>]
 | [I<--no-metadata>] [I<--halt>]} [I<name>] [I<description>]
+[I<--disk-only> [I<diskspec>]...]

 Create a snapshot for domain I<domain> with the given <name> and
 <description>; if either value is omitted, libvirt will choose a
 value.  If I<--print-xml> is specified, then XML appropriate for
 I<snapshot-create> is output, rather than actually creating a snapshot.
 Otherwise, if I<--halt> is specified, the domain will be left in an
-inactive state after the snapshot is created.
+inactive state after the snapshot is created, and if I<--disk-only>
+is specified, the snapshot will not include vm state.
+
+The I<--disk-only> flag is used to request a disk-only snapshot.  When
+this flag is in use, the command can also take additional I<diskspec>
+arguments to add <disk> elements to the xml.  Each <diskspec> is in the
+form B<disk[,snapshot=type][,driver=type][,file=name]>.  To include a
+literal comma in B<disk> or in B<file=name>, escape it with a second
+comma.  For example, a diskspec of "vda,snapshot=external,file=/path/to,,new"
+results in the following XML:
+  <disk name='vda' snapshot='external'>
+    <source file='/path/to,new'/>
+  </disk>

 If I<--no-metadata> is specified, then the snapshot data is created,
 but any metadata is immediately discarded (that is, libvirt does not
-- 
1.7.4.4




More information about the libvir-list mailing list