]> xenbits.xensource.com Git - libvirt.git/commitdiff
cmdDomblkinfo: add --all to show all block devices info
authorChen Hanxiao <chenhanxiao@gmail.com>
Tue, 19 Jun 2018 10:01:24 +0000 (18:01 +0800)
committerJohn Ferlan <jferlan@redhat.com>
Thu, 21 Jun 2018 21:39:22 +0000 (17:39 -0400)
This patch introduces --all to show all block devices info
of guests like:

virsh # domblkinfo w08 --all
Target     Capacity        Allocation      Physical
---------------------------------------------------
hda        42949672960     9878110208      9878110208
vda        10737418240     10736439296     10737418240

Target     Capacity        Allocation      Physical
---------------------------------------------------
hda        40.000 GiB      9.200 GiB       9.200 GiB
vda        10.000 GiB      9.999 GiB       10.000 GiB

For inactive domains using networked storage, a "-" will
be printed instead of the value since it's not possible
to determine the value without the storage connection.

Signed-off-by: Chen Hanxiao <chenhanxiao@gmail.com>
Reviewed-by: John Ferlan <jferlan@redhat.com>
tools/virsh-domain-monitor.c
tools/virsh.pod

index 4e28122dd1680492bc45df943334e195f45dba80..87660ee67404f6802a956f7ef3cf4d104875fc73 100644 (file)
@@ -388,8 +388,7 @@ static const vshCmdInfo info_domblkinfo[] = {
 static const vshCmdOptDef opts_domblkinfo[] = {
     VIRSH_COMMON_OPT_DOMAIN_FULL(0),
     {.name = "device",
-     .type = VSH_OT_DATA,
-     .flags = VSH_OFLAG_REQ,
+     .type = VSH_OT_STRING,
      .completer = virshDomainDiskTargetCompleter,
      .help = N_("block device")
     },
@@ -397,30 +396,66 @@ static const vshCmdOptDef opts_domblkinfo[] = {
      .type = VSH_OT_BOOL,
      .help = N_("Human readable output")
     },
+    {.name = "all",
+     .type = VSH_OT_BOOL,
+     .help = N_("display all block devices info")
+    },
     {.name = NULL}
 };
 
 static void
 cmdDomblkinfoPrint(vshControl *ctl,
                    const virDomainBlockInfo *info,
-                   bool human)
+                   const char *device,
+                   bool human, bool title)
 {
-    if (!human) {
-        vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info->capacity);
-        vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info->allocation);
-        vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info->physical);
+    char *cap = NULL;
+    char *alloc = NULL;
+    char *phy = NULL;
+
+    if (title) {
+        vshPrintExtra(ctl, "%-10s %-15s %-15s %-15s\n", _("Target"),
+                      _("Capacity"), _("Allocation"), _("Physical"));
+        vshPrintExtra(ctl, "-----------------------------"
+                      "------------------------\n");
+        return;
+    }
+
+    if (info->capacity == 0 && info->allocation == 0 && info->physical == 0) {
+        cap = vshStrdup(ctl, "-");
+        alloc = vshStrdup(ctl, "-");
+        phy = vshStrdup(ctl, "-");
+    } else if (!human) {
+        if (virAsprintf(&cap, "%llu", info->capacity) < 0 ||
+            virAsprintf(&alloc, "%llu", info->allocation) < 0 ||
+            virAsprintf(&phy, "%llu", info->physical) < 0)
+            goto cleanup;
+    } else {
+        double val_cap, val_alloc, val_phy;
+        const char *unit_cap, *unit_alloc, *unit_phy;
+
+        val_cap = vshPrettyCapacity(info->capacity, &unit_cap);
+        val_alloc = vshPrettyCapacity(info->allocation, &unit_alloc);
+        val_phy = vshPrettyCapacity(info->physical, &unit_phy);
+
+        if (virAsprintf(&cap, "%.3lf %s", val_cap, unit_cap) < 0 ||
+            virAsprintf(&alloc, "%.3lf %s", val_alloc, unit_alloc) < 0 ||
+            virAsprintf(&phy, "%.3lf %s", val_phy, unit_phy) < 0)
+            goto cleanup;
+    }
+
+    if (device) {
+        vshPrint(ctl, "%-10s %-15s %-15s %-15s\n", device, cap, alloc, phy);
     } else {
-        double val;
-        const char *unit;
-
-        val = vshPrettyCapacity(info->capacity, &unit);
-        vshPrint(ctl, "%-15s %-.3lf %s\n", _("Capacity:"), val, unit);
-        val = vshPrettyCapacity(info->allocation, &unit);
-        vshPrint(ctl, "%-15s %-.3lf %s\n", _("Allocation:"), val, unit);
-        val = vshPrettyCapacity(info->physical, &unit);
-        vshPrint(ctl, "%-15s %-.3lf %s\n", _("Physical:"), val, unit);
+        vshPrint(ctl, "%-15s %s\n", _("Capacity:"), cap);
+        vshPrint(ctl, "%-15s %s\n", _("Allocation:"), alloc);
+        vshPrint(ctl, "%-15s %s\n", _("Physical:"), phy);
     }
 
+ cleanup:
+    VIR_FREE(cap);
+    VIR_FREE(alloc);
+    VIR_FREE(phy);
 }
 
 
@@ -431,25 +466,83 @@ cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd)
     virDomainPtr dom;
     bool ret = false;
     bool human = false;
+    bool all = false;
     const char *device = NULL;
+    xmlDocPtr xmldoc = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    int ndisks;
+    size_t i;
+    xmlNodePtr *disks = NULL;
+    char *target = NULL;
+    char *protocol = NULL;
 
     if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
         return false;
 
-    if (vshCommandOptStringReq(ctl, cmd, "device", &device) < 0)
-        goto cleanup;
-
-    if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
+    all = vshCommandOptBool(cmd, "all");
+    if (!all && vshCommandOptStringQuiet(ctl, cmd, "device", &device) <= 0) {
+        vshError(ctl, "command 'domblkinfo' requires <device> option");
         goto cleanup;
+    }
 
     human = vshCommandOptBool(cmd, "human");
 
-    cmdDomblkinfoPrint(ctl, &info, human);
+    if (all) {
+        bool active = virDomainIsActive(dom) == 1;
+        int rc;
+
+        if (virshDomainGetXML(ctl, cmd, 0, &xmldoc, &ctxt) < 0)
+            goto cleanup;
+
+        ndisks = virXPathNodeSet("./devices/disk", ctxt, &disks);
+        if (ndisks < 0)
+            goto cleanup;
+
+        /* print the title */
+        cmdDomblkinfoPrint(ctl, NULL, NULL, false, true);
+
+        for (i = 0; i < ndisks; i++) {
+            ctxt->node = disks[i];
+            protocol = virXPathString("string(./source/@protocol)", ctxt);
+            target = virXPathString("string(./target/@dev)", ctxt);
+
+            rc = virDomainGetBlockInfo(dom, target, &info, 0);
+
+            if (rc < 0) {
+                /* If protocol is present that's an indication of a networked
+                 * storage device which cannot provide statistics, so generate
+                 * 0 based data and get the next disk. */
+                if (protocol && !active &&
+                    virGetLastErrorCode() == VIR_ERR_INTERNAL_ERROR &&
+                    virGetLastErrorDomain() == VIR_FROM_STORAGE) {
+                    memset(&info, 0, sizeof(info));
+                    vshResetLibvirtError();
+                } else {
+                    goto cleanup;
+                }
+            }
+
+            cmdDomblkinfoPrint(ctl, &info, target, human, false);
+
+            VIR_FREE(target);
+            VIR_FREE(protocol);
+        }
+    } else {
+        if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
+            goto cleanup;
+
+        cmdDomblkinfoPrint(ctl, &info, NULL, human, false);
+    }
 
     ret = true;
 
  cleanup:
     virshDomainFree(dom);
+    VIR_FREE(target);
+    VIR_FREE(protocol);
+    VIR_FREE(disks);
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(xmldoc);
     return ret;
 }
 
index 7cb8c8a6e43caa9b9522e459ecf77fdfe17e041c..c9ef4f137c3e9293c1de8d7cbd6561c003f3ea79 100644 (file)
@@ -949,13 +949,16 @@ B<domstate> command says that a domain was paused due to I/O error.
 The B<domblkerror> command lists all block devices in error state and
 the error seen on each of them.
 
-=item B<domblkinfo> I<domain> I<block-device> [I<--human>]
+=item B<domblkinfo> I<domain> [I<block-device> I<--all>] [I<--human>]
 
 Get block device size info for a domain.  A I<block-device> corresponds
 to a unique target name (<target dev='name'/>) or source file (<source
 file='name'/>) for one of the disk devices attached to I<domain> (see
 also B<domblklist> for listing these names). If I<--human> is set, the
 output will have a human readable output.
+If I<--all> is set, the output will be a table showing all block devices
+size info associated with I<domain>.
+The I<--all> option takes precedence of the others.
 
 =item B<domblklist> I<domain> [I<--inactive>] [I<--details>]