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;
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}
};
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;
goto cleanup;
}
- ret = vshSnapshotCreate(ctl, dom, buffer, 0, from);
+ ret = vshSnapshotCreate(ctl, dom, buffer, flags, from);
cleanup:
VIR_FREE(buffer);
{"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}
};
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;
goto cleanup;
}
- ret = vshSnapshotCreate(ctl, dom, buffer, 0, NULL);
+ ret = vshSnapshotCreate(ctl, dom, buffer, flags, NULL);
cleanup:
VIR_FREE(buffer);
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}
};
{"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}
};
int current;
virDomainSnapshotPtr snapshot = NULL;
char *xml = NULL;
+ const char *snapshotname = NULL;
unsigned int flags = 0;
if (vshCommandOptBool(cmd, "security-info"))
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;
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,
=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.
-
-=item B<snapshot-create-as> I<domain> [I<--print-xml>]
+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>.
+
+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
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>.
+
+=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.
-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-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>]