{"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}
};
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;
/*
* "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")},
{"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}
};
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;
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);
}
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;
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;
}
}
=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>.
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
=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