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

Reply via email to