Rather than having to do: $ virsh snapshot-revert dom $(virsh snapshot-current dom --name) I thought it would be nice to do: $ virsh snaphot-revert dom --current I intentionally made it so that omitting both --current and a name is an error (having the absence of a name imply --current seems just a bit too magic, so --current must be explicit). I didn't add 'virsh snapshot-dumpxml --current' since we already have 'virsh snapshot-current' for the same task. All other snapshot-* options that take a snapshotname now take --current in its place; while keeping snapshot-edit backwards-compatible. * tools/virsh.c (vshLookupSnapshot): New helper function. (cmdSnapshotEdit, cmdSnapshotList, cmdSnapshotParent) (cmdSnapshotDelete, cmdDomainSnapshotRevert): Use it, adding an option where needed. * tools/virsh.pod (snapshot-delete, snapshot-edit) (snapshot-list, snapshot-parent, snapshot-revert): Document use of --current. (snapshot-dumpxml): Mention alternative. --- Does not strictly depend on virDomainSnapshotNumChildren, other than the fact that I'm touching 'virsh snapshot-list dom --from name' to add 'virsh snapshot-list dom --current'; I could split that change out from the rest of the patch if desired to get the ease-of-use in the other snapshot-* commands before the new API is approved. tools/virsh.c | 109 ++++++++++++++++++++++++++++++++++++------------------- tools/virsh.pod | 31 ++++++++++------ 2 files changed, 90 insertions(+), 50 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 86b230d..ea7b56b 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -12816,6 +12816,48 @@ cleanup: return ret; } +/* Helper for resolving {--current | --ARG name} into a snapshot + * belonging to DOM. If EXCLUSIVE, fail if both --current and arg are + * present. On success, populate *SNAP, and if NAME is not NULL, + * *NAME, before returning 0. On failure, return -1 after issuing an + * error message. */ +static int +vshLookupSnapshot(vshControl *ctl, const vshCmd *cmd, + const char *arg, bool exclusive, virDomainPtr dom, + virDomainSnapshotPtr *snap, const char **name) +{ + bool current = vshCommandOptBool(cmd, "current"); + const char *snapname = NULL; + + if (vshCommandOptString(cmd, arg, &snapname) < 0) { + vshError(ctl, _("invalid argument for --%s"), arg); + return -1; + } + + if (exclusive && current && snapname) { + vshError(ctl, _("--%s and --current are mutually exclusive"), arg); + return -1; + } + + if (snapname) { + *snap = virDomainSnapshotLookupByName(dom, snapname, 0); + } else if (current) { + *snap = virDomainSnapshotCurrent(dom, 0); + } else { + vshError(ctl, _("--%s or --current is required"), arg); + return -1; + } + if (!*snap) { + virshReportError(ctl); + return -1; + } + + if (name && *snap) + *name = vshStrdup(ctl, virDomainSnapshotGetName(*snap)); + + return 0; +} + /* * "snapshot-edit" command */ @@ -12827,7 +12869,7 @@ static const vshCmdInfo info_snapshot_edit[] = { 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")}, + {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, {"current", VSH_OT_BOOL, 0, N_("also set edited snapshot as current")}, {NULL, 0, 0, NULL} }; @@ -12845,21 +12887,19 @@ cmdSnapshotEdit(vshControl *ctl, const vshCmd *cmd) unsigned int getxml_flags = VIR_DOMAIN_XML_SECURE; unsigned int define_flags = VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE; - if (vshCommandOptBool(cmd, "current")) + if (vshCommandOptBool(cmd, "current") && + vshCommandOptBool(cmd, "snapshotname")) 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) + if (vshLookupSnapshot(ctl, cmd, "snapshotname", false, dom, + &snapshot, &name) < 0) goto cleanup; /* Get the XML configuration of the snapshot. */ @@ -13109,6 +13149,8 @@ static const vshCmdOptDef opts_snapshot_list[] = { N_("list only snapshots that have metadata that would prevent undefine")}, {"tree", VSH_OT_BOOL, 0, N_("list snapshots in a tree")}, {"from", VSH_OT_DATA, 0, N_("limit list to children of given snapshot")}, + {"current", VSH_OT_BOOL, 0, + N_("limit list to children of current snapshot")}, {"descendants", VSH_OT_BOOL, 0, N_("with --from, list all descendants")}, {NULL, 0, 0, NULL} }; @@ -13142,10 +13184,17 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) int start_index = -1; bool descendants = false; - if (vshCommandOptString(cmd, "from", &from) < 0) { - vshError(ctl, _("invalid from argument '%s'"), from); + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + dom = vshCommandOptDomain(ctl, cmd, NULL); + if (dom == NULL) + goto cleanup; + + if ((vshCommandOptBool(cmd, "from") || + vshCommandOptBool(cmd, "current")) && + vshLookupSnapshot(ctl, cmd, "from", true, dom, &start, &from) < 0) goto cleanup; - } if (vshCommandOptBool(cmd, "parent")) { if (vshCommandOptBool(cmd, "roots")) { @@ -13176,18 +13225,8 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) flags |= VIR_DOMAIN_SNAPSHOT_LIST_METADATA; } - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - dom = vshCommandOptDomain(ctl, cmd, NULL); - if (dom == NULL) - goto cleanup; - if (from) { descendants = vshCommandOptBool(cmd, "descendants"); - start = virDomainSnapshotLookupByName(dom, from, 0); - if (!start) - goto cleanup; if (descendants || tree) { flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; } @@ -13519,7 +13558,8 @@ static const vshCmdInfo info_snapshot_parent[] = { static const vshCmdOptDef opts_snapshot_parent[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")}, + {"snapshotname", VSH_OT_DATA, 0, N_("find parent of snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("find parent of current snapshot")}, {NULL, 0, 0, NULL} }; @@ -13539,11 +13579,8 @@ cmdSnapshotParent(vshControl *ctl, const vshCmd *cmd) if (dom == NULL) goto cleanup; - if (vshCommandOptString(cmd, "snapshotname", &name) <= 0) - goto cleanup; - - snapshot = virDomainSnapshotLookupByName(dom, name, 0); - if (snapshot == NULL) + if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, + &snapshot, &name) < 0) goto cleanup; if (vshGetSnapshotParent(ctl, snapshot, &parent) < 0) @@ -13578,7 +13615,8 @@ static const vshCmdInfo info_snapshot_revert[] = { static const vshCmdOptDef opts_snapshot_revert[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")}, + {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("revert to current snapshot")}, {"running", VSH_OT_BOOL, 0, N_("after reverting, change state to running")}, {"paused", VSH_OT_BOOL, 0, N_("after reverting, change state to paused")}, {"force", VSH_OT_BOOL, 0, N_("try harder on risky reverts")}, @@ -13614,11 +13652,8 @@ cmdDomainSnapshotRevert(vshControl *ctl, const vshCmd *cmd) if (dom == NULL) goto cleanup; - if (vshCommandOptString(cmd, "snapshotname", &name) <= 0) - goto cleanup; - - snapshot = virDomainSnapshotLookupByName(dom, name, 0); - if (snapshot == NULL) + if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, + &snapshot, &name) < 0) goto cleanup; result = virDomainRevertToSnapshot(snapshot, flags); @@ -13654,7 +13689,8 @@ static const vshCmdInfo info_snapshot_delete[] = { static const vshCmdOptDef opts_snapshot_delete[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")}, + {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")}, + {"current", VSH_OT_BOOL, 0, N_("delete current snapshot")}, {"children", VSH_OT_BOOL, 0, N_("delete snapshot and all children")}, {"children-only", VSH_OT_BOOL, 0, N_("delete children but not snapshot")}, {"metadata", VSH_OT_BOOL, 0, @@ -13678,7 +13714,8 @@ cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd) if (dom == NULL) goto cleanup; - if (vshCommandOptString(cmd, "snapshotname", &name) <= 0) + if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom, + &snapshot, &name) < 0) goto cleanup; if (vshCommandOptBool(cmd, "children")) @@ -13688,10 +13725,6 @@ cmdSnapshotDelete(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "metadata")) flags |= VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY; - snapshot = virDomainSnapshotLookupByName(dom, name, 0); - if (snapshot == NULL) - goto cleanup; - /* XXX If we wanted, we could emulate DELETE_CHILDREN_ONLY even on * older servers that reject the flag, by manually computing the * list of descendants. But that's a lot of code to maintain. */ diff --git a/tools/virsh.pod b/tools/virsh.pod index dd60a64..e1a9b86 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1951,11 +1951,13 @@ 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>] +=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. +both I<snapshotname> and I<--current> are specified, also force the +edited snapshot to become the current snapshot. If I<snapshotname> +is omitted, then I<--current> must be supplied, to edit the current +snapshot. This is equivalent to: @@ -1969,7 +1971,7 @@ 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<--tree>}] -[I<--metadata>] [[I<--from>] B<snapshot> [I<--descendants>]] +[I<--metadata>] [{[I<--from>] B<snapshot> | I<--current>} [I<--descendants>]] List all of the available snapshots for the given domain, defaulting to show columns for the snapshot name, creation time, and domain state. @@ -1981,7 +1983,8 @@ If I<--tree> is specified, the output will be in a tree format, listing just snapshot names. These three options are mutually exclusive. If I<--from> is provided, filter the list to snapshots which are -children of the given B<snapshot>. When used in isolation or with +children of the given B<snapshot>; or if I<--current> is provided, +start at the current snapshot. When used in isolation or with I<--parent>, the list is limited to direct children unless I<--descendants> is also present. When used with I<--tree>, the use of I<--descendants> is implied. This option is not compatible @@ -1996,15 +1999,18 @@ a transient domain. Output the snapshot XML for the domain's snapshot named I<snapshot>. Using I<--security-info> will also include security sensitive information. +Use B<snapshot-current> to easily access the XML of the current snapshot. -=item B<snapshot-parent> I<domain> I<snapshot> +=item B<snapshot-parent> I<domain> {I<snapshot> | I<--current>} -Output the name of the parent snapshot for the given I<snapshot>, if any. +Output the name of the parent snapshot, if any, for the given +I<snapshot>, or for the current snapshot with I<--current>. -=item B<snapshot-revert> I<domain> I<snapshot> [{I<--running> | I<--paused>}] -[I<--force>] +=item B<snapshot-revert> I<domain> {I<snapshot> | I<--current>} +[{I<--running> | I<--paused>}] [I<--force>] -Revert the given domain to the snapshot specified by I<snapshot>. Be aware +Revert the given domain to the snapshot specified by I<snapshot>, or to +the current snapshot with I<--current>. Be aware that this is a destructive action; any changes in the domain since the last snapshot was taken will be lost. Also note that the state of the domain after snapshot-revert is complete will be the state of the domain at the time @@ -2034,10 +2040,11 @@ snapshot that uses a provably incompatible configuration, as well as with an inactive snapshot that is combined with the I<--start> or I<--pause> flag. -=item B<snapshot-delete> I<domain> I<snapshot> [I<--metadata>] +=item B<snapshot-delete> I<domain> {I<snapshot> | I<--current>} [I<--metadata>] [{I<--children> | I<--children-only>}] -Delete the snapshot for the domain named I<snapshot>. If this snapshot +Delete the snapshot for the domain named I<snapshot>, or the current +snapshot with I<--current>. If this snapshot has child snapshots, changes from this snapshot will be merged into the children. If I<--children> is passed, then delete this snapshot and any children of this snapshot. If I<--children-only> is passed, then delete -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list