提交 fe383bb5 编写于 作者: E Eric Blake

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.
上级 f2013c9d
...@@ -13146,6 +13146,8 @@ static const vshCmdOptDef opts_snapshot_list[] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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);
......
...@@ -1978,7 +1978,7 @@ snapshots, such as internal snapshots within a single qcow2 file, are ...@@ -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. ...@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册