New flag bits are worth exposing via virsh. Additionally, even though I recently added 'virsh snapshot-parent', doing it one snapshot at a time is painful, so make it possible to expand the snapshot-list table at once. In the case of snapshot-list --roots, it's possible to emulate this even when talking to an older server that lacks the bit; whereas --metadata requires a newer server. * tools/virsh.c (cmdSnapshotDumpXML, cmdSnapshotCurrent): Add --security-info. (cmdSnapshotList): Add --parent, --roots, --metadata. * tools/virsh.pod (snapshot-dumpxml, snapshot-current) (snapshot-list): Document these. --- Adding this also helped me find a couple of tweaks to make earlier in the series, where I've replied to those issues separately. tools/virsh.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++----- tools/virsh.pod | 22 +++++++++++--- 2 files changed, 90 insertions(+), 13 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index bb08d4c..f5049c6 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -12337,6 +12337,8 @@ static const vshCmdInfo info_snapshot_current[] = { static const vshCmdOptDef opts_snapshot_current[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"name", VSH_OT_BOOL, 0, N_("list the name, rather than the full xml")}, + {"security-info", VSH_OT_BOOL, 0, + N_("include security sensitive information in XML dump")}, {NULL, 0, 0, NULL} }; @@ -12348,6 +12350,10 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd) int current; virDomainSnapshotPtr snapshot = NULL; char *xml = NULL; + int flags = 0; + + if (vshCommandOptBool(cmd, "security-info")) + flags |= VIR_DOMAIN_XML_SECURE; if (!vshConnectionUsability(ctl, ctl->conn)) goto cleanup; @@ -12365,7 +12371,7 @@ cmdSnapshotCurrent(vshControl *ctl, const vshCmd *cmd) if (!(snapshot = virDomainSnapshotCurrent(dom, 0))) goto cleanup; - xml = virDomainSnapshotGetXMLDesc(snapshot, 0); + xml = virDomainSnapshotGetXMLDesc(snapshot, flags); if (!xml) goto cleanup; @@ -12418,6 +12424,10 @@ static const vshCmdInfo info_snapshot_list[] = { static const vshCmdOptDef opts_snapshot_list[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"parent", VSH_OT_BOOL, 0, N_("add a column showing parent snapshot")}, + {"roots", VSH_OT_BOOL, 0, N_("list only snapshots without parents")}, + {"metadata", VSH_OT_BOOL, 0, + N_("list only snapshots that have metadata that would prevent undefine")}, {NULL, 0, 0, NULL} }; @@ -12426,6 +12436,9 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom = NULL; bool ret = false; + int flags = 0; + int parent_filter = 0; /* -1 for roots filtering, 0 for no parent + information needed, 1 for parent column */ int numsnaps; char **names = NULL; int actual = 0; @@ -12435,11 +12448,27 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) char *doc = NULL; virDomainSnapshotPtr snapshot = NULL; char *state = NULL; + char *parent = NULL; long long creation_longlong; time_t creation_time_t; char timestr[100]; struct tm time_info; + if (vshCommandOptBool(cmd, "parent")) { + if (vshCommandOptBool(cmd, "roots")) { + vshError(ctl, "%s", + _("--parent and --roots are mutually exlusive")); + return false; + } + parent_filter = 1; + } else if (vshCommandOptBool(cmd, "roots")) { + flags |= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; + } + + if (vshCommandOptBool(cmd, "metadata")) { + flags |= VIR_DOMAIN_SNAPSHOT_LIST_METADATA; + } + if (!vshConnectionUsability(ctl, ctl->conn)) goto cleanup; @@ -12447,19 +12476,35 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) if (dom == NULL) goto cleanup; - numsnaps = virDomainSnapshotNum(dom, 0); + 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) goto cleanup; - vshPrintExtra(ctl, " %-20s %-25s %s\n", _("Name"), _("Creation Time"), _("State")); - vshPrintExtra(ctl, "---------------------------------------------------\n"); + if (parent_filter > 0) + vshPrintExtra(ctl, " %-20s %-25s %-15s %s", + _("Name"), _("Creation Time"), _("State"), _("Parent")); + else + vshPrintExtra(ctl, " %-20s %-25s %s", + _("Name"), _("Creation Time"), _("State")); + vshPrintExtra(ctl, "\n\ +------------------------------------------------------------\n"); if (numsnaps) { if (VIR_ALLOC_N(names, numsnaps) < 0) goto cleanup; - actual = virDomainSnapshotListNames(dom, names, numsnaps, 0); + actual = virDomainSnapshotListNames(dom, names, numsnaps, flags); if (actual < 0) goto cleanup; @@ -12467,6 +12512,7 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) for (i = 0; i < actual; i++) { /* free up memory from previous iterations of the loop */ + VIR_FREE(parent); VIR_FREE(state); if (snapshot) virDomainSnapshotFree(snapshot); @@ -12492,6 +12538,13 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) if (!ctxt) continue; + if (parent_filter) { + parent = virXPathString("string(/domainsnapshot/parent/name)", + ctxt); + if (!parent && parent_filter < 0) + continue; + } + state = virXPathString("string(/domainsnapshot/state)", ctxt); if (state == NULL) continue; @@ -12504,9 +12557,14 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) continue; } localtime_r(&creation_time_t, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", &time_info); + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", + &time_info); - vshPrint(ctl, " %-20s %-25s %s\n", names[i], timestr, state); + if (parent) + vshPrint(ctl, " %-20s %-25s %-15s %s\n", + names[i], timestr, state, parent); + else + vshPrint(ctl, " %-20s %-25s %s\n", names[i], timestr, state); } } @@ -12514,6 +12572,7 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) cleanup: /* this frees up memory from the last iteration of the loop */ + VIR_FREE(parent); VIR_FREE(state); if (snapshot) virDomainSnapshotFree(snapshot); @@ -12542,6 +12601,8 @@ static const vshCmdInfo info_snapshot_dumpxml[] = { static const vshCmdOptDef opts_snapshot_dumpxml[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"snapshotname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("snapshot name")}, + {"security-info", VSH_OT_BOOL, 0, + N_("include security sensitive information in XML dump")}, {NULL, 0, 0, NULL} }; @@ -12553,6 +12614,10 @@ cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd) const char *name = NULL; virDomainSnapshotPtr snapshot = NULL; char *xml = NULL; + int flags = 0; + + if (vshCommandOptBool(cmd, "security-info")) + flags |= VIR_DOMAIN_XML_SECURE; if (!vshConnectionUsability(ctl, ctl->conn)) goto cleanup; @@ -12568,7 +12633,7 @@ cmdSnapshotDumpXML(vshControl *ctl, const vshCmd *cmd) if (snapshot == NULL) goto cleanup; - xml = virDomainSnapshotGetXMLDesc(snapshot, 0); + xml = virDomainSnapshotGetXMLDesc(snapshot, flags); if (!xml) goto cleanup; diff --git a/tools/virsh.pod b/tools/virsh.pod index c27e99d..64c3895 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -523,7 +523,7 @@ Output the domain information as an XML dump to stdout, this format can be used by the B<create> command. Additional options affecting the XML dump may be used. I<--inactive> tells virsh to dump domain configuration that will be used on next start of the domain as opposed to the current domain configuration. -Using I<--security-info> security sensitive information will also be included +Using I<--security-info> will also include security sensitive information in the XML dump. I<--update-cpu> updates domain CPU requirements according to host CPU. @@ -1597,19 +1597,31 @@ Create a snapshot for domain I<domain> with the given <name> and value. If I<--print-xml> is specified, then XML appropriate for I<snapshot-create> is output, rather than actually creating a snapshot. -=item B<snapshot-current> I<domain> [I<--name>] +=item B<snapshot-current> I<domain> [I<--name>] [I<--security-info>] Output the snapshot XML for the domain's current snapshot (if any). If I<--name> is specified, just list the snapshot name instead of the -full xml. +full xml. Otherwise, using I<--security-info> will also include security +sensitive information. -=item B<snapshot-list> I<domain> +=item B<snapshot-list> I<domain> [{I<--parent> | I<--roots>}] [I<--metadata>] List all of the available snapshots for the given domain. -=item B<snapshot-dumpxml> I<domain> I<snapshot> +If I<--parent> is specified, add a column to the output table giving +the name of the parent of each snapshot. + +If I<--roots> is specified, the list will be filtered to just snapshots +that have no parents; this option is not compatible with I<--parent>. + +If I<--metadata> is specified, the list will be filtered to just +snapshots that involve libvirt metadata, and thus would interfere in +using the B<undefine> or B<destroy> commands on that domain. + +=item B<snapshot-dumpxml> I<domain> I<snapshot> [I<--security-info>] Output the snapshot XML for the domain's snapshot named I<snapshot>. +Using I<--security-info> will also include security sensitive information. =item B<snapshot-parent> I<domain> I<snapshot> -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list