[libvirt] [PATCH 2/2] virsh: add new --details option to vol-list

Justin Clift justin at salasaga.org
Wed Jun 16 12:28:30 UTC 2010


This patch adds a new --details option to the virsh vol-list
command, making its output more useful to people who use virsh
for significant lengths of time.
---

Output from the new option (hopefully this doesn't wrap):

virsh # pool-list
Name                 State      Autostart 
-----------------------------------------
default              active     yes       
image_dir            active     yes       
tmp                  active     no        

virsh # vol-list default
Name                               Path                                                      
---------------------------------------------------------------------------------------------
CentOS-5.5-x86_64-bin-DVD-1of2.iso /var/lib/libvirt/images/CentOS-5.5-x86_64-bin-DVD-1of2.iso
CentOS-5.5-x86_64-bin-DVD-2of2.iso /var/lib/libvirt/images/CentOS-5.5-x86_64-bin-DVD-2of2.iso

virsh # vol-list image_dir
Name                 Path                                                
-------------------------------------------------------------------------
snap1.img            /export/backend/centos_home/jc/tmp/images/snap1.img 
testimage1           /export/backend/centos_home/jc/tmp/images/testimage1

virsh # vol-list tmp
Name                 Path                 
------------------------------------------
disk1.img            /tmp/images/disk1.img
disk2.img            /tmp/images/disk2.img
disk3.img            /tmp/images/disk3.img
disk4.img            /tmp/images/disk4.img
disk5.img            /tmp/images/disk5.img
disk6.img            /tmp/images/disk6.img

virsh # vol-list default --details
Name                                Type   Capacity   Allocation
      Path                                                      
----------------------------------------------------------------
CentOS-5.5-x86_64-bin-DVD-1of2.iso  file   4.09 GB    4.10 GB   
      /var/lib/libvirt/images/CentOS-5.5-x86_64-bin-DVD-1of2.iso
CentOS-5.5-x86_64-bin-DVD-2of2.iso  file   412.33 MB  412.74 MB 
      /var/lib/libvirt/images/CentOS-5.5-x86_64-bin-DVD-2of2.iso

virsh # vol-list image_dir --details
Name        Type   Capacity   Allocation
      Path                                                
----------------------------------------------------------
snap1.img   file   20.00 GB   140.00 KB 
      /export/backend/centos_home/jc/tmp/images/snap1.img 
testimage1  file   20.00 GB   20.02 GB  
      /export/backend/centos_home/jc/tmp/images/testimage1

virsh # vol-list tmp --details
Name      Type   Capacity   Allocation  Path                 
-------------------------------------------------------------
disk1.img file   20.00 GB   136.00 KB   /tmp/images/disk1.img
disk2.img file   20.00 GB   136.00 KB   /tmp/images/disk2.img
disk3.img file   20.00 GB   136.00 KB   /tmp/images/disk3.img
disk4.img file   20.00 GB   136.00 KB   /tmp/images/disk4.img
disk5.img file   20.00 GB   136.00 KB   /tmp/images/disk5.img
disk6.img file   20.00 GB   136.00 KB   /tmp/images/disk6.img

virsh #

Much more practical than running vol-info individually on each volume.

 tools/virsh.c   |  212 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 tools/virsh.pod |    4 +-
 2 files changed, 189 insertions(+), 27 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index afa84e6..7a12e15 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -6047,67 +6047,227 @@ static const vshCmdInfo info_vol_list[] = {
 
 static const vshCmdOptDef opts_vol_list[] = {
     {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
+    {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")},
     {NULL, 0, 0, NULL}
 };
 
 static int
 cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
 {
+    virStorageVolInfo **volumeInfos = NULL;
     virStoragePoolPtr pool;
-    int maxactive = 0, i;
+    int details = vshCommandOptBool(cmd, "details");
+    int maxName = 0, maxPath = 0;
+    int numVolumes = 0, i;
     char **activeNames = NULL;
+    char **volumePaths = NULL;
 
+    /* Check the connection to libvirtd daemon is still working */
     if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
         return FALSE;
 
+    /* Look up the pool information given to us by the user */
     if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL)))
         return FALSE;
 
-    maxactive = virStoragePoolNumOfVolumes(pool);
-    if (maxactive < 0) {
+    /* Determine the number of volumes in the pool */
+    numVolumes = virStoragePoolNumOfVolumes(pool);
+    if (numVolumes < 0) {
         virStoragePoolFree(pool);
         vshError(ctl, "%s", _("Failed to list active vols"));
         return FALSE;
     }
-    if (maxactive) {
-        activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
 
-        if ((maxactive = virStoragePoolListVolumes(pool, activeNames,
-                                                   maxactive)) < 0) {
+    /* Retrieve the list of volume names in the pool */
+    if (numVolumes) {
+        activeNames = vshMalloc(ctl, sizeof(char *) * numVolumes);
+        if ((numVolumes = virStoragePoolListVolumes(pool, activeNames,
+                                                   numVolumes)) < 0) {
             vshError(ctl, "%s", _("Failed to list active vols"));
             VIR_FREE(activeNames);
             virStoragePoolFree(pool);
             return FALSE;
         }
 
-        qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
+        /* Sort the volume names */
+        qsort(&activeNames[0], numVolumes, sizeof(char *), namesorter);
     }
-    vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path"));
-    vshPrintExtra(ctl, "-----------------------------------------\n");
 
-    for (i = 0; i < maxactive; i++) {
-        virStorageVolPtr vol = virStorageVolLookupByName(pool, activeNames[i]);
-        char *path;
+    /* Set aside memory for volume information pointers */
+    volumePaths = vshMalloc(ctl, sizeof(char *) * numVolumes);
+    volumeInfos = vshMalloc(ctl, sizeof(virStorageVolInfo *) * numVolumes);
 
-        /* this kind of work with vols is not atomic operation */
-        if (!vol) {
-            VIR_FREE(activeNames[i]);
-            continue;
-        }
+    /* Collect the rest of the volume information for display */
+    for (i = 0; i < numVolumes; i++) {
+        int stringLength;
+        virStorageVolPtr vol = virStorageVolLookupByName(pool,
+                                                         activeNames[i]);
 
-        if ((path = virStorageVolGetPath(vol)) == NULL) {
-            virStorageVolFree(vol);
-            continue;
+        /* Retrieve the volume path */
+        if ((volumePaths[i] = virStorageVolGetPath(vol)) == NULL) {
+            /* Something went wrong retrieving a volume path, cope with it */
+            volumePaths[i] = vshStrdup(ctl, _("unknown"));
         }
 
+        /* Keep the length of path string if longest so far */
+        stringLength = strlen(volumePaths[i]);
+        if (stringLength > maxPath)
+            maxPath = stringLength;
+
+        /* Keep the length of name string if longest so far */
+        stringLength = strlen(activeNames[i]);
+        if (stringLength > maxName)
+            maxName = stringLength;
+
+        /* Retrieve the volume capacity and allocation */
+        volumeInfos[i] = vshMalloc(ctl, sizeof(virStorageVolInfo));
+        if (virStorageVolGetInfo(vol, volumeInfos[i]) != 0) {
+            /* Something went wrong retrieving volume info, cope with it */
+            volumeInfos[i] = NULL;
+        }
 
-        vshPrint(ctl, "%-20s %-40s\n",
-                 virStorageVolGetName(vol),
-                 path);
-        VIR_FREE(path);
+        /* Cleanup memory allocation */
         virStorageVolFree(vol);
-        VIR_FREE(activeNames[i]);
     }
+
+    /* Display the volume information */
+    vshDebug(ctl, 5, "Longest name string = %d chars\n", maxName);
+    vshDebug(ctl, 5, "Longest path string = %d chars\n", maxPath);
+    if (details) {
+        virBuffer formatStr = VIR_BUFFER_INITIALIZER;
+
+        /* Is the output too long to fit on one line? */
+        if ((maxName + maxPath + 30) < 80) {
+            virBuffer headerStr = VIR_BUFFER_INITIALIZER;
+
+            /* Output is not too long - use one line per entry */
+            virBufferVSprintf(&formatStr,
+                              "%%-%us %%-6s %%-10s %%-10s  %%-%us\n",
+                              maxName < 5 ? 5 : maxName,
+                              maxPath);
+            virBufferVSprintf(&headerStr,
+                              virBufferContentAndReset(&formatStr),
+                              _("Name"), _("Type"), _("Capacity"),
+                              _("Allocation"), _("Path"));
+            unsigned int headerLength = strlen(headerStr.d);
+            vshPrintExtra(ctl, "%s", virBufferContentAndReset(&headerStr));
+
+            /* Display an underline of appropriate length */
+            for (i = 0; i < headerLength - 1; i++)
+                vshPrintExtra(ctl, "-");
+            vshPrintExtra(ctl, "\n");
+
+            /* Define output format - one line per row of volume info */
+            virBufferVSprintf(&formatStr,
+                              "%%-%us %%-6s %%-10s %%-10s  %%-%us\n",
+                              maxName < 5 ? 5 : maxName,
+                              maxPath);
+        } else {
+            /* Output IS too long - use two lines per entry */
+            virBufferVSprintf(&formatStr,
+                              "%%-%us  %%-6s %%-10s %%-10s\n      %%-%us\n",
+                              maxName < 5 ? 5 : maxName,
+                              maxPath);
+            vshPrintExtra(ctl, virBufferContentAndReset(&formatStr),
+                          _("Name"), _("Type"), _("Capacity"),
+                          _("Allocation"), _("Path"));
+
+            /* Display an underline of appropriate length */
+            if ((maxName + 30) > (maxPath + 6)) {
+                /* 30 = # chars in the header not including the name field
+                 *  6 = Padding number picked out of the air that seems
+                 *      to work ok
+                 */
+                for (i = 0; i < maxName + 30; i++)
+                    vshPrintExtra(ctl, "-");
+            } else {
+                for (i = 0; i < maxPath + 6; i++)
+                    vshPrintExtra(ctl, "-");
+            }
+            vshPrintExtra(ctl, "\n");
+
+            /* Define output format - two lines per row of volume info */
+            virBufferVSprintf(&formatStr,
+                              "%%-%us  %%-6s %%-10s %%-10s\n      %%-%us\n",
+                              maxName < 5 ? 5 : maxName,
+                              maxPath);
+        }
+
+        /* Display the volume detail rows */
+        for (i = 0; i < numVolumes; i++) {
+            /* Do we have detailed sizing info? */
+            if (volumeInfos[i] != NULL) {
+                /* We have detailed sizing info */
+                double capVal, allocVal;
+                const char *capUnit, *allocUnit;
+                virBuffer capBufStr = VIR_BUFFER_INITIALIZER;
+                virBuffer allocBufStr = VIR_BUFFER_INITIALIZER;
+
+                /* Determine the capacity value to show */
+                capVal = prettyCapacity(volumeInfos[i]->capacity, &capUnit);
+                virBufferVSprintf(&capBufStr, "%.2lf %s", capVal, capUnit);
+
+                /* Determine the allocation value to show */
+                allocVal = prettyCapacity(volumeInfos[i]->allocation,
+                                          &allocUnit);
+                virBufferVSprintf(&allocBufStr, "%.2lf %s", allocVal,
+                                  allocUnit);
+
+                /* Output volume details, showing all volume info */
+                vshPrintExtra(ctl, formatStr.d,
+                              activeNames[i],
+                              volumeInfos[i]->type == VIR_STORAGE_VOL_FILE ?
+                              _("file") : _("block"),
+                              virBufferContentAndReset(&capBufStr),
+                              virBufferContentAndReset(&allocBufStr),
+                              volumePaths[i]);
+
+                /* Cleanup memory allocation */
+                VIR_FREE(volumeInfos[i]);
+            } else {
+                /* We don't have detailed sizing info, so output
+                 * what we have */
+                vshPrintExtra(ctl, formatStr.d,
+                              activeNames[i],
+                              _("unknown"),
+                              _("unknown"),
+                              _("unknown"),
+                              volumePaths[i]);
+            }
+
+            /* Cleanup memory allocation for this volume */
+            VIR_FREE(volumePaths[i]);
+            VIR_FREE(activeNames[i]);
+        }
+    } else {
+        /* Only basic volume information needs to be shown */
+        if (maxName < 20) /* Minimum column widths in the output */
+            maxName = 20;
+        if (maxPath < 4)  /* Minimum column widths in the output */
+            maxPath = 4;
+        virBuffer outputStr = VIR_BUFFER_INITIALIZER;
+        virBufferVSprintf(&outputStr, "%%-%us %%-%us\n", maxName, maxPath);
+
+        /* Output header */
+        vshPrintExtra(ctl, outputStr.d,  _("Name"), _("Path"));
+
+        /* Display underline */
+        for (i = 0; i < maxName + maxPath + 1; i++)
+                    vshPrintExtra(ctl, "-");
+        vshPrintExtra(ctl, "\n");
+
+        /* Output the volume information rows */
+        for (i = 0; i < numVolumes; i++) {
+            vshPrint(ctl, outputStr.d, activeNames[i], volumePaths[i]);
+        }
+
+        /* Cleanup memory allocation */
+        virBufferFreeAndReset(&outputStr);
+    }
+
+    /* Cleanup remaining memory allocation */
+    VIR_FREE(volumePaths);
+    VIR_FREE(volumeInfos);
     VIR_FREE(activeNames);
     virStoragePoolFree(pool);
     return TRUE;
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 8432b44..0f387e6 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -839,10 +839,12 @@ Returns basic information about the given storage volume.
 I<--pool> I<pool-or-uuid> is the name or UUID of the storage pool the volume is in.
 I<vol-name-or-key-or-path> is the name or key or path of the volume to return information for.
 
-=item B<vol-list> I<--pool> I<pool-or-uuid>
+=item B<vol-list> I<--pool> I<pool-or-uuid> optional I<--details>
 
 Return the list of volumes in the given storage pool.
 I<--pool> I<pool-or-uuid> is the name or UUID of the storage pool.
+The I<--details> option instructs virsh to additionally display volume
+persistence and capacity related information where available.
 
 =item B<vol-pool> I<vol-key-or-path>
 
-- 
1.7.0.1




More information about the libvir-list mailing list