Sometimes, we only care about one branch of the snapshot hierarchy. Make it easier to list a single branch, by using the new APIs. Technically, I could emulate these new virsh options on old servers by doing a complete dump, then scraping xml to filter out just the snapshots that I care about, but I didn't want to do that in this patch. * tools/virsh.c (cmdSnapshotList): Add --from, --descendants. * tools/virsh.pod (snapshot-list): Document them. --- tools/virsh.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++------- tools/virsh.pod | 9 +++++++- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 1909dce..f43af7e 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -13081,6 +13081,8 @@ static const vshCmdOptDef opts_snapshot_list[] = { {"metadata", VSH_OT_BOOL, 0, 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")}, + {"descendants", VSH_OT_BOOL, 0, N_("with --from, list all descendants")}, {NULL, 0, 0, NULL} }; @@ -13107,25 +13109,36 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) char timestr[100]; struct tm time_info; bool tree = vshCommandOptBool(cmd, "tree"); + const char *from = NULL; + virDomainSnapshotPtr start = NULL; + + if (vshCommandOptString(cmd, "from", &from) < 0) { + vshError(ctl, _("invalid from argument '%s'"), from); + goto cleanup; + } if (vshCommandOptBool(cmd, "parent")) { if (vshCommandOptBool(cmd, "roots")) { vshError(ctl, "%s", - _("--parent and --roots are mutually exlusive")); + _("--parent and --roots are mutually exclusive")); return false; } if (tree) { vshError(ctl, "%s", - _("--parent and --tree are mutually exlusive")); + _("--parent and --tree are mutually exclusive")); return false; } parent_filter = 1; } else if (vshCommandOptBool(cmd, "roots")) { if (tree) { vshError(ctl, "%s", - _("--roots and --tree are mutually exlusive")); + _("--roots and --tree are mutually exclusive")); return false; } + if (from) { + vshError(ctl, "%s", + _("--roots and --from are mutually exclusive")); + } flags |= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; } @@ -13140,10 +13153,23 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) if (dom == NULL) goto cleanup; - numsnaps = virDomainSnapshotNum(dom, flags); + if (from) { + start = virDomainSnapshotLookupByName(dom, from, 0); + if (!start) + goto cleanup; + if (vshCommandOptBool(cmd, "descendants") || tree) { + flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; + } + numsnaps = virDomainSnapshotNumChildren(start, flags); + if (tree) + numsnaps++; + } else { + numsnaps = virDomainSnapshotNum(dom, flags); + } - /* Fall back to simulation if --roots was unsupported. */ - if (numsnaps < 0 && last_error->code == VIR_ERR_INVALID_ARG && + /* Fall back to simulation if --roots was unsupported. + * XXX Is it worth emulating --from on older servers? */ + if (numsnaps < 0 && last_error->code == VIR_ERR_INVALID_ARG && !from && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) { virFreeError(last_error); last_error = NULL; @@ -13175,14 +13201,32 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) if (VIR_ALLOC_N(names, numsnaps) < 0) goto cleanup; - actual = virDomainSnapshotListNames(dom, names, numsnaps, flags); + if (from) { + /* When mixing --from and --tree, we want to start the tree at the + * given snapshot. Without --tree, only list the children. */ + if (tree) { + if (numsnaps) + actual = virDomainSnapshotListChildrenNames(start, names + 1, + numsnaps - 1, + flags); + if (actual >= 0) { + actual++; + names[0] = vshStrdup(ctl, from); + } + } else { + actual = virDomainSnapshotListChildrenNames(start, names, + numsnaps, flags); + } + } else { + actual = virDomainSnapshotListNames(dom, names, numsnaps, flags); + } if (actual < 0) goto cleanup; if (tree) { char indentBuf[INDENT_BUFLEN]; - char **parents = vshMalloc(ctl, sizeof(char *) * actual); - for (i = 0; i < actual; i++) { + char **parents = vshCalloc(ctl, sizeof(char *), actual); + for (i = (from ? 1 : 0); i < actual; i++) { /* free up memory from previous iterations of the loop */ if (snapshot) virDomainSnapshotFree(snapshot); @@ -13277,6 +13321,8 @@ cleanup: VIR_FREE(state); if (snapshot) virDomainSnapshotFree(snapshot); + if (start) + virDomainSnapshotFree(start); xmlXPathFreeContext(ctxt); xmlFreeDoc(xml); VIR_FREE(doc); diff --git a/tools/virsh.pod b/tools/virsh.pod index be81afc..7c91d75 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1969,7 +1969,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<--metadata>] [[I<--from>] B<snapshot> [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. @@ -1980,6 +1980,13 @@ the list will be filtered to just snapshots that have no parents. 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 +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 +with I<--roots>. + If I<--metadata> is specified, the list will be filtered to just snapshots that involve libvirt metadata, and thus would prevent B<undefine> of a persistent domain, or be lost on B<destroy> of -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list