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