mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-24 05:25:18 +00:00
snapshot: wire up disk-only flag to snapshot-create
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.
This commit is contained in:
parent
e03a62b456
commit
35d52b56bb
@ -67,6 +67,26 @@ for args in \
|
|||||||
virsh -d0 -c $test_url setvcpus $args >out 2>>err || fail=1
|
virsh -d0 -c $test_url setvcpus $args >out 2>>err || fail=1
|
||||||
LC_ALL=C sort out | compare - exp-out || fail=1
|
LC_ALL=C sort out | compare - exp-out || fail=1
|
||||||
done
|
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
|
test -s err && fail=1
|
||||||
|
|
||||||
(exit $fail); exit $fail
|
(exit $fail); exit $fail
|
||||||
|
@ -12166,6 +12166,7 @@ static const vshCmdOptDef opts_snapshot_create[] = {
|
|||||||
{"current", VSH_OT_BOOL, 0, N_("with redefine, set current snapshot")},
|
{"current", VSH_OT_BOOL, 0, N_("with redefine, set current snapshot")},
|
||||||
{"no-metadata", VSH_OT_BOOL, 0, N_("take snapshot but create no metadata")},
|
{"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")},
|
{"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}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12186,6 +12187,8 @@ cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
|
|||||||
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
|
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
|
||||||
if (vshCommandOptBool(cmd, "halt"))
|
if (vshCommandOptBool(cmd, "halt"))
|
||||||
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
|
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
|
||||||
|
if (vshCommandOptBool(cmd, "disk-only"))
|
||||||
|
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;
|
||||||
|
|
||||||
if (!vshConnectionUsability(ctl, ctl->conn))
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -12224,6 +12227,62 @@ cleanup:
|
|||||||
/*
|
/*
|
||||||
* "snapshot-create-as" command
|
* "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[] = {
|
static const vshCmdInfo info_snapshot_create_as[] = {
|
||||||
{"help", N_("Create a snapshot from a set of args")},
|
{"help", N_("Create a snapshot from a set of args")},
|
||||||
{"desc", N_("Create a snapshot (disk and RAM) from arguments")},
|
{"desc", N_("Create a snapshot (disk and RAM) from arguments")},
|
||||||
@ -12237,6 +12296,9 @@ static const vshCmdOptDef opts_snapshot_create_as[] = {
|
|||||||
{"print-xml", VSH_OT_BOOL, 0, N_("print XML document rather than create")},
|
{"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")},
|
{"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")},
|
{"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}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12250,11 +12312,14 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
|
|||||||
const char *desc = NULL;
|
const char *desc = NULL;
|
||||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
|
const vshCmdOpt *opt = NULL;
|
||||||
|
|
||||||
if (vshCommandOptBool(cmd, "no-metadata"))
|
if (vshCommandOptBool(cmd, "no-metadata"))
|
||||||
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
|
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
|
||||||
if (vshCommandOptBool(cmd, "halt"))
|
if (vshCommandOptBool(cmd, "halt"))
|
||||||
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
|
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_HALT;
|
||||||
|
if (vshCommandOptBool(cmd, "disk-only"))
|
||||||
|
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;
|
||||||
|
|
||||||
if (!vshConnectionUsability(ctl, ctl->conn))
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -12274,6 +12339,16 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
|
|||||||
virBufferEscapeString(&buf, " <name>%s</name>\n", name);
|
virBufferEscapeString(&buf, " <name>%s</name>\n", name);
|
||||||
if (desc)
|
if (desc)
|
||||||
virBufferEscapeString(&buf, " <description>%s</description>\n", 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");
|
virBufferAddLit(&buf, "</domainsnapshot>\n");
|
||||||
|
|
||||||
buffer = virBufferContentAndReset(&buf);
|
buffer = virBufferContentAndReset(&buf);
|
||||||
@ -12283,11 +12358,6 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vshCommandOptBool(cmd, "print-xml")) {
|
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);
|
vshPrint(ctl, "%s\n", buffer);
|
||||||
ret = true;
|
ret = true;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -13437,12 +13507,8 @@ vshCmddefGetOption(vshControl *ctl, const vshCmdDef *cmd, const char *name,
|
|||||||
vshError(ctl, _("option --%s already seen"), name);
|
vshError(ctl, _("option --%s already seen"), name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (opt->type == VSH_OT_ARGV) {
|
if (opt->type != VSH_OT_ARGV)
|
||||||
vshError(ctl, _("variable argument <%s> "
|
*opts_seen |= 1 << i;
|
||||||
"should not be used with --<%s>"), name, name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*opts_seen |= 1 << i;
|
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1718,11 +1718,12 @@ used to represent properties of snapshots.
|
|||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
=item B<snapshot-create> I<domain> [I<xmlfile>] {[I<--redefine> [I<--current>]]
|
=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
|
Create a snapshot for domain I<domain> with the properties specified in
|
||||||
I<xmlfile>. Normally, the only properties settable for a domain snapshot
|
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
|
ignored, and automatically filled in by libvirt. If I<xmlfile> is
|
||||||
completely omitted, then libvirt will choose a value for all fields.
|
completely omitted, then libvirt will choose a value for all fields.
|
||||||
The new snapshot will become current, as listed by B<snapshot-current>.
|
The new snapshot will become current, as listed by B<snapshot-current>.
|
||||||
@ -1730,6 +1731,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
|
If I<--halt> is specified, the domain will be left in an inactive state
|
||||||
after the snapshot is created.
|
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
|
If I<--redefine> is specified, then all XML elements produced by
|
||||||
B<snapshot-dumpxml> are valid; this can be used to migrate snapshot
|
B<snapshot-dumpxml> are valid; this can be used to migrate snapshot
|
||||||
hierarchy from one machine to another, to recreate hierarchy for the
|
hierarchy from one machine to another, to recreate hierarchy for the
|
||||||
@ -1753,13 +1762,26 @@ by command such as B<destroy> or by internal guest action).
|
|||||||
|
|
||||||
=item B<snapshot-create-as> I<domain> {[I<--print-xml>]
|
=item B<snapshot-create-as> I<domain> {[I<--print-xml>]
|
||||||
| [I<--no-metadata>] [I<--halt>]} [I<name>] [I<description>]
|
| [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
|
Create a snapshot for domain I<domain> with the given <name> and
|
||||||
<description>; if either value is omitted, libvirt will choose a
|
<description>; if either value is omitted, libvirt will choose a
|
||||||
value. If I<--print-xml> is specified, then XML appropriate for
|
value. If I<--print-xml> is specified, then XML appropriate for
|
||||||
I<snapshot-create> is output, rather than actually creating a snapshot.
|
I<snapshot-create> is output, rather than actually creating a snapshot.
|
||||||
Otherwise, if I<--halt> is specified, the domain will be left in an
|
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,
|
If I<--no-metadata> is specified, then the snapshot data is created,
|
||||||
but any metadata is immediately discarded (that is, libvirt does not
|
but any metadata is immediately discarded (that is, libvirt does not
|
||||||
|
Loading…
x
Reference in New Issue
Block a user