diff --git a/tools/virsh.c b/tools/virsh.c index 20b3dc5a61..7151694a23 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -12830,6 +12830,8 @@ 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")}, + {"rename", VSH_OT_BOOL, 0, N_("allow renaming an existing snapshot")}, + {"clone", VSH_OT_BOOL, 0, N_("allow cloning to new name")}, {NULL, 0, 0, NULL} }; @@ -12838,13 +12840,23 @@ cmdSnapshotEdit(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom = NULL; virDomainSnapshotPtr snapshot = NULL; + virDomainSnapshotPtr edited = NULL; const char *name; + const char *edited_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; + bool rename_okay = vshCommandOptBool(cmd, "rename"); + bool clone_okay = vshCommandOptBool(cmd, "clone"); + + if (rename_okay && clone_okay) { + vshError(ctl, "%s", + _("--rename and --clone are mutually exclusive")); + return false; + } if (vshCommandOptBool(cmd, "current")) define_flags |= VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT; @@ -12867,8 +12879,6 @@ cmdSnapshotEdit(vshControl *ctl, const vshCmd *cmd) doc = virDomainSnapshotGetXMLDesc(snapshot, getxml_flags); if (!doc) goto cleanup; - virDomainSnapshotFree(snapshot); - snapshot = NULL; /* strstr is safe here, since xml came from libvirt API and not user */ if (strstr(doc, "disk-snapshot")) @@ -12899,13 +12909,36 @@ cmdSnapshotEdit(vshControl *ctl, const vshCmd *cmd) } /* Everything checks out, so redefine the xml. */ - snapshot = virDomainSnapshotCreateXML(dom, doc_edited, define_flags); - if (!snapshot) { + edited = virDomainSnapshotCreateXML(dom, doc_edited, define_flags); + if (!edited) { vshError(ctl, _("Failed to update %s"), name); goto cleanup; } - vshPrint(ctl, _("Snapshot %s edited.\n"), name); + edited_name = virDomainSnapshotGetName(edited); + if (STREQ(name, edited_name)) { + vshPrint(ctl, _("Snapshot %s edited.\n"), name); + } else if (clone_okay) { + vshPrint(ctl, _("Snapshot %s cloned to %s.\n"), name, + edited_name); + } else { + unsigned int delete_flags; + + delete_flags = VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY; + if (virDomainSnapshotDelete(rename_okay ? snapshot : edited, + delete_flags) < 0) { + virshReportError(ctl); + vshError(ctl, _("Failed to clean up %s"), + rename_okay ? name : edited_name); + goto cleanup; + } + if (!rename_okay) { + vshError(ctl, _("Must use --rename or --clone to change %s to %s"), + name, edited_name); + goto cleanup; + } + } + ret = true; cleanup: @@ -12917,6 +12950,8 @@ cleanup: } if (snapshot) virDomainSnapshotFree(snapshot); + if (edited) + virDomainSnapshotFree(edited); if (dom) virDomainFree(dom); return ret; diff --git a/tools/virsh.pod b/tools/virsh.pod index 1f7c76f3d2..8ce41fb5d4 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1952,6 +1952,7 @@ With I, this is a request to make the existing named snapshot become the current snapshot, without reverting the domain. =item B I I [I<--current>] +{[I<--rename>] | [I<--clone>]} Edit the XML configuration file for I of a domain. If I<--current> is specified, also force the edited snapshot to become @@ -1968,6 +1969,14 @@ 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. +If I<--rename> is specified, then the edits can change the snapshot +name. If I<--clone> is specified, then changing the snapshot name +will create a clone of the snapshot metadata. If neither is specified, +then the edits must not change the snapshot name. Note that changing +a snapshot name must be done with care, since the contents of some +snapshots, such as internal snapshots within a single qcow2 file, are +accessible only from the original name. + =item B I [{I<--parent> | I<--roots> | I<--tree>}] [I<--metadata>]