From: Peter Krempa <pkre...@redhat.com> The new condition allows waiting for the guest agent to show up, which usually means that the guest has booted enough to respond to external stimuli.
Signed-off-by: Peter Krempa <pkre...@redhat.com> --- docs/manpages/virsh.rst | 5 +++++ tools/virsh-domain-event.c | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst index 1515f84063..0259c21065 100644 --- a/docs/manpages/virsh.rst +++ b/docs/manpages/virsh.rst @@ -3080,6 +3080,11 @@ Supported conditions: domain is or becomes inactive + *guest-agent-available* + + the guest agent inside the guest connects and becomes available for commands + (usually means that the guest has booted) + If *--timeout* is specified, the command gives up waiting for the condition to satisfy after *seconds* have elapsed. If SIGINT is delivered to virsh (usually via ``Ctrl-C``) the wait is given up immediately. In non-interactive diff --git a/tools/virsh-domain-event.c b/tools/virsh-domain-event.c index 2cd52933c7..de33ed9d74 100644 --- a/tools/virsh-domain-event.c +++ b/tools/virsh-domain-event.c @@ -24,6 +24,7 @@ #include "virenum.h" #include "virtime.h" #include "virtypedparam.h" +#include "virxml.h" /* * "event" command @@ -1109,6 +1110,20 @@ virshDomainEventAwaitCallbackLifecycle(virConnectPtr conn G_GNUC_UNUSED, } +static void +virshDomainEventAwaitAgentLifecycle(virConnectPtr conn G_GNUC_UNUSED, + virDomainPtr dom G_GNUC_UNUSED, + int state G_GNUC_UNUSED, + int reason G_GNUC_UNUSED, + void *opaque G_GNUC_UNUSED) +{ + struct virshDomEventAwaitConditionData *data = opaque; + + if (data->cond->handler(data) < 1) + vshEventDone(data->ctl); +} + + struct virshDomainEventAwaitCallbackTuple { int event; virConnectDomainEventGenericCallback eventCB; @@ -1120,6 +1135,9 @@ static const struct virshDomainEventAwaitCallbackTuple callbacks[] = { .event = VIR_DOMAIN_EVENT_ID_LIFECYCLE, .eventCB = VIR_DOMAIN_EVENT_CALLBACK(virshDomainEventAwaitCallbackLifecycle), }, + { .event = VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE, + .eventCB = VIR_DOMAIN_EVENT_CALLBACK(virshDomainEventAwaitAgentLifecycle), + }, }; @@ -1152,11 +1170,35 @@ virshDomainEventAwaitConditionDomainInactive(struct virshDomEventAwaitConditionD } +static int +virshDomainEventAwaitConditionGuestAgentAvailable(struct virshDomEventAwaitConditionData *data) +{ + g_autoptr(xmlDoc) xml = NULL; + g_autoptr(xmlXPathContext) ctxt = NULL; + g_autofree char *state = NULL; + + if (virshDomainGetXMLFromDom(data->ctl, data->dom, 0, &xml, &ctxt) < 0) + return -1; + + if ((state = virXPathString("string(//devices/channel/target[@name = 'org.qemu.guest_agent.0']/@state)", + ctxt))) { + if (STREQ(state, "connected")) + return 0; + } + + return 1; +} + + static const struct virshDomainEventAwaitCondition conditions[] = { { .name = "domain-inactive", .event = VIR_DOMAIN_EVENT_ID_LIFECYCLE, .handler = virshDomainEventAwaitConditionDomainInactive, }, + { .name = "guest-agent-available", + .event = VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE, + .handler = virshDomainEventAwaitConditionGuestAgentAvailable, + }, }; -- 2.49.0