diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 22277b0a84..a2f007568c 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4916,4 +4916,14 @@ int virDomainGetGuestInfo(virDomainPtr domain, int *nparams, 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 */ diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h index 891617443f..0cc2872821 100644 --- a/include/libvirt/libvirt-qemu.h +++ b/include/libvirt/libvirt-qemu.h @@ -43,10 +43,10 @@ virDomainPtr virDomainQemuAttach(virConnectPtr domain, unsigned int flags); typedef enum { - VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN = -2, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK = -2, - VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT = -1, - VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT = 0, + VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK, + VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK, + VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_DEFAULT, + VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_NOWAIT, VIR_DOMAIN_QEMU_AGENT_COMMAND_SHUTDOWN = 60, } virDomainQemuAgentCommandTimeoutValues; diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index 015b2cd01c..4afd8f6ec5 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1372,6 +1372,11 @@ typedef int int *nparams, unsigned int flags); +typedef int +(*virDrvDomainAgentSetResponseTimeout)(virDomainPtr domain, + int timeout, + unsigned int flags); + typedef struct _virHypervisorDriver virHypervisorDriver; typedef virHypervisorDriver *virHypervisorDriverPtr; @@ -1632,4 +1637,5 @@ struct _virHypervisorDriver { virDrvDomainCheckpointGetParent domainCheckpointGetParent; virDrvDomainCheckpointDelete domainCheckpointDelete; virDrvDomainGetGuestInfo domainGetGuestInfo; + virDrvDomainAgentSetResponseTimeout domainAgentSetResponseTimeout; }; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index dcab179e6e..02622cb2ca 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -12497,3 +12497,52 @@ int virDomainGetLaunchSecurityInfo(virDomainPtr domain, virDispatchError(domain->conn); 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; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index f88a77892f..c92f083758 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -862,4 +862,9 @@ LIBVIRT_5.8.0 { virConnectSetIdentity; } LIBVIRT_5.7.0; +LIBVIRT_5.10.0 { + global: + virDomainAgentSetResponseTimeout; +} LIBVIRT_5.8.0; + # .... define new API here using predicted next version number .... diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c index 5a50f7f3be..7905a74f90 100644 --- a/src/qemu/qemu_agent.c +++ b/src/qemu/qemu_agent.c @@ -30,6 +30,7 @@ #include #include "qemu_agent.h" +#include "qemu_domain.h" #include "viralloc.h" #include "virlog.h" #include "virerror.h" @@ -127,6 +128,7 @@ struct _qemuAgent { * but fire up an event on qemu monitor instead. * Take that as indication of successful completion */ qemuAgentEvent await_event; + int timeout; }; static virClassPtr qemuAgentClass; @@ -695,6 +697,7 @@ qemuAgentOpen(virDomainObjPtr vm, if (!(mon = virObjectLockableNew(qemuAgentClass))) return NULL; + mon->timeout = QEMU_DOMAIN_PRIVATE(vm)->agentTimeout; mon->fd = -1; if (virCondInit(&mon->notify) < 0) { virReportSystemError(errno, "%s", @@ -907,6 +910,12 @@ qemuAgentGuestSync(qemuAgentPtr mon) int send_ret; unsigned long long id; 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)); /* set only on first sync */ @@ -925,8 +934,7 @@ qemuAgentGuestSync(qemuAgentPtr mon) VIR_DEBUG("Sending guest-sync command with ID: %llu", id); - send_ret = qemuAgentSend(mon, &sync_msg, - VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT); + send_ret = qemuAgentSend(mon, &sync_msg, timeout); VIR_DEBUG("qemuAgentSend returned: %d", send_ret); @@ -1301,8 +1309,7 @@ int qemuAgentFSFreeze(qemuAgentPtr mon, const char **mountpoints, if (!cmd) goto cleanup; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) { @@ -1339,8 +1346,7 @@ int qemuAgentFSThaw(qemuAgentPtr mon) if (!cmd) return -1; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) { @@ -1377,8 +1383,7 @@ qemuAgentSuspend(qemuAgentPtr mon, return -1; mon->await_event = QEMU_AGENT_EVENT_SUSPEND; - ret = qemuAgentCommand(mon, cmd, &reply, false, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK); + ret = qemuAgentCommand(mon, cmd, &reply, false, mon->timeout); virJSONValueFree(cmd); virJSONValueFree(reply); @@ -1434,8 +1439,7 @@ qemuAgentFSTrim(qemuAgentPtr mon, if (!cmd) return ret; - ret = qemuAgentCommand(mon, cmd, &reply, false, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK); + ret = qemuAgentCommand(mon, cmd, &reply, false, mon->timeout); virJSONValueFree(cmd); virJSONValueFree(reply); @@ -1456,8 +1460,7 @@ qemuAgentGetVCPUs(qemuAgentPtr mon, if (!(cmd = qemuAgentMakeCommand("guest-get-vcpus", NULL))) return -1; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; if (!(data = virJSONValueObjectGetArray(reply, "return"))) { @@ -1572,8 +1575,7 @@ qemuAgentSetVCPUsCommand(qemuAgentPtr mon, NULL))) goto cleanup; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; /* All negative values are invalid. Return of 0 is bogus since we wouldn't @@ -1728,8 +1730,7 @@ qemuAgentGetHostname(qemuAgentPtr mon, if (!cmd) return ret; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) { + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) { if (qemuAgentErrorCommandUnsupported(reply)) ret = -2; goto cleanup; @@ -1773,8 +1774,7 @@ qemuAgentGetTime(qemuAgentPtr mon, if (!cmd) return ret; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; if (virJSONValueObjectGetNumberUlong(reply, "return", &json_time) < 0) { @@ -1839,8 +1839,7 @@ qemuAgentSetTime(qemuAgentPtr mon, if (!cmd) return ret; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; ret = 0; @@ -2043,8 +2042,7 @@ qemuAgentGetFSInfoInternal(qemuAgentPtr mon, if (!cmd) return ret; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) { + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) { if (qemuAgentErrorCommandUnsupported(reply)) ret = -2; goto cleanup; @@ -2333,8 +2331,7 @@ qemuAgentGetInterfaces(qemuAgentPtr mon, if (!(cmd = qemuAgentMakeCommand("guest-network-get-interfaces", NULL))) goto cleanup; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; if (!(ret_array = virJSONValueObjectGet(reply, "return"))) { @@ -2511,8 +2508,7 @@ qemuAgentSetUserPassword(qemuAgentPtr mon, NULL))) goto cleanup; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) goto cleanup; ret = 0; @@ -2543,8 +2539,7 @@ qemuAgentGetUsers(qemuAgentPtr mon, if (!(cmd = qemuAgentMakeCommand("guest-get-users", NULL))) return -1; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) { + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) { if (qemuAgentErrorCommandUnsupported(reply)) return -2; return -1; @@ -2633,8 +2628,7 @@ qemuAgentGetOSInfo(qemuAgentPtr mon, if (!(cmd = qemuAgentMakeCommand("guest-get-osinfo", NULL))) return -1; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) { + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) { if (qemuAgentErrorCommandUnsupported(reply)) return -2; return -1; @@ -2689,8 +2683,7 @@ qemuAgentGetTimezone(qemuAgentPtr mon, if (!(cmd = qemuAgentMakeCommand("guest-get-timezone", NULL))) return -1; - if (qemuAgentCommand(mon, cmd, &reply, true, - VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) { + if (qemuAgentCommand(mon, cmd, &reply, true, mon->timeout) < 0) { if (qemuAgentErrorCommandUnsupported(reply)) return -2; return -1; @@ -2719,3 +2712,16 @@ qemuAgentGetTimezone(qemuAgentPtr mon, 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; +} diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h index 78e648992a..85e436cf68 100644 --- a/src/qemu/qemu_agent.h +++ b/src/qemu/qemu_agent.h @@ -140,3 +140,6 @@ int qemuAgentGetTimezone(qemuAgentPtr mon, virTypedParameterPtr *params, int *nparams, int *maxparams); + +void qemuAgentSetResponseTimeout(qemuAgentPtr mon, + int timeout); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index ace3761e20..e14b414518 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2093,6 +2093,8 @@ qemuDomainObjPrivateAlloc(void *opaque) if (!(priv->dbusVMStates = virHashCreate(5, dbusVMStateHashFree))) 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->driver = opaque; @@ -2875,6 +2877,8 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, if (qemuDomainObjPrivateXMLFormatSlirp(buf, vm) < 0) return -1; + virBufferAsprintf(buf, "%i\n", priv->agentTimeout); + return 0; } @@ -3518,6 +3522,12 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, 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))) { xmlNodePtr next; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index ab00b25789..98a9540275 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -293,6 +293,7 @@ struct _qemuDomainObjPrivate { virDomainChrSourceDefPtr monConfig; bool monError; unsigned long long monStart; + int agentTimeout; qemuAgentPtr agent; bool agentError; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index bb75fe5807..2f06217a5f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -22685,6 +22685,61 @@ qemuDomainGetGuestInfo(virDomainPtr dom, 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 = { .name = QEMU_DRIVER_NAME, .connectURIProbe = qemuConnectURIProbe, @@ -22921,6 +22976,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainCheckpointGetParent = qemuDomainCheckpointGetParent, /* 5.6.0 */ .domainCheckpointDelete = qemuDomainCheckpointDelete, /* 5.6.0 */ .domainGetGuestInfo = qemuDomainGetGuestInfo, /* 5.7.0 */ + .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 5.10.0 */ }; diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 503f49a902..a1384fc655 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -8701,6 +8701,7 @@ static virHypervisorDriver hypervisor_driver = { .domainCheckpointGetParent = remoteDomainCheckpointGetParent, /* 5.6.0 */ .domainCheckpointDelete = remoteDomainCheckpointDelete, /* 5.6.0 */ .domainGetGuestInfo = remoteDomainGetGuestInfo, /* 5.7.0 */ + .domainAgentSetResponseTimeout = remoteDomainAgentSetResponseTimeout, /* 5.10.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index f4e3392212..23e42d17b1 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3744,6 +3744,16 @@ struct remote_connect_set_identity_args { 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. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -6617,5 +6627,11 @@ enum remote_procedure { * @generate: client * @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 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 51606e7473..9ad7a857e0 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -3114,6 +3114,14 @@ struct remote_connect_set_identity_args { } params; 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 { REMOTE_PROC_CONNECT_OPEN = 1, REMOTE_PROC_CONNECT_CLOSE = 2, @@ -3534,4 +3542,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417, REMOTE_PROC_DOMAIN_GET_GUEST_INFO = 418, REMOTE_PROC_CONNECT_SET_IDENTITY = 419, + REMOTE_PROC_DOMAIN_AGENT_SET_RESPONSE_TIMEOUT = 420, }; diff --git a/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml b/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml index e9031b7087..4f6930001e 100644 --- a/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml +++ b/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml @@ -338,6 +338,7 @@ + -2 copy 0439a4a8-db56-4933-9183-d8681d7b0746 diff --git a/tests/qemustatusxml2xmldata/blockjob-mirror-in.xml b/tests/qemustatusxml2xmldata/blockjob-mirror-in.xml index 0fba3b69e7..abd9f62965 100644 --- a/tests/qemustatusxml2xmldata/blockjob-mirror-in.xml +++ b/tests/qemustatusxml2xmldata/blockjob-mirror-in.xml @@ -23,6 +23,7 @@ + -2 QEMUGuest1 c7a5fdbd-edaf-9455-926a-d65c16db1809 diff --git a/tests/qemustatusxml2xmldata/disk-secinfo-upgrade-out.xml b/tests/qemustatusxml2xmldata/disk-secinfo-upgrade-out.xml index 3d5e8f1438..5d3287606f 100644 --- a/tests/qemustatusxml2xmldata/disk-secinfo-upgrade-out.xml +++ b/tests/qemustatusxml2xmldata/disk-secinfo-upgrade-out.xml @@ -258,6 +258,7 @@ + -2 upstream dcf47dbd-46d1-4d5b-b442-262a806a333a diff --git a/tests/qemustatusxml2xmldata/migration-in-params-in.xml b/tests/qemustatusxml2xmldata/migration-in-params-in.xml index 80cc4b4666..fdc2d39173 100644 --- a/tests/qemustatusxml2xmldata/migration-in-params-in.xml +++ b/tests/qemustatusxml2xmldata/migration-in-params-in.xml @@ -257,6 +257,7 @@ + -2 nest 994cee0d-2a70-4937-9693-0431e39d20f7 diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-out.xml b/tests/qemustatusxml2xmldata/migration-out-nbd-out.xml index 455c30be85..304fb1b77f 100644 --- a/tests/qemustatusxml2xmldata/migration-out-nbd-out.xml +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-out.xml @@ -260,6 +260,7 @@ + -2 upstream dcf47dbd-46d1-4d5b-b442-262a806a333a diff --git a/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml b/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml index 409e97a918..d69796e029 100644 --- a/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml +++ b/tests/qemustatusxml2xmldata/migration-out-nbd-tls-out.xml @@ -289,6 +289,7 @@ + -2 upstream dcf47dbd-46d1-4d5b-b442-262a806a333a diff --git a/tests/qemustatusxml2xmldata/migration-out-params-in.xml b/tests/qemustatusxml2xmldata/migration-out-params-in.xml index 4a660281d2..1956eac120 100644 --- a/tests/qemustatusxml2xmldata/migration-out-params-in.xml +++ b/tests/qemustatusxml2xmldata/migration-out-params-in.xml @@ -271,6 +271,7 @@ + -2 nest 994cee0d-2a70-4937-9693-0431e39d20f7 diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxml2xmldata/modern-in.xml index 2125b899f4..8a2718293f 100644 --- a/tests/qemustatusxml2xmldata/modern-in.xml +++ b/tests/qemustatusxml2xmldata/modern-in.xml @@ -261,6 +261,7 @@ + -2 upstream dcf47dbd-46d1-4d5b-b442-262a806a333a diff --git a/tests/qemustatusxml2xmldata/vcpus-multi-in.xml b/tests/qemustatusxml2xmldata/vcpus-multi-in.xml index b8ec650714..11ec74ecf8 100644 --- a/tests/qemustatusxml2xmldata/vcpus-multi-in.xml +++ b/tests/qemustatusxml2xmldata/vcpus-multi-in.xml @@ -309,6 +309,7 @@ + -2 QEMUGuest1 c7a5fdbd-edaf-9455-926a-d65c16db1809 diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 0feb21ef17..cfdaec1673 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -13971,6 +13971,52 @@ cmdDomFSInfo(vshControl *ctl, const vshCmd *cmd) 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 */ @@ -14492,6 +14538,12 @@ const vshCmdDef domManagementCmds[] = { .info = info_qemu_agent_command, .flags = 0 }, + {.name = "guest-agent-timeout", + .handler = cmdGuestAgentTimeout, + .opts = opts_guest_agent_timeout, + .info = info_guest_agent_timeout, + .flags = 0 + }, {.name = "reboot", .handler = cmdReboot, .opts = opts_reboot, diff --git a/tools/virsh.pod b/tools/virsh.pod index cf2798e71a..c261d403d8 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1820,6 +1820,17 @@ events until a timeout or interrupt key. When I<--timestamp> is used, a human-readable timestamp will be printed before the event. +=item B I I<--timeout> B + +Set how long to wait for a response from guest agent commands. By default, +agent commands block forever waiting for a response. B 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 I [I<--user>] [I<--os>] [I<--timezone>] [I<--hostname>] [I<--filesystem>]