]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: guestinfo: handle unsupported agent commands
authorJonathon Jongsma <jjongsma@redhat.com>
Tue, 27 Aug 2019 20:35:54 +0000 (15:35 -0500)
committerMichal Privoznik <mprivozn@redhat.com>
Thu, 29 Aug 2019 10:03:23 +0000 (12:03 +0200)
When we're collecting guest information, older agents may not support
all agent commands. In the case where the user requested all info
types (i.e. types == 0), ignore unsupported command errors and gather as
much information as possible. If the agent command failed for some other
reason, or if the user explciitly requested a specific info type (i.e.
types != 0), abort on the first error.

Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/qemu/qemu_agent.c
src/qemu/qemu_driver.c
tests/qemuagenttest.c

index f2a8bb62632b2d390a381d8614616e607be80cf8..c53a78ed44aeecbe9f9ad3c048d88baee5651033 100644 (file)
@@ -995,6 +995,26 @@ qemuAgentStringifyErrorClass(const char *klass)
         return "unknown QEMU command error";
 }
 
+/* Checks whether the agent reply msg is an error caused by an unsupported
+ * command.
+ *
+ * Returns true when reply is CommandNotFound or CommandDisabled
+ *         false otherwise
+ */
+static bool
+qemuAgentErrorCommandUnsupported(virJSONValuePtr reply)
+{
+    const char *klass;
+    virJSONValuePtr error = virJSONValueObjectGet(reply, "error");
+
+    if (!error)
+        return false;
+
+    klass = virJSONValueObjectGetString(error, "class");
+    return STREQ_NULLABLE(klass, "CommandNotFound") ||
+        STREQ_NULLABLE(klass, "CommandDisabled");
+}
+
 /* Ignoring OOM in this method, since we're already reporting
  * a more important error
  *
@@ -1708,8 +1728,11 @@ qemuAgentGetHostname(qemuAgentPtr mon,
         return ret;
 
     if (qemuAgentCommand(mon, cmd, &reply, true,
-                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+        if (qemuAgentErrorCommandUnsupported(reply))
+            ret = -2;
         goto cleanup;
+    }
 
     if (!(data = virJSONValueObjectGet(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -2005,6 +2028,10 @@ qemuAgentGetFSInfoInternalDisk(virJSONValuePtr jsondisks,
     return 0;
 }
 
+/* Returns: 0 on success
+ *          -2 when agent command is not supported by the agent
+ *          -1 otherwise
+ */
 static int
 qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
                            qemuAgentFSInfoPtr **info,
@@ -2023,8 +2050,11 @@ qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
         return ret;
 
     if (qemuAgentCommand(mon, cmd, &reply, true,
-                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+        if (qemuAgentErrorCommandUnsupported(reply))
+            ret = -2;
         goto cleanup;
+    }
 
     if (!(data = virJSONValueObjectGet(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -2141,6 +2171,9 @@ qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
     return ret;
 }
 
+/* Returns: 0 on success
+ *          -1 otherwise
+ */
 int
 qemuAgentGetFSInfo(qemuAgentPtr mon,
                    virDomainFSInfoPtr **info,
@@ -2178,6 +2211,10 @@ qemuAgentGetFSInfo(qemuAgentPtr mon,
     return ret;
 }
 
+/* Returns: 0 on success
+ *          -2 when agent command is not supported by the agent
+ *          -1 otherwise
+ */
 int
 qemuAgentGetFSInfoParams(qemuAgentPtr mon,
                          virTypedParameterPtr *params,
@@ -2190,7 +2227,7 @@ qemuAgentGetFSInfoParams(qemuAgentPtr mon,
     int nfs;
 
     if ((nfs = qemuAgentGetFSInfoInternal(mon, &fsinfo, vmdef)) < 0)
-        return -1;
+        return nfs;
 
     if (virTypedParamsAddUInt(params, nparams, maxparams,
                               "fs.count", nfs) < 0)
@@ -2499,6 +2536,10 @@ qemuAgentSetUserPassword(qemuAgentPtr mon,
     return ret;
 }
 
+/* Returns: 0 on success
+ *          -2 when agent command is not supported by the agent
+ *          -1 otherwise
+ */
 int
 qemuAgentGetUsers(qemuAgentPtr mon,
                   virTypedParameterPtr *params,
@@ -2515,8 +2556,11 @@ qemuAgentGetUsers(qemuAgentPtr mon,
         return -1;
 
     if (qemuAgentCommand(mon, cmd, &reply, true,
-                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+        if (qemuAgentErrorCommandUnsupported(reply))
+            return -2;
         return -1;
+    }
 
     if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -2584,6 +2628,10 @@ qemuAgentGetUsers(qemuAgentPtr mon,
     return ndata;
 }
 
+/* Returns: 0 on success
+ *          -2 when agent command is not supported by the agent
+ *          -1 otherwise
+ */
 int
 qemuAgentGetOSInfo(qemuAgentPtr mon,
                    virTypedParameterPtr *params,
@@ -2598,8 +2646,11 @@ qemuAgentGetOSInfo(qemuAgentPtr mon,
         return -1;
 
     if (qemuAgentCommand(mon, cmd, &reply, true,
-                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+        if (qemuAgentErrorCommandUnsupported(reply))
+            return -2;
         return -1;
+    }
 
     if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -2631,6 +2682,10 @@ qemuAgentGetOSInfo(qemuAgentPtr mon,
     return 0;
 }
 
+/* Returns: 0 on success
+ *          -2 when agent command is not supported by the agent
+ *          -1 otherwise
+ */
 int
 qemuAgentGetTimezone(qemuAgentPtr mon,
                      virTypedParameterPtr *params,
@@ -2647,8 +2702,11 @@ qemuAgentGetTimezone(qemuAgentPtr mon,
         return -1;
 
     if (qemuAgentCommand(mon, cmd, &reply, true,
-                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+                         VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+        if (qemuAgentErrorCommandUnsupported(reply))
+            return -2;
         return -1;
+    }
 
     if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
index d0e67863eafe1681208f402b95f328f10a6da9b5..78f5471b794bde1db237852f16937a14dc7da64c 100644 (file)
@@ -23220,6 +23220,7 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
     int maxparams = 0;
     VIR_AUTOFREE(char *) hostname = NULL;
     unsigned int supportedTypes = types;
+    int rc;
 
     virCheckFlags(0, -1);
     qemuDomainGetGuestInfoCheckSupport(&supportedTypes);
@@ -23240,30 +23241,30 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
 
     agent = qemuDomainObjEnterAgent(vm);
 
-    /* Although the libvirt qemu driver supports all of these guest info types,
-     * some guest agents might be too old to support these commands. If these
-     * info categories were explicitly requested (i.e. 'types' is non-zero),
-     * abort and report an error on any failures, otherwise continue and return
-     * as much info as is supported by the guest agent. */
+    /* The agent info commands will return -2 for any commands that are not
+     * supported by the agent, or -1 for all other errors. In the case where no
+     * categories were explicitly requested (i.e. 'types' is 0), ignore
+     * 'unsupported' errors and gather as much information as we can. In all
+     * other cases, abort on error. */
     if (supportedTypes & VIR_DOMAIN_GUEST_INFO_USERS) {
-        if (qemuAgentGetUsers(agent, params, nparams, &maxparams) < 0 &&
-            types != 0)
+        rc = qemuAgentGetUsers(agent, params, nparams, &maxparams);
+        if (rc < 0 && !(rc == -2 && types == 0))
             goto exitagent;
     }
     if (supportedTypes & VIR_DOMAIN_GUEST_INFO_OS) {
-        if (qemuAgentGetOSInfo(agent, params, nparams, &maxparams) < 0
-            && types != 0)
+        rc = qemuAgentGetOSInfo(agent, params, nparams, &maxparams);
+        if (rc < 0 && !(rc == -2 && types == 0))
             goto exitagent;
     }
     if (supportedTypes & VIR_DOMAIN_GUEST_INFO_TIMEZONE) {
-        if (qemuAgentGetTimezone(agent, params, nparams, &maxparams) < 0
-            && types != 0)
+        rc = qemuAgentGetTimezone(agent, params, nparams, &maxparams);
+        if (rc < 0 && !(rc == -2 && types == 0))
             goto exitagent;
     }
     if (supportedTypes & VIR_DOMAIN_GUEST_INFO_HOSTNAME) {
-        if (qemuAgentGetHostname(agent, &hostname) < 0) {
-            if (types != 0)
-                goto exitagent;
+        rc = qemuAgentGetHostname(agent, &hostname);
+        if (rc < 0 && !(rc == -2 && types == 0)) {
+            goto exitagent;
         } else {
             if (virTypedParamsAddString(params, nparams, &maxparams, "hostname",
                                         hostname) < 0)
@@ -23271,8 +23272,8 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
         }
     }
     if (supportedTypes & VIR_DOMAIN_GUEST_INFO_FILESYSTEM) {
-        if (qemuAgentGetFSInfoParams(agent, params, nparams, &maxparams, vm->def) < 0 &&
-            types != 0)
+        rc = qemuAgentGetFSInfoParams(agent, params, nparams, &maxparams, vm->def);
+        if (rc < 0 && !(rc == -2 && types == 0))
             goto exitagent;
     }
 
index ae57da598999ac2e198bd0b47aa6b09afe807605..91f19644d5780239bd2b23ba20668514c074757a 100644 (file)
@@ -462,7 +462,7 @@ testQemuAgentGetFSInfoParams(const void *data)
         goto cleanup;
 
     if (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test), &params,
-                                 &nparams, &maxparams, def) != -1) {
+                                 &nparams, &maxparams, def) != -2) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        "agent get-fsinfo command should have failed");
         goto cleanup;