qemu: guestinfo: handle unsupported agent commands

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>
This commit is contained in:
Jonathon Jongsma 2019-08-27 15:35:54 -05:00 committed by Michal Privoznik
parent 56cac62bfd
commit a931486a97
3 changed files with 82 additions and 23 deletions

View File

@ -995,6 +995,26 @@ qemuAgentStringifyErrorClass(const char *klass)
return "unknown QEMU command error"; 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 /* Ignoring OOM in this method, since we're already reporting
* a more important error * a more important error
* *
@ -1708,8 +1728,11 @@ qemuAgentGetHostname(qemuAgentPtr mon,
return ret; return ret;
if (qemuAgentCommand(mon, cmd, &reply, true, 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; goto cleanup;
}
if (!(data = virJSONValueObjectGet(reply, "return"))) { if (!(data = virJSONValueObjectGet(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -2005,6 +2028,10 @@ qemuAgentGetFSInfoInternalDisk(virJSONValuePtr jsondisks,
return 0; return 0;
} }
/* Returns: 0 on success
* -2 when agent command is not supported by the agent
* -1 otherwise
*/
static int static int
qemuAgentGetFSInfoInternal(qemuAgentPtr mon, qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
qemuAgentFSInfoPtr **info, qemuAgentFSInfoPtr **info,
@ -2023,8 +2050,11 @@ qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
return ret; return ret;
if (qemuAgentCommand(mon, cmd, &reply, true, 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; goto cleanup;
}
if (!(data = virJSONValueObjectGet(reply, "return"))) { if (!(data = virJSONValueObjectGet(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -2141,6 +2171,9 @@ qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
return ret; return ret;
} }
/* Returns: 0 on success
* -1 otherwise
*/
int int
qemuAgentGetFSInfo(qemuAgentPtr mon, qemuAgentGetFSInfo(qemuAgentPtr mon,
virDomainFSInfoPtr **info, virDomainFSInfoPtr **info,
@ -2178,6 +2211,10 @@ qemuAgentGetFSInfo(qemuAgentPtr mon,
return ret; return ret;
} }
/* Returns: 0 on success
* -2 when agent command is not supported by the agent
* -1 otherwise
*/
int int
qemuAgentGetFSInfoParams(qemuAgentPtr mon, qemuAgentGetFSInfoParams(qemuAgentPtr mon,
virTypedParameterPtr *params, virTypedParameterPtr *params,
@ -2190,7 +2227,7 @@ qemuAgentGetFSInfoParams(qemuAgentPtr mon,
int nfs; int nfs;
if ((nfs = qemuAgentGetFSInfoInternal(mon, &fsinfo, vmdef)) < 0) if ((nfs = qemuAgentGetFSInfoInternal(mon, &fsinfo, vmdef)) < 0)
return -1; return nfs;
if (virTypedParamsAddUInt(params, nparams, maxparams, if (virTypedParamsAddUInt(params, nparams, maxparams,
"fs.count", nfs) < 0) "fs.count", nfs) < 0)
@ -2499,6 +2536,10 @@ qemuAgentSetUserPassword(qemuAgentPtr mon,
return ret; return ret;
} }
/* Returns: 0 on success
* -2 when agent command is not supported by the agent
* -1 otherwise
*/
int int
qemuAgentGetUsers(qemuAgentPtr mon, qemuAgentGetUsers(qemuAgentPtr mon,
virTypedParameterPtr *params, virTypedParameterPtr *params,
@ -2515,8 +2556,11 @@ qemuAgentGetUsers(qemuAgentPtr mon,
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, 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; return -1;
}
if (!(data = virJSONValueObjectGetArray(reply, "return"))) { if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -2584,6 +2628,10 @@ qemuAgentGetUsers(qemuAgentPtr mon,
return ndata; return ndata;
} }
/* Returns: 0 on success
* -2 when agent command is not supported by the agent
* -1 otherwise
*/
int int
qemuAgentGetOSInfo(qemuAgentPtr mon, qemuAgentGetOSInfo(qemuAgentPtr mon,
virTypedParameterPtr *params, virTypedParameterPtr *params,
@ -2598,8 +2646,11 @@ qemuAgentGetOSInfo(qemuAgentPtr mon,
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, 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; return -1;
}
if (!(data = virJSONValueObjectGetObject(reply, "return"))) { if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -2631,6 +2682,10 @@ qemuAgentGetOSInfo(qemuAgentPtr mon,
return 0; return 0;
} }
/* Returns: 0 on success
* -2 when agent command is not supported by the agent
* -1 otherwise
*/
int int
qemuAgentGetTimezone(qemuAgentPtr mon, qemuAgentGetTimezone(qemuAgentPtr mon,
virTypedParameterPtr *params, virTypedParameterPtr *params,
@ -2647,8 +2702,11 @@ qemuAgentGetTimezone(qemuAgentPtr mon,
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, 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; return -1;
}
if (!(data = virJSONValueObjectGetObject(reply, "return"))) { if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",

View File

@ -23220,6 +23220,7 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
int maxparams = 0; int maxparams = 0;
VIR_AUTOFREE(char *) hostname = NULL; VIR_AUTOFREE(char *) hostname = NULL;
unsigned int supportedTypes = types; unsigned int supportedTypes = types;
int rc;
virCheckFlags(0, -1); virCheckFlags(0, -1);
qemuDomainGetGuestInfoCheckSupport(&supportedTypes); qemuDomainGetGuestInfoCheckSupport(&supportedTypes);
@ -23240,30 +23241,30 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
agent = qemuDomainObjEnterAgent(vm); agent = qemuDomainObjEnterAgent(vm);
/* Although the libvirt qemu driver supports all of these guest info types, /* The agent info commands will return -2 for any commands that are not
* some guest agents might be too old to support these commands. If these * supported by the agent, or -1 for all other errors. In the case where no
* info categories were explicitly requested (i.e. 'types' is non-zero), * categories were explicitly requested (i.e. 'types' is 0), ignore
* abort and report an error on any failures, otherwise continue and return * 'unsupported' errors and gather as much information as we can. In all
* as much info as is supported by the guest agent. */ * other cases, abort on error. */
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_USERS) { if (supportedTypes & VIR_DOMAIN_GUEST_INFO_USERS) {
if (qemuAgentGetUsers(agent, params, nparams, &maxparams) < 0 && rc = qemuAgentGetUsers(agent, params, nparams, &maxparams);
types != 0) if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent; goto exitagent;
} }
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_OS) { if (supportedTypes & VIR_DOMAIN_GUEST_INFO_OS) {
if (qemuAgentGetOSInfo(agent, params, nparams, &maxparams) < 0 rc = qemuAgentGetOSInfo(agent, params, nparams, &maxparams);
&& types != 0) if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent; goto exitagent;
} }
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_TIMEZONE) { if (supportedTypes & VIR_DOMAIN_GUEST_INFO_TIMEZONE) {
if (qemuAgentGetTimezone(agent, params, nparams, &maxparams) < 0 rc = qemuAgentGetTimezone(agent, params, nparams, &maxparams);
&& types != 0) if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent; goto exitagent;
} }
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_HOSTNAME) { if (supportedTypes & VIR_DOMAIN_GUEST_INFO_HOSTNAME) {
if (qemuAgentGetHostname(agent, &hostname) < 0) { rc = qemuAgentGetHostname(agent, &hostname);
if (types != 0) if (rc < 0 && !(rc == -2 && types == 0)) {
goto exitagent; goto exitagent;
} else { } else {
if (virTypedParamsAddString(params, nparams, &maxparams, "hostname", if (virTypedParamsAddString(params, nparams, &maxparams, "hostname",
hostname) < 0) hostname) < 0)
@ -23271,8 +23272,8 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
} }
} }
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_FILESYSTEM) { if (supportedTypes & VIR_DOMAIN_GUEST_INFO_FILESYSTEM) {
if (qemuAgentGetFSInfoParams(agent, params, nparams, &maxparams, vm->def) < 0 && rc = qemuAgentGetFSInfoParams(agent, params, nparams, &maxparams, vm->def);
types != 0) if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent; goto exitagent;
} }

View File

@ -462,7 +462,7 @@ testQemuAgentGetFSInfoParams(const void *data)
goto cleanup; goto cleanup;
if (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test), &params, if (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test), &params,
&nparams, &maxparams, def) != -1) { &nparams, &maxparams, def) != -2) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"agent get-fsinfo command should have failed"); "agent get-fsinfo command should have failed");
goto cleanup; goto cleanup;