]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
virsh: await: Introduce 'guest-agent-available' condition
authorPeter Krempa <pkrempa@redhat.com>
Wed, 4 Jun 2025 07:48:40 +0000 (09:48 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 12 Jun 2025 08:17:03 +0000 (10:17 +0200)
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 <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
docs/manpages/virsh.rst
tools/virsh-domain-event.c

index 565c2a395a759ce2c0b0cb4ef137c082db8fa70e..e13b5020b56db1d996962ac1206559cf23b0b4a6 100644 (file)
@@ -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
index 2cd52933c7853f654660798c93d175e78476c7ee..de33ed9d74650581e03bfb9b4de519ef95b12463 100644 (file)
@@ -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,
+    },
 };