snapshot: virsh snapshot-list and children

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.
This commit is contained in:
Eric Blake 2011-09-29 11:51:23 -06:00
parent f2013c9dd1
commit fe383bb541
2 changed files with 66 additions and 13 deletions

View File

@ -13146,6 +13146,8 @@ static const vshCmdOptDef opts_snapshot_list[] = {
{"metadata", VSH_OT_BOOL, 0, {"metadata", VSH_OT_BOOL, 0,
N_("list only snapshots that have metadata that would prevent undefine")}, N_("list only snapshots that have metadata that would prevent undefine")},
{"tree", VSH_OT_BOOL, 0, N_("list snapshots in a tree")}, {"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} {NULL, 0, 0, NULL}
}; };
@ -13172,6 +13174,13 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
char timestr[100]; char timestr[100];
struct tm time_info; struct tm time_info;
bool tree = vshCommandOptBool(cmd, "tree"); 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, "parent")) {
if (vshCommandOptBool(cmd, "roots")) { if (vshCommandOptBool(cmd, "roots")) {
@ -13191,6 +13200,10 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
_("--roots and --tree are mutually exclusive")); _("--roots and --tree are mutually exclusive"));
return false; return false;
} }
if (from) {
vshError(ctl, "%s",
_("--roots and --from are mutually exclusive"));
}
flags |= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; flags |= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS;
} }
@ -13205,16 +13218,29 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
if (dom == NULL) if (dom == NULL)
goto cleanup; goto cleanup;
numsnaps = virDomainSnapshotNum(dom, flags); if (from) {
start = virDomainSnapshotLookupByName(dom, from, 0);
/* Fall back to simulation if --roots was unsupported. */ if (!start)
if (numsnaps < 0 && last_error->code == VIR_ERR_INVALID_ARG && goto cleanup;
(flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) { if (vshCommandOptBool(cmd, "descendants") || tree) {
virFreeError(last_error); flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS;
last_error = NULL; }
parent_filter = -1; numsnaps = virDomainSnapshotNumChildren(start, flags);
flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; if (numsnaps >= 0 && tree)
numsnaps++;
/* XXX Is it worth emulating --from on older servers? */
} else {
numsnaps = virDomainSnapshotNum(dom, flags); numsnaps = virDomainSnapshotNum(dom, flags);
/* Fall back to simulation if --roots was unsupported. */
if (numsnaps < 0 && last_error->code == VIR_ERR_INVALID_ARG &&
(flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) {
virFreeError(last_error);
last_error = NULL;
parent_filter = -1;
flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_ROOTS;
numsnaps = virDomainSnapshotNum(dom, flags);
}
} }
if (numsnaps < 0) if (numsnaps < 0)
@ -13240,7 +13266,25 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
if (VIR_ALLOC_N(names, numsnaps) < 0) if (VIR_ALLOC_N(names, numsnaps) < 0)
goto cleanup; 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) if (actual < 0)
goto cleanup; goto cleanup;
@ -13248,8 +13292,8 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
if (tree) { if (tree) {
char indentBuf[INDENT_BUFLEN]; char indentBuf[INDENT_BUFLEN];
char **parents = vshMalloc(ctl, sizeof(char *) * actual); char **parents = vshCalloc(ctl, sizeof(char *), actual);
for (i = 0; i < actual; i++) { for (i = (from ? 1 : 0); i < actual; i++) {
/* free up memory from previous iterations of the loop */ /* free up memory from previous iterations of the loop */
if (snapshot) if (snapshot)
virDomainSnapshotFree(snapshot); virDomainSnapshotFree(snapshot);
@ -13342,6 +13386,8 @@ cleanup:
VIR_FREE(state); VIR_FREE(state);
if (snapshot) if (snapshot)
virDomainSnapshotFree(snapshot); virDomainSnapshotFree(snapshot);
if (start)
virDomainSnapshotFree(start);
xmlXPathFreeContext(ctxt); xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml); xmlFreeDoc(xml);
VIR_FREE(doc); VIR_FREE(doc);

View File

@ -1978,7 +1978,7 @@ snapshots, such as internal snapshots within a single qcow2 file, are
accessible only from the original name. accessible only from the original name.
=item B<snapshot-list> I<domain> [{I<--parent> | I<--roots> | I<--tree>}] =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 List all of the available snapshots for the given domain, defaulting
to show columns for the snapshot name, creation time, and domain state. to show columns for the snapshot name, creation time, and domain state.
@ -1989,6 +1989,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 If I<--tree> is specified, the output will be in a tree format, listing
just snapshot names. These three options are mutually exclusive. 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 If I<--metadata> is specified, the list will be filtered to just
snapshots that involve libvirt metadata, and thus would prevent snapshots that involve libvirt metadata, and thus would prevent
B<undefine> of a persistent domain, or be lost on B<destroy> of B<undefine> of a persistent domain, or be lost on B<destroy> of