mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-09 09:14:57 +00:00
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:
parent
90ec08ed73
commit
2b4d8deb6b
164
tools/virsh.c
164
tools/virsh.c
@ -11931,7 +11931,10 @@ vshSnapshotCreate(vshControl *ctl, virDomainPtr dom, const char *buffer,
|
|||||||
if (snapshot == NULL)
|
if (snapshot == NULL)
|
||||||
goto cleanup;
|
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)
|
if (!doc)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -11975,6 +11978,9 @@ static const vshCmdInfo info_snapshot_create[] = {
|
|||||||
static const vshCmdOptDef opts_snapshot_create[] = {
|
static const vshCmdOptDef opts_snapshot_create[] = {
|
||||||
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
|
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
|
||||||
{"xmlfile", VSH_OT_DATA, 0, N_("domain snapshot XML")},
|
{"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}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -11985,6 +11991,14 @@ cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
|
|||||||
bool ret = false;
|
bool ret = false;
|
||||||
const char *from = NULL;
|
const char *from = NULL;
|
||||||
char *buffer = 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))
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -12010,7 +12024,7 @@ cmdSnapshotCreate(vshControl *ctl, const vshCmd *cmd)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = vshSnapshotCreate(ctl, dom, buffer, 0, from);
|
ret = vshSnapshotCreate(ctl, dom, buffer, flags, from);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(buffer);
|
VIR_FREE(buffer);
|
||||||
@ -12034,6 +12048,7 @@ static const vshCmdOptDef opts_snapshot_create_as[] = {
|
|||||||
{"name", VSH_OT_DATA, 0, N_("name of snapshot")},
|
{"name", VSH_OT_DATA, 0, N_("name of snapshot")},
|
||||||
{"description", VSH_OT_DATA, 0, N_("description of snapshot")},
|
{"description", VSH_OT_DATA, 0, N_("description of snapshot")},
|
||||||
{"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")},
|
||||||
{NULL, 0, 0, NULL}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12046,6 +12061,10 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
|
|||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
const char *desc = NULL;
|
const char *desc = NULL;
|
||||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
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))
|
if (!vshConnectionUsability(ctl, ctl->conn))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -12079,7 +12098,7 @@ cmdSnapshotCreateAs(vshControl *ctl, const vshCmd *cmd)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = vshSnapshotCreate(ctl, dom, buffer, 0, NULL);
|
ret = vshSnapshotCreate(ctl, dom, buffer, flags, NULL);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(buffer);
|
VIR_FREE(buffer);
|
||||||
@ -12089,12 +12108,113 @@ cleanup:
|
|||||||
return ret;
|
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
|
* "snapshot-current" command
|
||||||
*/
|
*/
|
||||||
static const vshCmdInfo info_snapshot_current[] = {
|
static const vshCmdInfo info_snapshot_current[] = {
|
||||||
{"help", N_("Get the current snapshot")},
|
{"help", N_("Get or set the current snapshot")},
|
||||||
{"desc", N_("Get the current snapshot")},
|
{"desc", N_("Get or set the current snapshot")},
|
||||||
{NULL, NULL}
|
{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")},
|
{"name", VSH_OT_BOOL, 0, N_("list the name, rather than the full xml")},
|
||||||
{"security-info", VSH_OT_BOOL, 0,
|
{"security-info", VSH_OT_BOOL, 0,
|
||||||
N_("include security sensitive information in XML dump")},
|
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}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12114,6 +12236,7 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
int current;
|
int current;
|
||||||
virDomainSnapshotPtr snapshot = NULL;
|
virDomainSnapshotPtr snapshot = NULL;
|
||||||
char *xml = NULL;
|
char *xml = NULL;
|
||||||
|
const char *snapshotname = NULL;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
|
|
||||||
if (vshCommandOptBool(cmd, "security-info"))
|
if (vshCommandOptBool(cmd, "security-info"))
|
||||||
@ -12126,6 +12249,35 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd)
|
|||||||
if (dom == NULL)
|
if (dom == NULL)
|
||||||
goto cleanup;
|
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);
|
current = virDomainHasCurrentSnapshot(dom, 0);
|
||||||
if (current < 0)
|
if (current < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -12960,6 +13112,8 @@ static const vshCmdDef snapshotCmds[] = {
|
|||||||
info_snapshot_delete, 0},
|
info_snapshot_delete, 0},
|
||||||
{"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml,
|
{"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml,
|
||||||
info_snapshot_dumpxml, 0},
|
info_snapshot_dumpxml, 0},
|
||||||
|
{"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit,
|
||||||
|
info_snapshot_edit, 0},
|
||||||
{"snapshot-list", cmdSnapshotList, opts_snapshot_list,
|
{"snapshot-list", cmdSnapshotList, opts_snapshot_list,
|
||||||
info_snapshot_list, 0},
|
info_snapshot_list, 0},
|
||||||
{"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent,
|
{"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent,
|
||||||
|
@ -1685,15 +1685,33 @@ used to represent properties of snapshots.
|
|||||||
|
|
||||||
=over 4
|
=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
|
Create a snapshot for domain I<domain> with the properties specified in
|
||||||
I<xmlfile>. The only properties settable for a domain snapshot are the
|
I<xmlfile>. Normally, the only properties settable for a domain snapshot
|
||||||
<name> and <description>; the rest of the fields are ignored, and
|
are the <name> and <description> elements; the rest of the fields are
|
||||||
automatically filled in by libvirt. If I<xmlfile> is completely omitted,
|
ignored, and automatically filled in by libvirt. If I<xmlfile> is
|
||||||
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>.
|
||||||
|
|
||||||
=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>]
|
[I<name>] [I<description>]
|
||||||
|
|
||||||
Create a snapshot for domain I<domain> with the given <name> and
|
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
|
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.
|
||||||
|
|
||||||
=item B<snapshot-current> I<domain> [I<--name>]
|
If I<--no-metadata> is specified, then the snapshot data is created,
|
||||||
=item B<snapshot-current> I<domain> {[I<--name>] | [I<--security-info]}
|
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).
|
=item B<snapshot-current> I<domain> {[I<--name>] | [I<--security-info]
|
||||||
If I<--name> is specified, just print the current snapshot name instead
|
| [I<snapshotname>]}
|
||||||
of the full xml. Otherwise, using I<--security-info> will also include
|
|
||||||
security sensitive information in the XML.
|
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>]
|
=item B<snapshot-list> I<domain> [{I<--parent> | I<--roots>}] [I<--metadata>]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user