* tools/virsh.c (cmdSetvcpus): Add new flags. Let invalid
commands through to driver, to ease testing of hypervisor argument
validation.
(cmdVcpucount): New command.
(commands): Add new command.
* tools/virsh.pod (setvcpus, vcpucount): Document new behavior.
---
I know - the typical API addition sequence adds driver support
first and then virsh support. I can rearrange the patch order
if desired.
tools/virsh.c | 211 +--
tools/virsh.pod | 28 +++-
2 files changed, 217 insertions(+), 22 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 85014f2..0fcfdb7 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2220,10 +2220,181 @@ cmdFreecell(vshControl *ctl, const vshCmd *cmd)
}
/*
+ * vcpucount command
+ */
+static const vshCmdInfo info_vcpucount[] = {
+{help, N_(domain vcpu counts)},
+{desc, N_(Returns the number of domain virtual CPUs.)},
+{NULL, NULL}
+};
+
+static const vshCmdOptDef opts_vcpucount[] = {
+{domain, VSH_OT_DATA, VSH_OFLAG_REQ, N_(domain name, id or uuid)},
+{maximum, VSH_OT_BOOL, 0, N_(get maximum cap on vcpus)},
+{current, VSH_OT_BOOL, 0, N_(get current vcpu usage)},
+{persistent, VSH_OT_BOOL, 0, N_(get value to be used on next boot)},
+{active, VSH_OT_BOOL, 0, N_(get value from running domain)},
+{NULL, 0, 0, NULL}
+};
+
+static int
+cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
+{
+virDomainPtr dom;
+int ret = TRUE;
+int maximum = vshCommandOptBool(cmd, maximum);
+int current = vshCommandOptBool(cmd, current);
+int persistent = vshCommandOptBool(cmd, persistent);
+int active = vshCommandOptBool(cmd, active);
+bool all = maximum + current + persistent + active == 0;
+int count;
+
+if (maximum current) {
+vshError(ctl, %s,
+ _(--maximum and --current cannot both be specified));
+return FALSE;
+}
+if (persistent active) {
+vshError(ctl, %s,
+ _(--persistent and --active cannot both be specified));
+return FALSE;
+}
+if (maximum + current + persistent + active == 1) {
+vshError(ctl,
+ _(when using --%s, either --%s or --%s must be specified),
+ maximum ? maximum : current ? current
+ : persistent ? persistent : active,
+ maximum + current ? persistent : maximum,
+ maximum + current ? active : current);
+return FALSE;
+}
+
+if (!vshConnectionUsability(ctl, ctl-conn))
+return FALSE;
+
+if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+return FALSE;
+
+/* In all cases, try the new API first; if it fails because we are
+ * talking to an older client, try a fallback API before giving
+ * up. */
+if (all || (maximum persistent)) {
+count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
+ VIR_DOMAIN_VCPU_PERSISTENT));
+if (count 0 (last_error-code == VIR_ERR_NO_SUPPORT
+ || last_error-code == VIR_ERR_INVALID_ARG)) {
+char *tmp;
+char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
+if (xml (tmp = strstr(xml, vcpu))) {
+tmp = strchr(tmp, '');
+if (!tmp || virStrToLong_i(tmp + 1, tmp, 10, count) 0)
+count = -1;
+}
+VIR_FREE(xml);
+}
+
+if (count 0) {
+virshReportError(ctl);
+ret = FALSE;
+} else if (all) {
+vshPrint(ctl, %-12s %-12s %3d\n, _(maximum), _(persistent),
+ count);
+} else {
+vshPrint(ctl, %d\n, count);
+}
+virFreeError(last_error);
+last_error = NULL;
+}
+
+if (all || (maximum active)) {
+count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM |
+ VIR_DOMAIN_VCPU_ACTIVE));
+if (count 0 (last_error-code == VIR_ERR_NO_SUPPORT
+ || last_error-code == VIR_ERR_INVALID_ARG)) {
+count = virDomainGetMaxVcpus(dom);
+}
+
+if (count 0) {
+virshReportError(ctl);
+ret = FALSE;
+} else if (all) {
+vshPrint(ctl, %-12s %-12s %3d\n, _(maximum), _(active),
+ count);
+} else {
+vshPrint(ctl, %d\n, count);
+}
+virFreeError(last_error);
+last_error = NULL;
+}
+
+if (all || (current persistent)) {
+count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_PERSISTENT);
+if (count 0 (last_error-code == VIR_ERR_NO_SUPPORT
+ || last_error-code == VIR_ERR_INVALID_ARG)) {
+char *tmp, *end;
+char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
+if (xml (tmp = strstr(xml, vcpu))) {
+