mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
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:
parent
56cac62bfd
commit
a931486a97
@ -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",
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ testQemuAgentGetFSInfoParams(const void *data)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test), ¶ms,
|
if (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test), ¶ms,
|
||||||
&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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user