snapshot: improve virsh snapshot-create, add snapshot-edit

Wire up the new snapshot creation flags in virsh.  For convenience,
teach 'snapshot-current' how to make an existing snapshot become
current (can be used after upgrading to newer libvirt to recover
from the fact that the older libvirt lost track of the current
snapshot after a restart).  The snapshot-create-as command is
intentionally not taught --redefine or --current, as this would
imply adding a lot of other options for everything else that can
appear in the <domainsnapshot> xml, but which is normally read-only.
Besides, redefining will usually be done on files created by
snapshot-dumpxml, rather than something built up by hand on the
command line.  And now that we can redefine, we can edit.

* tools/virsh.c (cmdSnapshotCreate): Add --redefine, --current,
and --no-metadata.
(cmdSnapshotCreateAs): Add --no-metadata.
(cmdSnapshotCurrent): Add snapshotname to alter current snapshot.
(cmdSnapshotEdit): New command.
* tools/virsh.pod (snapshot-create, snapshot-create-as)
(snapshot-current, snapshot-edit):  Document these.
This commit is contained in:
Eric Blake 2011-09-01 14:21:28 -06:00
parent 90ec08ed73
commit 2b4d8deb6b
2 changed files with 216 additions and 17 deletions

View File

@ -11931,7 +11931,10 @@ vshSnapshotCreate(vshControl *ctl, virDomainPtr dom, const char *buffer,
if (snapshot == NULL)
goto cleanup;
doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)
doc = vshStrdup(ctl, buffer);
else
doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
if (!doc)
goto cleanup;
@ -11975,6 +11978,9 @@ static const vshCmdInfo info_snapshot_create[] = {
static const vshCmdOptDef opts_snapshot_create[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
{"xmlfile", VSH_OT_DATA, 0, N_("domain snapshot XML")},
{"redefine", VSH_OT_BOOL, 0, N_("redefine metadata for existing 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")},
{NULL, 0, 0, NULL}
};
@ -11985,6 +11991,14 @@ cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
bool ret = false;
const char *from = NULL;
char *buffer = NULL;
unsigned int flags = 0;
if (vshCommandOptBool(cmd, "redefine"))
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
if (vshCommandOptBool(cmd, "current"))
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT;
if (vshCommandOptBool(cmd, "no-metadata"))
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
if (!vshConnectionUsability(ctl, ctl->conn))
goto cleanup;
@ -12010,7 +12024,7 @@ cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
goto cleanup;
}
ret = vshSnapshotCreate(ctl, dom, buffer, 0, from);
ret = vshSnapshotCreate(ctl, dom, buffer, flags, from);
cleanup:
VIR_FREE(buffer);
@ -12034,6 +12048,7 @@ static const vshCmdOptDef opts_snapshot_create_as[] = {
{"name", VSH_OT_DATA, 0, N_("name of snapshot")},
{"description", VSH_OT_DATA, 0, N_("description of snapshot")},
{"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")},
{NULL, 0, 0, NULL}
};
@ -12046,6 +12061,10 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
const char *name = NULL;
const char *desc = NULL;
virBuffer buf = VIR_BUFFER_INITIALIZER;
unsigned int flags = 0;
if (vshCommandOptBool(cmd, "no-metadata"))
flags |= VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA;
if (!vshConnectionUsability(ctl, ctl->conn))
goto cleanup;
@ -12079,7 +12098,7 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
goto cleanup;
}
ret = vshSnapshotCreate(ctl, dom, buffer, 0, NULL);
ret = vshSnapshotCreate(ctl, dom, buffer, flags, NULL);
cleanup:
VIR_FREE(buffer);
@ -12089,12 +12108,113 @@ cleanup:
return ret;
}
/*
* "snapshot-edit" command
*/
static const vshCmdInfo info_snapshot_edit[] = {
{"help", N_("edit XML for a snapshot")},
{"desc", N_("Edit the domain snapshot XML for a named snapshot")},
{NULL, NULL}
};
static const vshCmdOptDef opts_snapshot_edit[] = {
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
{"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")},
{"current", VSH_OT_BOOL, 0, N_("also set edited snapshot as current")},
{NULL, 0, 0, NULL}
};
static bool
cmdSnapshotEdit(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom = NULL;
virDomainSnapshotPtr snapshot = NULL;
const char *name;
bool ret = false;
char *tmp = NULL;
char *doc = NULL;
char *doc_edited = NULL;
unsigned int getxml_flags = VIR_DOMAIN_XML_SECURE;
unsigned int define_flags = VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
if (vshCommandOptBool(cmd, "current"))
define_flags |= VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT;
if (!vshConnectionUsability(ctl, ctl->conn))
return false;
if (vshCommandOptString(cmd, "snapshotname", &name) <= 0)
goto cleanup;
dom = vshCommandOptDomain(ctl, cmd, NULL);
if (dom == NULL)
goto cleanup;
snapshot = virDomainSnapshotLookupByName(dom, name, 0);
if (snapshot == NULL)
goto cleanup;
/* Get the XML configuration of the snapshot. */
doc = virDomainSnapshotGetXMLDesc(snapshot, getxml_flags);
if (!doc)
goto cleanup;
virDomainSnapshotFree(snapshot);
snapshot = NULL;
/* Create and open the temporary file. */
tmp = editWriteToTempFile(ctl, doc);
if (!tmp)
goto cleanup;
/* Start the editor. */
if (editFile(ctl, tmp) == -1)
goto cleanup;
/* Read back the edited file. */
doc_edited = editReadBackFile(ctl, tmp);
if (!doc_edited)
goto cleanup;
/* Compare original XML with edited. Short-circuit if it did not
* change, and we do not have any flags. */
if (STREQ(doc, doc_edited) &&
!(define_flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) {
vshPrint(ctl, _("Snapshot %s XML configuration not changed.\n"),
name);
ret = true;
goto cleanup;
}
/* Everything checks out, so redefine the xml. */
snapshot = virDomainSnapshotCreateXML(dom, doc_edited, define_flags);
if (!snapshot) {
vshError(ctl, _("Failed to update %s"), name);
goto cleanup;
}
vshPrint(ctl, _("Snapshot %s edited.\n"), name);
ret = true;
cleanup:
VIR_FREE(doc);
VIR_FREE(doc_edited);
if (tmp) {
unlink(tmp);
VIR_FREE(tmp);
}
if (snapshot)
virDomainSnapshotFree(snapshot);
if (dom)
virDomainFree(dom);
return ret;
}
/*
* "snapshot-current" command
*/
static const vshCmdInfo info_snapshot_current[] = {
{"help", N_("Get the current snapshot")},
{"desc", N_("Get the current snapshot")},
{"help", N_("Get or set the current snapshot")},
{"desc", N_("Get or set the current snapshot")},
{NULL, NULL}
};
@ -12103,6 +12223,8 @@ static const vshCmdOptDef opts_snapshot_current[] = {
{"name", VSH_OT_BOOL, 0, N_("list the name, rather than the full xml")},
{"security-info", VSH_OT_BOOL, 0,
N_("include security sensitive information in XML dump")},
{"snapshotname", VSH_OT_DATA, 0,
N_("name of existing snapshot to make current")},
{NULL, 0, 0, NULL}
};
@ -12114,6 +12236,7 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
int current;
virDomainSnapshotPtr snapshot = NULL;
char *xml = NULL;
const char *snapshotname = NULL;
unsigned int flags = 0;
if (vshCommandOptBool(cmd, "security-info"))
@ -12126,6 +12249,35 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
if (dom == NULL)
goto cleanup;
if (vshCommandOptString(cmd, "snapshotname", &snapshotname) < 0) {
vshError(ctl, _("invalid snapshotname argument '%s'"), snapshotname);
goto cleanup;
}
if (snapshotname) {
virDomainSnapshotPtr snapshot2 = NULL;
flags = (VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT);
if (vshCommandOptBool(cmd, "name")) {
vshError(ctl, "%s",
_("--name and snapshotname are mutually exclusive"));
goto cleanup;
}
snapshot = virDomainSnapshotLookupByName(dom, snapshotname, 0);
if (snapshot == NULL)
goto cleanup;
xml = virDomainSnapshotGetXMLDesc(snapshot, VIR_DOMAIN_XML_SECURE);
if (!xml)
goto cleanup;
snapshot2 = virDomainSnapshotCreateXML(dom, xml, flags);
if (snapshot2 == NULL)
goto cleanup;
virDomainSnapshotFree(snapshot2);
vshPrint(ctl, _("Snapshot %s set as current"), snapshotname);
ret = true;
goto cleanup;
}
current = virDomainHasCurrentSnapshot(dom, 0);
if (current < 0)
goto cleanup;
@ -12960,6 +13112,8 @@ static const vshCmdDef snapshotCmds[] = {
info_snapshot_delete, 0},
{"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml,
info_snapshot_dumpxml, 0},
{"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit,
info_snapshot_edit, 0},
{"snapshot-list", cmdSnapshotList, opts_snapshot_list,
info_snapshot_list, 0},
{"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent,

View File

@ -1685,15 +1685,33 @@ used to represent properties of snapshots.
=over 4
=item B<snapshot-create> I<domain> [I<xmlfile>]
=item B<snapshot-create> I<domain> [I<xmlfile>] {[I<--redefine> [I<--current>]]
| [I<--no-metadata>]}
Create a snapshot for domain I<domain> with the properties specified in
I<xmlfile>. The only properties settable for a domain snapshot are the
<name> and <description>; 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.
I<xmlfile>. Normally, the only properties settable for a domain snapshot
are the <name> and <description> elements; 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>.
=item B<snapshot-create-as> I<domain> [I<--print-xml>]
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
case of a transient domain that goes away and is later recreated with
the same name and UUID, or to make slight alterations in the snapshot
metadata (such as host-specific aspects of the domain XML embedded in
the snapshot). When this flag is supplied, the I<xmlfile> argument
is mandatory, and the domain's current snapshot will not be altered
unless the I<--current> flag is also given.
If I<--no-metadata> is specified, then the snapshot data is created,
but any metadata is immediately discarded (that is, libvirt does not
treat the snapshot as current, and cannot revert to the snapshot
unless I<--redefine> is later used to teach libvirt about the
metadata again).
=item B<snapshot-create-as> I<domain> {[I<--print-xml>] | [I<--no-metadata>]}
[I<name>] [I<description>]
Create a snapshot for domain I<domain> with the given <name> and
@ -1701,13 +1719,40 @@ Create a snapshot for domain I<domain> with the given <name> and
value. If I<--print-xml> is specified, then XML appropriate for
I<snapshot-create> is output, rather than actually creating a snapshot.
=item B<snapshot-current> I<domain> [I<--name>]
=item B<snapshot-current> I<domain> {[I<--name>] | [I<--security-info]}
If I<--no-metadata> is specified, then the snapshot data is created,
but any metadata is immediately discarded (that is, libvirt does not
treat the snapshot as current, and cannot revert to the snapshot
unless B<snapshot-create> is later used to teach libvirt about the
metadata again). This flag is incompatible with I<--print-xml>.
Output the snapshot XML for the domain's current snapshot (if any).
If I<--name> is specified, just print the current snapshot name instead
of the full xml. Otherwise, using I<--security-info> will also include
security sensitive information in the XML.
=item B<snapshot-current> I<domain> {[I<--name>] | [I<--security-info]
| [I<snapshotname>]}
Without I<snapshotname>, this will output the snapshot XML for the domain's
current snapshot (if any). If I<--name> is specified, just the
current snapshot name instead of the full xml. Otherwise, using
I<--security-info> will also include security sensitive information in
the XML.
With I<snapshotname>, this is a request to make the existing named
snapshot become the current snapshot, without reverting the domain.
=item B<snapshot-edit> I<domain> I<snapshotname> [I<--current>]
Edit the XML configuration file for I<snapshotname> of a domain. If
I<--current> is specified, also force the edited snapshot to become
the current snapshot.
This is equivalent to:
virsh snapshot-dumpxml dom name > snapshot.xml
vi snapshot.xml (or make changes with your other text editor)
virsh snapshot-create dom snapshot.xml --redefine [--current]
except that it does some error checking.
The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment
variables, and defaults to C<vi>.
=item B<snapshot-list> I<domain> [{I<--parent> | I<--roots>}] [I<--metadata>]