cmdDomblkinfo: add --all to show all block devices info

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>
This commit is contained in:
Chen Hanxiao 2018-06-19 18:01:24 +08:00 committed by John Ferlan
parent 4afcaa8843
commit 62c3919328
2 changed files with 118 additions and 22 deletions

View File

@ -388,8 +388,7 @@ static const vshCmdInfo info_domblkinfo[] = {
static const vshCmdOptDef opts_domblkinfo[] = { static const vshCmdOptDef opts_domblkinfo[] = {
VIRSH_COMMON_OPT_DOMAIN_FULL(0), VIRSH_COMMON_OPT_DOMAIN_FULL(0),
{.name = "device", {.name = "device",
.type = VSH_OT_DATA, .type = VSH_OT_STRING,
.flags = VSH_OFLAG_REQ,
.completer = virshDomainDiskTargetCompleter, .completer = virshDomainDiskTargetCompleter,
.help = N_("block device") .help = N_("block device")
}, },
@ -397,30 +396,66 @@ static const vshCmdOptDef opts_domblkinfo[] = {
.type = VSH_OT_BOOL, .type = VSH_OT_BOOL,
.help = N_("Human readable output") .help = N_("Human readable output")
}, },
{.name = "all",
.type = VSH_OT_BOOL,
.help = N_("display all block devices info")
},
{.name = NULL} {.name = NULL}
}; };
static void static void
cmdDomblkinfoPrint(vshControl *ctl, cmdDomblkinfoPrint(vshControl *ctl,
const virDomainBlockInfo *info, const virDomainBlockInfo *info,
bool human) const char *device,
bool human, bool title)
{ {
if (!human) { char *cap = NULL;
vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info->capacity); char *alloc = NULL;
vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info->allocation); char *phy = NULL;
vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info->physical);
} else {
double val;
const char *unit;
val = vshPrettyCapacity(info->capacity, &unit); if (title) {
vshPrint(ctl, "%-15s %-.3lf %s\n", _("Capacity:"), val, unit); vshPrintExtra(ctl, "%-10s %-15s %-15s %-15s\n", _("Target"),
val = vshPrettyCapacity(info->allocation, &unit); _("Capacity"), _("Allocation"), _("Physical"));
vshPrint(ctl, "%-15s %-.3lf %s\n", _("Allocation:"), val, unit); vshPrintExtra(ctl, "-----------------------------"
val = vshPrettyCapacity(info->physical, &unit); "------------------------\n");
vshPrint(ctl, "%-15s %-.3lf %s\n", _("Physical:"), val, unit); 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 {
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; virDomainPtr dom;
bool ret = false; bool ret = false;
bool human = false; bool human = false;
bool all = false;
const char *device = NULL; 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))) if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
return false; return false;
if (vshCommandOptStringReq(ctl, cmd, "device", &device) < 0) all = vshCommandOptBool(cmd, "all");
goto cleanup; if (!all && vshCommandOptStringQuiet(ctl, cmd, "device", &device) <= 0) {
vshError(ctl, "command 'domblkinfo' requires <device> option");
if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
goto cleanup; goto cleanup;
}
human = vshCommandOptBool(cmd, "human"); 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; ret = true;
cleanup: cleanup:
virshDomainFree(dom); virshDomainFree(dom);
VIR_FREE(target);
VIR_FREE(protocol);
VIR_FREE(disks);
xmlXPathFreeContext(ctxt);
xmlFreeDoc(xmldoc);
return ret; return ret;
} }

View 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 B<domblkerror> command lists all block devices in error state and
the error seen on each of them. 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 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 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 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 also B<domblklist> for listing these names). If I<--human> is set, the
output will have a human readable output. 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>] =item B<domblklist> I<domain> [I<--inactive>] [I<--details>]