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