mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +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";
|
||||
}
|
||||
|
||||
/* 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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -462,7 +462,7 @@ testQemuAgentGetFSInfoParams(const void *data)
|
||||
goto cleanup;
|
||||
|
||||
if (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test), ¶ms,
|
||||
&nparams, &maxparams, def) != -1) {
|
||||
&nparams, &maxparams, def) != -2) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
"agent get-fsinfo command should have failed");
|
||||
goto cleanup;
|
||||
|
Loading…
x
Reference in New Issue
Block a user