Add API to change qemu agent response timeout

Some layered products such as oVirt have requested a way to avoid being
blocked by guest agent commands when querying a loaded vm. For example,
many guest agent commands are polled periodically to monitor changes,
and rather than blocking the calling process, they'd prefer to simply
time out when an agent query is taking too long.

This patch adds a way for the user to specify a custom agent timeout
that is applied to all agent commands.

One special case to note here is the 'guest-sync' command. 'guest-sync'
is issued internally prior to calling any other command. (For example,
when libvirt wants to call 'guest-get-fsinfo', we first call
'guest-sync' and then call 'guest-get-fsinfo').

Previously, the 'guest-sync' command used a 5-second timeout
(VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT), whereas the actual command that
followed always blocked indefinitely
(VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK). As part of this patch, if a
custom timeout is specified that is shorter than
5 seconds,  this new timeout is also used for 'guest-sync'. If there is
no custom timeout or if the custom timeout is longer than 5 seconds, we
will continue to use the 5-second timeout.

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-11-13 16:06:09 -06:00 committed by Michal Privoznik
parent 954f36e078
commit 95f5ac9ae5
24 changed files with 281 additions and 37 deletions

View File

@ -4916,4 +4916,14 @@ int virDomainGetGuestInfo(virDomainPtr domain,
int *nparams, int *nparams,
unsigned int flags); unsigned int flags);
typedef enum {
VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK = -2,
VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_DEFAULT = -1,
VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_NOWAIT = 0,
} virDomainAgentResponseTimeoutValues;
int virDomainAgentSetResponseTimeout(virDomainPtr domain,
int timeout,
unsigned int flags);
#endif /* LIBVIRT_DOMAIN_H */ #endif /* LIBVIRT_DOMAIN_H */

View File

@ -43,10 +43,10 @@ virDomainPtr virDomainQemuAttach(virConnectPtr domain,
unsigned int flags); unsigned int flags);
typedef enum { typedef enum {
VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN = -2, VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK,
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK = -2, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK,
VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT = -1, VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_DEFAULT,
VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT = 0, VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_NOWAIT,
VIR_DOMAIN_QEMU_AGENT_COMMAND_SHUTDOWN = 60, VIR_DOMAIN_QEMU_AGENT_COMMAND_SHUTDOWN = 60,
} virDomainQemuAgentCommandTimeoutValues; } virDomainQemuAgentCommandTimeoutValues;

View File

@ -1372,6 +1372,11 @@ typedef int
int *nparams, int *nparams,
unsigned int flags); unsigned int flags);
typedef int
(*virDrvDomainAgentSetResponseTimeout)(virDomainPtr domain,
int timeout,
unsigned int flags);
typedef struct _virHypervisorDriver virHypervisorDriver; typedef struct _virHypervisorDriver virHypervisorDriver;
typedef virHypervisorDriver *virHypervisorDriverPtr; typedef virHypervisorDriver *virHypervisorDriverPtr;
@ -1632,4 +1637,5 @@ struct _virHypervisorDriver {
virDrvDomainCheckpointGetParent domainCheckpointGetParent; virDrvDomainCheckpointGetParent domainCheckpointGetParent;
virDrvDomainCheckpointDelete domainCheckpointDelete; virDrvDomainCheckpointDelete domainCheckpointDelete;
virDrvDomainGetGuestInfo domainGetGuestInfo; virDrvDomainGetGuestInfo domainGetGuestInfo;
virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout;
}; };

View File

@ -12497,3 +12497,52 @@ int virDomainGetLaunchSecurityInfo(virDomainPtr domain,
virDispatchError(domain->conn); virDispatchError(domain->conn);
return -1; return -1;
} }
/**
* virDomainAgentSetResponseTimeout:
* @domain: a domain object
* @timeout: timeout in seconds
* @flags: extra flags; not used yet, so callers should always pass 0
*
* Set how long to wait for a response from guest agent commands. By default,
* agent commands block forever waiting for a response.
*
* @timeout must be a value from virDomainAgentCommandTimeoutValues or
* positive:
*
* VIR_DOMAIN_AGENT_COMMAND_TIMEOUT_BLOCK(-2): meaning to block forever
* waiting for a result.
* VIR_DOMAIN_AGENT_COMMAND_TIMEOUT_DEFAULT(-1): use default timeout value.
* VIR_DOMAIN_AGENT_COMMAND_TIMEOUT_NOWAIT(0): does not wait.
* positive value: wait for @timeout seconds
*
* Returns 0 on success, -1 on failure
*/
int
virDomainAgentSetResponseTimeout(virDomainPtr domain,
int timeout,
unsigned int flags)
{
virConnectPtr conn;
VIR_DOMAIN_DEBUG(domain, "timeout=%i, flags=0x%x",
timeout, flags);
virResetLastError();
virCheckDomainReturn(domain, -1);
conn = domain->conn;
if (conn->driver->domainAgentSetResponseTimeout) {
if (conn->driver->domainAgentSetResponseTimeout(domain, timeout, flags) < 0)
goto error;
return 0;
}
virReportUnsupportedError();
error:
virDispatchError(conn);
return -1;
}

View File

@ -862,4 +862,9 @@ LIBVIRT_5.8.0 {
virConnectSetIdentity; virConnectSetIdentity;
} LIBVIRT_5.7.0; } LIBVIRT_5.7.0;
LIBVIRT_5.10.0 {
global:
virDomainAgentSetResponseTimeout;
} LIBVIRT_5.8.0;
# .... define new API here using predicted next version number .... # .... define new API here using predicted next version number ....

View File

@ -30,6 +30,7 @@
#include <sys/time.h> #include <sys/time.h>
#include "qemu_agent.h" #include "qemu_agent.h"
#include "qemu_domain.h"
#include "viralloc.h" #include "viralloc.h"
#include "virlog.h" #include "virlog.h"
#include "virerror.h" #include "virerror.h"
@ -127,6 +128,7 @@ struct _qemuAgent {
* but fire up an event on qemu monitor instead. * but fire up an event on qemu monitor instead.
* Take that as indication of successful completion */ * Take that as indication of successful completion */
qemuAgentEvent await_event; qemuAgentEvent await_event;
int timeout;
}; };
static virClassPtr qemuAgentClass; static virClassPtr qemuAgentClass;
@ -695,6 +697,7 @@ qemuAgentOpen(virDomainObjPtr vm,
if (!(mon = virObjectLockableNew(qemuAgentClass))) if (!(mon = virObjectLockableNew(qemuAgentClass)))
return NULL; return NULL;
mon->timeout = QEMU_DOMAIN_PRIVATE(vm)->agentTimeout;
mon->fd = -1; mon->fd = -1;
if (virCondInit(&mon->notify) < 0) { if (virCondInit(&mon->notify) < 0) {
virReportSystemError(errno, "%s", virReportSystemError(errno, "%s",
@ -907,6 +910,12 @@ qemuAgentGuestSync(qemuAgentPtr mon)
int send_ret; int send_ret;
unsigned long long id; unsigned long long id;
qemuAgentMessage sync_msg; qemuAgentMessage sync_msg;
int timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT;
/* if user specified a custom agent timeout that is lower than the
* default timeout, use the shorter timeout instead */
if ((mon->timeout >= 0) && (mon->timeout < timeout))
timeout = mon->timeout;
memset(&sync_msg, 0, sizeof(sync_msg)); memset(&sync_msg, 0, sizeof(sync_msg));
/* set only on first sync */ /* set only on first sync */
@ -925,8 +934,7 @@ qemuAgentGuestSync(qemuAgentPtr mon)
VIR_DEBUG("Sending guest-sync command with ID: %llu", id); VIR_DEBUG("Sending guest-sync command with ID: %llu", id);
send_ret = qemuAgentSend(mon, &sync_msg, send_ret = qemuAgentSend(mon, &sync_msg, timeout);
VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT);
VIR_DEBUG("qemuAgentSend returned: %d", send_ret); VIR_DEBUG("qemuAgentSend returned: %d", send_ret);
@ -1301,8 +1309,7 @@ int qemuAgentFSFreeze(qemuAgentPtr mon, const char **mountpoints,
if (!cmd) if (!cmd)
goto cleanup; goto cleanup;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) { if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) {
@ -1339,8 +1346,7 @@ int qemuAgentFSThaw(qemuAgentPtr mon)
if (!cmd) if (!cmd)
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) { if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) {
@ -1377,8 +1383,7 @@ qemuAgentSuspend(qemuAgentPtr mon,
return -1; return -1;
mon->await_event = QEMU_AGENT_EVENT_SUSPEND; mon->await_event = QEMU_AGENT_EVENT_SUSPEND;
ret = qemuAgentCommand(mon, cmd, &reply, false, ret = qemuAgentCommand(mon, cmd, &reply, false, mon->timeout);
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK);
virJSONValueFree(cmd); virJSONValueFree(cmd);
virJSONValueFree(reply); virJSONValueFree(reply);
@ -1434,8 +1439,7 @@ qemuAgentFSTrim(qemuAgentPtr mon,
if (!cmd) if (!cmd)
return ret; return ret;
ret = qemuAgentCommand(mon, cmd, &reply, false, ret = qemuAgentCommand(mon, cmd, &reply, false, mon->timeout);
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK);
virJSONValueFree(cmd); virJSONValueFree(cmd);
virJSONValueFree(reply); virJSONValueFree(reply);
@ -1456,8 +1460,7 @@ qemuAgentGetVCPUs(qemuAgentPtr mon,
if (!(cmd = qemuAgentMakeCommand("guest-get-vcpus", NULL))) if (!(cmd = qemuAgentMakeCommand("guest-get-vcpus", NULL)))
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
if (!(data = virJSONValueObjectGetArray(reply, "return"))) { if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
@ -1572,8 +1575,7 @@ qemuAgentSetVCPUsCommand(qemuAgentPtr mon,
NULL))) NULL)))
goto cleanup; goto cleanup;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
/* All negative values are invalid. Return of 0 is bogus since we wouldn't /* All negative values are invalid. Return of 0 is bogus since we wouldn't
@ -1728,8 +1730,7 @@ qemuAgentGetHostname(qemuAgentPtr mon,
if (!cmd) if (!cmd)
return ret; return ret;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) {
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
if (qemuAgentErrorCommandUnsupported(reply)) if (qemuAgentErrorCommandUnsupported(reply))
ret = -2; ret = -2;
goto cleanup; goto cleanup;
@ -1773,8 +1774,7 @@ qemuAgentGetTime(qemuAgentPtr mon,
if (!cmd) if (!cmd)
return ret; return ret;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
if (virJSONValueObjectGetNumberUlong(reply, "return", &json_time) < 0) { if (virJSONValueObjectGetNumberUlong(reply, "return", &json_time) < 0) {
@ -1839,8 +1839,7 @@ qemuAgentSetTime(qemuAgentPtr mon,
if (!cmd) if (!cmd)
return ret; return ret;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
ret = 0; ret = 0;
@ -2043,8 +2042,7 @@ qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
if (!cmd) if (!cmd)
return ret; return ret;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) {
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
if (qemuAgentErrorCommandUnsupported(reply)) if (qemuAgentErrorCommandUnsupported(reply))
ret = -2; ret = -2;
goto cleanup; goto cleanup;
@ -2333,8 +2331,7 @@ qemuAgentGetInterfaces(qemuAgentPtr mon,
if (!(cmd = qemuAgentMakeCommand("guest-network-get-interfaces", NULL))) if (!(cmd = qemuAgentMakeCommand("guest-network-get-interfaces", NULL)))
goto cleanup; goto cleanup;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
if (!(ret_array = virJSONValueObjectGet(reply, "return"))) { if (!(ret_array = virJSONValueObjectGet(reply, "return"))) {
@ -2511,8 +2508,7 @@ qemuAgentSetUserPassword(qemuAgentPtr mon,
NULL))) NULL)))
goto cleanup; goto cleanup;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0)
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup; goto cleanup;
ret = 0; ret = 0;
@ -2543,8 +2539,7 @@ qemuAgentGetUsers(qemuAgentPtr mon,
if (!(cmd = qemuAgentMakeCommand("guest-get-users", NULL))) if (!(cmd = qemuAgentMakeCommand("guest-get-users", NULL)))
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) {
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
if (qemuAgentErrorCommandUnsupported(reply)) if (qemuAgentErrorCommandUnsupported(reply))
return -2; return -2;
return -1; return -1;
@ -2633,8 +2628,7 @@ qemuAgentGetOSInfo(qemuAgentPtr mon,
if (!(cmd = qemuAgentMakeCommand("guest-get-osinfo", NULL))) if (!(cmd = qemuAgentMakeCommand("guest-get-osinfo", NULL)))
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) {
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
if (qemuAgentErrorCommandUnsupported(reply)) if (qemuAgentErrorCommandUnsupported(reply))
return -2; return -2;
return -1; return -1;
@ -2689,8 +2683,7 @@ qemuAgentGetTimezone(qemuAgentPtr mon,
if (!(cmd = qemuAgentMakeCommand("guest-get-timezone", NULL))) if (!(cmd = qemuAgentMakeCommand("guest-get-timezone", NULL)))
return -1; return -1;
if (qemuAgentCommand(mon, cmd, &reply, true, if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) {
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
if (qemuAgentErrorCommandUnsupported(reply)) if (qemuAgentErrorCommandUnsupported(reply))
return -2; return -2;
return -1; return -1;
@ -2719,3 +2712,16 @@ qemuAgentGetTimezone(qemuAgentPtr mon,
return 0; return 0;
} }
/* qemuAgentSetResponseTimeout:
* mon: agent monitor
* timeout: number of seconds to wait for agent response
*
* The agent object must be locked prior to calling this function.
*/
void
qemuAgentSetResponseTimeout(qemuAgentPtr mon,
int timeout)
{
mon->timeout = timeout;
}

View File

@ -140,3 +140,6 @@ int qemuAgentGetTimezone(qemuAgentPtr mon,
virTypedParameterPtr *params, virTypedParameterPtr *params,
int *nparams, int *nparams,
int *maxparams); int *maxparams);
void qemuAgentSetResponseTimeout(qemuAgentPtr mon,
int timeout);

View File

@ -2093,6 +2093,8 @@ qemuDomainObjPrivateAlloc(void *opaque)
if (!(priv->dbusVMStates = virHashCreate(5, dbusVMStateHashFree))) if (!(priv->dbusVMStates = virHashCreate(5, dbusVMStateHashFree)))
goto error; goto error;
/* agent commands block by default, user can choose different behavior */
priv->agentTimeout = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK;
priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX; priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
priv->driver = opaque; priv->driver = opaque;
@ -2875,6 +2877,8 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf,
if (qemuDomainObjPrivateXMLFormatSlirp(buf, vm) < 0) if (qemuDomainObjPrivateXMLFormatSlirp(buf, vm) < 0)
return -1; return -1;
virBufferAsprintf(buf, "<agentTimeout>%i</agentTimeout>\n", priv->agentTimeout);
return 0; return 0;
} }
@ -3518,6 +3522,12 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
goto error; goto error;
} }
if (virXPathInt("string(./agentTimeout)", ctxt, &priv->agentTimeout) == -2) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("failed to parse agent timeout"));
goto error;
}
if ((node = virXPathNode("./namespaces", ctxt))) { if ((node = virXPathNode("./namespaces", ctxt))) {
xmlNodePtr next; xmlNodePtr next;

View File

@ -293,6 +293,7 @@ struct _qemuDomainObjPrivate {
virDomainChrSourceDefPtr monConfig; virDomainChrSourceDefPtr monConfig;
bool monError; bool monError;
unsigned long long monStart; unsigned long long monStart;
int agentTimeout;
qemuAgentPtr agent; qemuAgentPtr agent;
bool agentError; bool agentError;

View File

@ -22685,6 +22685,61 @@ qemuDomainGetGuestInfo(virDomainPtr dom,
return ret; return ret;
} }
static int
qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
int timeout,
unsigned int flags)
{
virQEMUDriverPtr driver = dom->conn->privateData;
g_autoptr(virQEMUDriverConfig) cfg = NULL;
virDomainObjPtr vm = NULL;
int ret = -1;
virCheckFlags(0, -1);
if (timeout < VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN) {
virReportError(VIR_ERR_INVALID_ARG,
_("guest agent timeout '%d' is "
"less than the minimum '%d'"),
timeout, VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN);
return -1;
}
if (!(vm = qemuDomainObjFromDomain(dom)))
return -1;
cfg = virQEMUDriverGetConfig(driver);
if (virDomainAgentSetResponseTimeoutEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
/* If domain has an agent, change its timeout. Otherwise just save the
* request so that we can set the timeout when the agent appears */
if (qemuDomainAgentAvailable(vm, false)) {
/* We don't need to acquire a job since we're not interacting with the
* agent or the qemu monitor. We're only setting a struct member, so
* just acquire the mutex lock. Worst case, any in-process agent
* commands will use the newly-set agent timeout. */
virObjectLock(QEMU_DOMAIN_PRIVATE(vm)->agent);
qemuAgentSetResponseTimeout(QEMU_DOMAIN_PRIVATE(vm)->agent, timeout);
virObjectUnlock(QEMU_DOMAIN_PRIVATE(vm)->agent);
}
QEMU_DOMAIN_PRIVATE(vm)->agentTimeout = timeout;
if (virDomainObjIsActive(vm) &&
virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
goto cleanup;
ret = 0;
cleanup:
virDomainObjEndAPI(&vm);
return ret;
}
static virHypervisorDriver qemuHypervisorDriver = { static virHypervisorDriver qemuHypervisorDriver = {
.name = QEMU_DRIVER_NAME, .name = QEMU_DRIVER_NAME,
.connectURIProbe = qemuConnectURIProbe, .connectURIProbe = qemuConnectURIProbe,
@ -22921,6 +22976,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
.domainCheckpointGetParent = qemuDomainCheckpointGetParent, /* 5.6.0 */ .domainCheckpointGetParent = qemuDomainCheckpointGetParent, /* 5.6.0 */
.domainCheckpointDelete = qemuDomainCheckpointDelete, /* 5.6.0 */ .domainCheckpointDelete = qemuDomainCheckpointDelete, /* 5.6.0 */
.domainGetGuestInfo = qemuDomainGetGuestInfo, /* 5.7.0 */ .domainGetGuestInfo = qemuDomainGetGuestInfo, /* 5.7.0 */
.domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 5.10.0 */
}; };

View File

@ -8701,6 +8701,7 @@ static virHypervisorDriver hypervisor_driver = {
.domainCheckpointGetParent = remoteDomainCheckpointGetParent, /* 5.6.0 */ .domainCheckpointGetParent = remoteDomainCheckpointGetParent, /* 5.6.0 */
.domainCheckpointDelete = remoteDomainCheckpointDelete, /* 5.6.0 */ .domainCheckpointDelete = remoteDomainCheckpointDelete, /* 5.6.0 */
.domainGetGuestInfo = remoteDomainGetGuestInfo, /* 5.7.0 */ .domainGetGuestInfo = remoteDomainGetGuestInfo, /* 5.7.0 */
.domainAgentSetResponseTimeout = remoteDomainAgentSetResponseTimeout, /* 5.10.0 */
}; };
static virNetworkDriver network_driver = { static virNetworkDriver network_driver = {

View File

@ -3744,6 +3744,16 @@ struct remote_connect_set_identity_args {
unsigned int flags; unsigned int flags;
}; };
struct remote_domain_agent_set_response_timeout_args {
remote_nonnull_domain dom;
int timeout;
unsigned int flags;
};
struct remote_domain_agent_set_response_timeout_ret {
int result;
};
/*----- Protocol. -----*/ /*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */ /* Define the program number, protocol version and procedure numbers here. */
@ -6617,5 +6627,11 @@ enum remote_procedure {
* @generate: client * @generate: client
* @acl: connect:write * @acl: connect:write
*/ */
REMOTE_PROC_CONNECT_SET_IDENTITY = 419 REMOTE_PROC_CONNECT_SET_IDENTITY = 419,
/**
* @generate: both
* @acl: domain:write
*/
REMOTE_PROC_DOMAIN_AGENT_SET_RESPONSE_TIMEOUT = 420
}; };

View File

@ -3114,6 +3114,14 @@ struct remote_connect_set_identity_args {
} params; } params;
u_int flags; u_int flags;
}; };
struct remote_domain_agent_set_response_timeout_args {
remote_nonnull_domain dom;
int timeout;
u_int flags;
};
struct remote_domain_agent_set_response_timeout_ret {
int result;
};
enum remote_procedure { enum remote_procedure {
REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_OPEN = 1,
REMOTE_PROC_CONNECT_CLOSE = 2, REMOTE_PROC_CONNECT_CLOSE = 2,
@ -3534,4 +3542,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417, REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417,
REMOTE_PROC_DOMAIN_GET_GUEST_INFO = 418, REMOTE_PROC_DOMAIN_GET_GUEST_INFO = 418,
REMOTE_PROC_CONNECT_SET_IDENTITY = 419, REMOTE_PROC_CONNECT_SET_IDENTITY = 419,
REMOTE_PROC_DOMAIN_AGENT_SET_RESPONSE_TIMEOUT = 420,
}; };

View File

@ -338,6 +338,7 @@
</chains> </chains>
</blockjob> </blockjob>
</blockjobs> </blockjobs>
<agentTimeout>-2</agentTimeout>
<domain type='kvm' id='4'> <domain type='kvm' id='4'>
<name>copy</name> <name>copy</name>
<uuid>0439a4a8-db56-4933-9183-d8681d7b0746</uuid> <uuid>0439a4a8-db56-4933-9183-d8681d7b0746</uuid>

View File

@ -23,6 +23,7 @@
<channelTargetDir path='/tmp/channel'/> <channelTargetDir path='/tmp/channel'/>
<allowReboot value='yes'/> <allowReboot value='yes'/>
<blockjobs active='yes'/> <blockjobs active='yes'/>
<agentTimeout>-2</agentTimeout>
<domain type='qemu' id='1'> <domain type='qemu' id='1'>
<name>QEMUGuest1</name> <name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>

View File

@ -258,6 +258,7 @@
<chardevStdioLogd/> <chardevStdioLogd/>
<allowReboot value='yes'/> <allowReboot value='yes'/>
<blockjobs active='no'/> <blockjobs active='no'/>
<agentTimeout>-2</agentTimeout>
<domain type='kvm' id='1'> <domain type='kvm' id='1'>
<name>upstream</name> <name>upstream</name>
<uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid> <uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid>

View File

@ -257,6 +257,7 @@
<chardevStdioLogd/> <chardevStdioLogd/>
<allowReboot value='yes'/> <allowReboot value='yes'/>
<blockjobs active='no'/> <blockjobs active='no'/>
<agentTimeout>-2</agentTimeout>
<domain type='kvm' id='1'> <domain type='kvm' id='1'>
<name>nest</name> <name>nest</name>
<uuid>994cee0d-2a70-4937-9693-0431e39d20f7</uuid> <uuid>994cee0d-2a70-4937-9693-0431e39d20f7</uuid>

View File

@ -260,6 +260,7 @@
<chardevStdioLogd/> <chardevStdioLogd/>
<allowReboot value='yes'/> <allowReboot value='yes'/>
<blockjobs active='no'/> <blockjobs active='no'/>
<agentTimeout>-2</agentTimeout>
<domain type='kvm' id='4'> <domain type='kvm' id='4'>
<name>upstream</name> <name>upstream</name>
<uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid> <uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid>

View File

@ -289,6 +289,7 @@
<chardevStdioLogd/> <chardevStdioLogd/>
<allowReboot value='yes'/> <allowReboot value='yes'/>
<blockjobs active='no'/> <blockjobs active='no'/>
<agentTimeout>-2</agentTimeout>
<domain type='kvm' id='3'> <domain type='kvm' id='3'>
<name>upstream</name> <name>upstream</name>
<uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid> <uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid>

View File

@ -271,6 +271,7 @@
<chardevStdioLogd/> <chardevStdioLogd/>
<allowReboot value='yes'/> <allowReboot value='yes'/>
<blockjobs active='no'/> <blockjobs active='no'/>
<agentTimeout>-2</agentTimeout>
<domain type='kvm' id='7'> <domain type='kvm' id='7'>
<name>nest</name> <name>nest</name>
<uuid>994cee0d-2a70-4937-9693-0431e39d20f7</uuid> <uuid>994cee0d-2a70-4937-9693-0431e39d20f7</uuid>

View File

@ -261,6 +261,7 @@
<allowReboot value='yes'/> <allowReboot value='yes'/>
<nodename index='123'/> <nodename index='123'/>
<blockjobs active='no'/> <blockjobs active='no'/>
<agentTimeout>-2</agentTimeout>
<domain type='kvm' id='1'> <domain type='kvm' id='1'>
<name>upstream</name> <name>upstream</name>
<uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid> <uuid>dcf47dbd-46d1-4d5b-b442-262a806a333a</uuid>

View File

@ -309,6 +309,7 @@
<channelTargetDir path='/tmp/channel'/> <channelTargetDir path='/tmp/channel'/>
<allowReboot value='yes'/> <allowReboot value='yes'/>
<blockjobs active='no'/> <blockjobs active='no'/>
<agentTimeout>-2</agentTimeout>
<domain type='kvm'> <domain type='kvm'>
<name>QEMUGuest1</name> <name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>

View File

@ -13971,6 +13971,52 @@ cmdDomFSInfo(vshControl *ctl, const vshCmd *cmd)
return ret; return ret;
} }
/*
* "guest-agent-timeout" command
*/
static const vshCmdInfo info_guest_agent_timeout[] = {
{.name = "help",
.data = N_("Set the guest agent timeout")
},
{.name = "desc",
.data = N_("Set the number of seconds to wait for a response from the guest agent.")
},
{.name = NULL}
};
static const vshCmdOptDef opts_guest_agent_timeout[] = {
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
{.name = "timeout",
.type = VSH_OT_INT,
.flags = VSH_OFLAG_REQ_OPT,
.help = N_("timeout seconds.")
},
{.name = NULL}
};
static bool
cmdGuestAgentTimeout(vshControl *ctl, const vshCmd *cmd)
{
virDomainPtr dom = NULL;
int timeout;
const unsigned int flags = 0;
bool ret = false;
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
return false;
if (vshCommandOptInt(ctl, cmd, "timeout", &timeout) < 0)
goto cleanup;
if (virDomainAgentSetResponseTimeout(dom, timeout, flags) < 0)
goto cleanup;
ret = true;
cleanup:
virshDomainFree(dom);
return ret;
}
/* /*
* "guestinfo" command * "guestinfo" command
*/ */
@ -14492,6 +14538,12 @@ const vshCmdDef domManagementCmds[] = {
.info = info_qemu_agent_command, .info = info_qemu_agent_command,
.flags = 0 .flags = 0
}, },
{.name = "guest-agent-timeout",
.handler = cmdGuestAgentTimeout,
.opts = opts_guest_agent_timeout,
.info = info_guest_agent_timeout,
.flags = 0
},
{.name = "reboot", {.name = "reboot",
.handler = cmdReboot, .handler = cmdReboot,
.opts = opts_reboot, .opts = opts_reboot,

View File

@ -1820,6 +1820,17 @@ events until a timeout or interrupt key.
When I<--timestamp> is used, a human-readable timestamp will be printed When I<--timestamp> is used, a human-readable timestamp will be printed
before the event. before the event.
=item B<guest-agent-timeout> I<domain> I<--timeout> B<value>
Set how long to wait for a response from guest agent commands. By default,
agent commands block forever waiting for a response. B<value> must be a
positive value (wait for given amount of seconds) or one of the following
values:
-2 - block forever waiting for a resuly,
-1 - reset timeout to the default value,
0 - do not wait at all,
=item B<guestinfo> I<domain> [I<--user>] [I<--os>] [I<--timezone>] =item B<guestinfo> I<domain> [I<--user>] [I<--os>] [I<--timezone>]
[I<--hostname>] [I<--filesystem>] [I<--hostname>] [I<--filesystem>]