Expose the recent API additions in virsh. Borrows ideas from 'dominfo'
for the general type of information to display. Output looks like:
$ tools/virsh snapshot-info fedora-local tmp
Name: tmp
Domain: fedora-local
Current: no
State: disk-snapshot
Parent: -
Children: 1
Descendants: 2
Metadata: yes
possibly with fewer lines when talking to older servers.
* tools/virsh.c (cmdSnapshotInfo): New command.
* tools/virsh.pod (snapshot-info): Document it.
---
tools/virsh.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 5 ++
2 files changed, 130 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index ffe6ed2..6a85338 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -16601,6 +16601,129 @@ cleanup:
}
/*
+ * "snapshot-info" command
+ */
+static const vshCmdInfo info_snapshot_info[] = {
+ {"help", N_("snapshot information")},
+ {"desc", N_("Returns basic information about a snapshot.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_snapshot_info[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+ {"snapshotname", VSH_OT_DATA, 0, N_("snapshot name")},
+ {"current", VSH_OT_BOOL, 0, N_("info on current snapshot")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdSnapshotInfo(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom;
+ virDomainSnapshotPtr snapshot = NULL;
+ const char *name;
+ char *doc = NULL;
+ char *tmp;
+ char *parent = NULL;
+ bool ret = false;
+ int count;
+ unsigned int flags;
+ int current;
+ int metadata;
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ return false;
+
+ dom = vshCommandOptDomain(ctl, cmd, NULL);
+ if (dom == NULL)
+ return false;
+
+ if (vshLookupSnapshot(ctl, cmd, "snapshotname", true, dom,
+&snapshot,&name)< 0)
+ goto cleanup;
+
+ vshPrint(ctl, "%-15s %s\n", _("Name:"), name);
+ vshPrint(ctl, "%-15s %s\n", _("Domain:"), virDomainGetName(dom));
+
+ /* Determine if snapshot is current; this is useful enough that we
+ * attempt a fallback. */
+ current = virDomainSnapshotIsCurrent(snapshot, 0);
+ if (current< 0) {
+ virDomainSnapshotPtr other = virDomainSnapshotCurrent(dom, 0);
+
+ virResetLastError();
+ current = 0;
+ if (other) {
+ if (STREQ(name, virDomainSnapshotGetName(other)))
+ current = 1;
+ virDomainSnapshotFree(other);
+ }
+ }
+ vshPrint(ctl, "%-15s %s\n", _("Current:"),
+ current> 0 ? _("yes") : _("no"));
+
+ /* Get the XML configuration of the snapshot to determine the
+ * state of the machine at the time of the snapshot. */
+ doc = virDomainSnapshotGetXMLDesc(snapshot, 0);
+ if (!doc)
+ goto cleanup;
+
+ tmp = strstr(doc, "<state>");
+ if (!tmp) {
+ vshError(ctl, "%s",
+ _("unexpected problem reading snapshot xml"));
+ goto cleanup;
+ }
+ tmp += strlen("<state>");
+ vshPrint(ctl, "%-15s %.*s\n", _("State:"),
+ (int) (strchr(tmp, '<') - tmp), tmp);
+
+ if (vshGetSnapshotParent(ctl, snapshot,&parent)< 0)
+ goto cleanup;
+ vshPrint(ctl, "%-15s %s\n", _("Parent:"), parent ? parent : "-");
+
+ /* Children, Descendants. After this point, the fallback to
+ * compute children is too expensive, so we gracefully quit if the
+ * APIs don't exist. */
+ if (ctl->useSnapshotOld) {
+ ret = true;
+ goto cleanup;
+ }
+ flags = 0;
+ count = virDomainSnapshotNumChildren(snapshot, 0);
+ if (count< 0)
+ goto cleanup;
+ vshPrint(ctl, "%-15s %d\n", _("Children:"), count);
+ flags = VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS;
+ count = virDomainSnapshotNumChildren(snapshot, flags);
+ if (count< 0)
+ goto cleanup;
+ vshPrint(ctl, "%-15s %d\n", _("Descendants:"), count);
+
+ /* Metadata; the fallback here relies on the fact that metadata
+ * used to have an all-or-nothing effect on snapshot count. */
+ metadata = virDomainSnapshotHasMetadata(snapshot, 0);
+ if (metadata< 0) {
+ virResetLastError();
+ count = virDomainSnapshotNum(dom,
+ VIR_DOMAIN_SNAPSHOT_LIST_METADATA);
+ metadata = count != 0;
+ }
+ vshPrint(ctl, "%-15s %s\n", _("Metadata:"),
+ metadata> 0 ? _("yes") : _("no"));
+
+ ret = true;
+
+cleanup:
+ VIR_FREE(doc);
+ VIR_FREE(parent);
+ if (snapshot)
+ virDomainSnapshotFree(snapshot);
+ virDomainFree(dom);
+ return ret;
+}
+
+/*
* "snapshot-list" command
*/
static const vshCmdInfo info_snapshot_list[] = {
@@ -17702,6 +17825,8 @@ static const vshCmdDef snapshotCmds[] = {
info_snapshot_dumpxml, 0},
{"snapshot-edit", cmdSnapshotEdit, opts_snapshot_edit,
info_snapshot_edit, 0},
+ {"snapshot-info", cmdSnapshotInfo, opts_snapshot_info,
+ info_snapshot_info, 0},
{"snapshot-list", cmdSnapshotList, opts_snapshot_list,
info_snapshot_list, 0},
{"snapshot-parent", cmdSnapshotParent, opts_snapshot_parent,
diff --git a/tools/virsh.pod b/tools/virsh.pod
index ef71717..6553825 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -2504,6 +2504,11 @@ a snapshot name must be done with care, since the contents of some
snapshots, such as internal snapshots within a single qcow2 file, are
accessible only from the original name.
+=item B<snapshot-info> I<domain> {I<snapshot> | I<--current>}
+
+Output basic information about a named<snapshot>, or the current snapshot
+with I<--current>.
+
=item B<snapshot-list> I<domain> [{I<--parent> | I<--roots> | I<--tree>}]
[{[I<--from>] B<snapshot> | I<--current>} [I<--descendants>]]
[I<--metadata>] [I<--leaves>]