[libvirt] [PATCH] qemu: Emit domain events for all virtio-serial channels

Matt Broadstone mbroadst at gmail.com
Mon Nov 7 20:48:35 UTC 2016


Presently domain events are emitted for the "agent lifecycle" which
is a specialization on virtio-serial events specific to the channel
named "org.qemu.guest_agent.0". This patch adds a generic event for
"channel lifecycles", which emit state change events for all
attached channels.
---
 daemon/remote.c                     | 42 +++++++++++++++++
 examples/object-events/event-test.c | 57 ++++++++++++++++++++++++
 include/libvirt/libvirt-domain.h    | 41 +++++++++++++++++
 src/conf/domain_event.c             | 89 +++++++++++++++++++++++++++++++++++++
 src/conf/domain_event.h             | 12 +++++
 src/libvirt_private.syms            |  2 +
 src/qemu/qemu_driver.c              |  5 +++
 src/qemu/qemu_process.c             |  6 +++
 src/remote/remote_driver.c          | 32 +++++++++++++
 src/remote/remote_protocol.x        | 17 ++++++-
 src/remote_protocol-structs         |  7 +++
 tools/virsh-domain.c                | 35 +++++++++++++++
 12 files changed, 344 insertions(+), 1 deletion(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index e414f92..25b32f2 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1086,6 +1086,47 @@ remoteRelayDomainEventAgentLifecycle(virConnectPtr conn,
 
 
 static int
+remoteRelayDomainEventChannelLifecycle(virConnectPtr conn,
+                                       virDomainPtr dom,
+                                       const char *channelName,
+                                       int state,
+                                       int reason,
+                                       void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
+    remote_domain_event_callback_channel_lifecycle_msg data;
+
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+        return -1;
+
+    VIR_DEBUG("Relaying domain channel lifecycle event %s %d, callback %d, "
+              " name: %s, state %d, reason %d",
+              dom->name, dom->id, callback->callbackID, channelName, state, reason);
+
+    /* build return data */
+    memset(&data, 0, sizeof(data));
+    data.callbackID = callback->callbackID;
+    make_nonnull_domain(&data.dom, dom);
+
+    if (VIR_STRDUP(data.channelName, channelName) < 0)
+        goto error;
+    data.state = state;
+    data.reason = reason;
+
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
+                                  REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE,
+                                  (xdrproc_t)xdr_remote_domain_event_callback_channel_lifecycle_msg,
+                                  &data);
+
+    return 0;
+ error:
+    VIR_FREE(data.channelName);
+    return -1;
+}
+
+
+static int
 remoteRelayDomainEventDeviceAdded(virConnectPtr conn,
                                   virDomainPtr dom,
                                   const char *devAlias,
@@ -1248,6 +1289,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventJobCompleted),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed),
+    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventChannelLifecycle)
 };
 
 verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c
index 730cb8b..da023eb 100644
--- a/examples/object-events/event-test.c
+++ b/examples/object-events/event-test.c
@@ -337,6 +337,46 @@ guestAgentLifecycleEventReasonToString(int event)
     return "unknown";
 }
 
+
+static const char *
+guestChannelLifecycleEventStateToString(int event)
+{
+    switch ((virConnectDomainEventChannelLifecycleState) event) {
+    case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_DISCONNECTED:
+        return "Disconnected";
+
+    case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_CONNECTED:
+        return "Connected";
+
+    case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST:
+        break;
+    }
+
+    return "unknown";
+}
+
+
+static const char *
+guestChannelLifecycleEventReasonToString(int event)
+{
+    switch ((virConnectDomainEventChannelLifecycleReason) event) {
+    case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_UNKNOWN:
+        return "Unknown";
+
+    case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_DOMAIN_STARTED:
+        return "Domain started";
+
+    case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL:
+        return "Channel event";
+
+    case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST:
+        break;
+    }
+
+    return "unknown";
+}
+
+
 static const char *
 storagePoolEventToString(int event)
 {
@@ -797,6 +837,22 @@ myDomainEventAgentLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
     return 0;
 }
 
+static int
+myDomainEventChannelLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                      virDomainPtr dom,
+                                      const char *channelName,
+                                      int state,
+                                      int reason,
+                                      void *opaque ATTRIBUTE_UNUSED)
+{
+    printf("%s EVENT: Domain %s(%d) guest channel(%s) state changed: %s reason: %s\n",
+           __func__, virDomainGetName(dom), virDomainGetID(dom), channelName,
+           guestChannelLifecycleEventStateToString(state),
+           guestChannelLifecycleEventReasonToString(reason));
+
+    return 0;
+}
+
 
 static int
 myDomainEventDeviceAddedCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -971,6 +1027,7 @@ struct domainEventData domainEvents[] = {
     DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION, myDomainEventMigrationIterationCallback),
     DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_JOB_COMPLETED, myDomainEventJobCompletedCallback),
     DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback),
+    DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE, myDomainEventChannelLifecycleCallback)
 };
 
 struct storagePoolEventData {
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 5f50660..d720132 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3965,6 +3965,46 @@ typedef void (*virConnectDomainEventAgentLifecycleCallback)(virConnectPtr conn,
                                                             int reason,
                                                             void *opaque);
 
+typedef enum {
+    VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_CONNECTED = 1, /* channel connected */
+    VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_DISCONNECTED = 2, /* channel disconnected */
+
+# ifdef VIR_ENUM_SENTINELS
+    VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST
+# endif
+} virConnectDomainEventChannelLifecycleState;
+
+typedef enum {
+    VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_UNKNOWN = 0, /* unknown state change reason */
+    VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_DOMAIN_STARTED = 1, /* state changed due to domain start */
+    VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL = 2, /* channel state changed */
+
+# ifdef VIR_ENUM_SENTINELS
+    VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST
+# endif
+} virConnectDomainEventChannelLifecycleReason;
+
+/**
+ * virConnectDomainEventChannelLifecycleCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @channelName: the name of the channel on which the event occurred
+ * @state: new state of the guest channel, one of virConnectDomainEventChannelLifecycleState
+ * @reason: reason for state change; one of virConnectDomainEventChannelLifecycleReason
+ * @opaque: application specified data
+ *
+ * This callback occurs when libvirt detects a change in the state of a guest
+ * serial channel.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventChannelLifecycleCallback)(virConnectPtr conn,
+                                                              virDomainPtr dom,
+                                                              const char *channelName,
+                                                              int state,
+                                                              int reason,
+                                                              void *opaque);
 
 /**
  * VIR_DOMAIN_EVENT_CALLBACK:
@@ -4006,6 +4046,7 @@ typedef enum {
     VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION = 20, /* virConnectDomainEventMigrationIterationCallback */
     VIR_DOMAIN_EVENT_ID_JOB_COMPLETED = 21,  /* virConnectDomainEventJobCompletedCallback */
     VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED = 22, /* virConnectDomainEventDeviceRemovalFailedCallback */
+    VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE = 23, /* virConnectDomainEventChannelLifecycleCallback */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_ID_LAST
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 63ae9e1..f971a0d 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -55,6 +55,7 @@ static virClassPtr virDomainEventPMClass;
 static virClassPtr virDomainQemuMonitorEventClass;
 static virClassPtr virDomainEventTunableClass;
 static virClassPtr virDomainEventAgentLifecycleClass;
+static virClassPtr virDomainEventChannelLifecycleClass;
 static virClassPtr virDomainEventDeviceAddedClass;
 static virClassPtr virDomainEventMigrationIterationClass;
 static virClassPtr virDomainEventJobCompletedClass;
@@ -75,6 +76,7 @@ static void virDomainEventPMDispose(void *obj);
 static void virDomainQemuMonitorEventDispose(void *obj);
 static void virDomainEventTunableDispose(void *obj);
 static void virDomainEventAgentLifecycleDispose(void *obj);
+static void virDomainEventChannelLifecycleDispose(void *obj);
 static void virDomainEventDeviceAddedDispose(void *obj);
 static void virDomainEventMigrationIterationDispose(void *obj);
 static void virDomainEventJobCompletedDispose(void *obj);
@@ -241,6 +243,16 @@ struct _virDomainEventAgentLifecycle {
 typedef struct _virDomainEventAgentLifecycle virDomainEventAgentLifecycle;
 typedef virDomainEventAgentLifecycle *virDomainEventAgentLifecyclePtr;
 
+struct _virDomainEventChannelLifecycle {
+    virDomainEvent parent;
+
+    char *channelName;
+    int state;
+    int reason;
+};
+typedef struct _virDomainEventChannelLifecycle virDomainEventChannelLifecycle;
+typedef virDomainEventChannelLifecycle *virDomainEventChannelLifecyclePtr;
+
 struct _virDomainEventMigrationIteration {
     virDomainEvent parent;
 
@@ -367,6 +379,12 @@ virDomainEventsOnceInit(void)
                       sizeof(virDomainEventAgentLifecycle),
                       virDomainEventAgentLifecycleDispose)))
         return -1;
+    if (!(virDomainEventChannelLifecycleClass =
+          virClassNew(virDomainEventClass,
+                      "virDomainEventChannelLifecycle",
+                      sizeof(virDomainEventChannelLifecycle),
+                      virDomainEventChannelLifecycleDispose)))
+        return -1;
     if (!(virDomainEventMigrationIterationClass =
           virClassNew(virDomainEventClass,
                       "virDomainEventMigrationIteration",
@@ -557,6 +575,15 @@ virDomainEventAgentLifecycleDispose(void *obj)
 };
 
 static void
+virDomainEventChannelLifecycleDispose(void *obj)
+{
+    virDomainEventChannelLifecyclePtr event = obj;
+    VIR_DEBUG("obj=%p", event);
+
+    VIR_FREE(event->channelName);
+};
+
+static void
 virDomainEventMigrationIterationDispose(void *obj)
 {
     virDomainEventMigrationIterationPtr event = obj;
@@ -1460,6 +1487,56 @@ virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom,
 }
 
 static virObjectEventPtr
+virDomainEventChannelLifecycleNew(int id,
+                                  const char *name,
+                                  const unsigned char *uuid,
+                                  const char *channelName,
+                                  int state,
+                                  int reason)
+{
+    virDomainEventChannelLifecyclePtr ev;
+
+    if (virDomainEventsInitialize() < 0)
+        return NULL;
+
+    if (!(ev = virDomainEventNew(virDomainEventChannelLifecycleClass,
+                                 VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE,
+                                 id, name, uuid)))
+        return NULL;
+
+    if (VIR_STRDUP(ev->channelName, channelName) < 0) {
+        virObjectUnref(ev);
+        return NULL;
+    }
+
+    ev->state = state;
+    ev->reason = reason;
+
+    return (virObjectEventPtr)ev;
+}
+
+virObjectEventPtr
+virDomainEventChannelLifecycleNewFromObj(virDomainObjPtr obj,
+                                         const char *channelName,
+                                         int state,
+                                         int reason)
+{
+    return virDomainEventChannelLifecycleNew(obj->def->id, obj->def->name,
+                                             obj->def->uuid, channelName, state, reason);
+}
+
+virObjectEventPtr
+virDomainEventChannelLifecycleNewFromDom(virDomainPtr dom,
+                                         const char *channelName,
+                                         int state,
+                                         int reason)
+{
+    return virDomainEventChannelLifecycleNew(dom->id, dom->name, dom->uuid,
+                                             channelName, state, reason);
+}
+
+
+static virObjectEventPtr
 virDomainEventMigrationIterationNew(int id,
                                     const char *name,
                                     const unsigned char *uuid,
@@ -1812,6 +1889,18 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
             goto cleanup;
         }
 
+    case VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE:
+        {
+            virDomainEventChannelLifecyclePtr channelLifecycleEvent;
+            channelLifecycleEvent = (virDomainEventChannelLifecyclePtr)event;
+            ((virConnectDomainEventChannelLifecycleCallback)cb)(conn, dom,
+                                                                channelLifecycleEvent->channelName,
+                                                                channelLifecycleEvent->state,
+                                                                channelLifecycleEvent->reason,
+                                                                cbopaque);
+            goto cleanup;
+        }
+
     case VIR_DOMAIN_EVENT_ID_DEVICE_ADDED:
         {
             virDomainEventDeviceAddedPtr deviceAddedEvent;
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 54fa879..3a689b3 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -217,6 +217,18 @@ virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom,
                                        int reason);
 
 virObjectEventPtr
+virDomainEventChannelLifecycleNewFromObj(virDomainObjPtr obj,
+                                         const char *channelName,
+                                         int state,
+                                         int reason);
+
+virObjectEventPtr
+virDomainEventChannelLifecycleNewFromDom(virDomainPtr dom,
+                                         const char *channelName,
+                                         int state,
+                                         int reason);
+
+virObjectEventPtr
 virDomainEventMigrationIterationNewFromObj(virDomainObjPtr obj,
                                            int iteration);
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 74dd527..e259687 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -535,6 +535,8 @@ virDomainEventBlockJob2NewFromDom;
 virDomainEventBlockJob2NewFromObj;
 virDomainEventBlockJobNewFromDom;
 virDomainEventBlockJobNewFromObj;
+virDomainEventChannelLifecycleNewFromDom;
+virDomainEventChannelLifecycleNewFromObj;
 virDomainEventControlErrorNewFromDom;
 virDomainEventControlErrorNewFromObj;
 virDomainEventDeviceAddedNewFromDom;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 38c8414..b464412 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4407,6 +4407,7 @@ processSerialChangedEvent(virQEMUDriverPtr driver,
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
     virDomainChrDeviceState newstate;
     virObjectEventPtr event = NULL;
+    virObjectEventPtr channelEvent = NULL;
     virDomainDeviceDef dev;
     qemuDomainObjPrivatePtr priv = vm->privateData;
     int rc;
@@ -4482,6 +4483,10 @@ processSerialChangedEvent(virQEMUDriverPtr driver,
         qemuDomainEventQueue(driver, event);
     }
 
+    channelEvent = virDomainEventChannelLifecycleNewFromObj(vm, dev.data.chr->target.name, newstate,
+                                                            VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL);
+    qemuDomainEventQueue(driver, channelEvent);
+
  endjob:
     qemuDomainObjEndJob(driver, vm);
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 1b67aee..31b5028 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1931,6 +1931,7 @@ qemuProcessRefreshChannelVirtioState(virQEMUDriverPtr driver,
     int agentReason = VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL;
     qemuMonitorChardevInfoPtr entry;
     virObjectEventPtr event = NULL;
+    virObjectEventPtr channelEvent = NULL;
     char id[32];
 
     if (booted)
@@ -1958,6 +1959,11 @@ qemuProcessRefreshChannelVirtioState(virQEMUDriverPtr driver,
                                                                 agentReason)))
                 qemuDomainEventQueue(driver, event);
 
+
+            channelEvent =
+                virDomainEventChannelLifecycleNewFromObj(vm, chr->target.name, entry->state, agentReason);
+            qemuDomainEventQueue(driver, channelEvent);
+
             chr->state = entry->state;
         }
     }
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index a3cd7cd..c778c42 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -345,6 +345,11 @@ remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog,
                                              void *evdata, void *opaque);
 
 static void
+remoteDomainBuildEventCallbackChannelLifecycle(virNetClientProgramPtr prog,
+                                               virNetClientPtr client,
+                                               void *evdata, void *opaque);
+
+static void
 remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog,
                                                  virNetClientPtr client,
                                                  void *evdata, void *opaque);
@@ -538,6 +543,10 @@ static virNetClientProgramEvent remoteEvents[] = {
       remoteDomainBuildEventCallbackAgentLifecycle,
       sizeof(remote_domain_event_callback_agent_lifecycle_msg),
       (xdrproc_t)xdr_remote_domain_event_callback_agent_lifecycle_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE,
+      remoteDomainBuildEventCallbackChannelLifecycle,
+      sizeof(remote_domain_event_callback_channel_lifecycle_msg),
+      (xdrproc_t)xdr_remote_domain_event_callback_channel_lifecycle_msg },
     { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_DEVICE_ADDED,
       remoteDomainBuildEventCallbackDeviceAdded,
       sizeof(remote_domain_event_callback_device_added_msg),
@@ -5152,6 +5161,29 @@ remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog ATTRIBU
 
 
 static void
+remoteDomainBuildEventCallbackChannelLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                               virNetClientPtr client ATTRIBUTE_UNUSED,
+                                               void *evdata, void *opaque)
+{
+    virConnectPtr conn = opaque;
+    remote_domain_event_callback_channel_lifecycle_msg *msg = evdata;
+    struct private_data *priv = conn->privateData;
+    virDomainPtr dom;
+    virObjectEventPtr event = NULL;
+
+    if (!(dom = get_nonnull_domain(conn, msg->dom)))
+        return;
+
+    event = virDomainEventChannelLifecycleNewFromDom(dom, msg->channelName, msg->state,
+                                                     msg->reason);
+
+    virObjectUnref(dom);
+
+    remoteEventQueue(priv, event, msg->callbackID);
+}
+
+
+static void
 remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
                                                  virNetClientPtr client ATTRIBUTE_UNUSED,
                                                  void *evdata,
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index e8382dc..e5227c4 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3242,6 +3242,15 @@ struct remote_domain_event_callback_agent_lifecycle_msg {
     int reason;
 };
 
+struct remote_domain_event_callback_channel_lifecycle_msg {
+    int callbackID;
+    remote_nonnull_domain dom;
+
+    char *channelName;
+    int state;
+    int reason;
+};
+
 struct remote_connect_get_all_domain_stats_ret {
     remote_domain_stats_record retStats<REMOTE_DOMAIN_LIST_MAX>;
 };
@@ -5934,5 +5943,11 @@ enum remote_procedure {
      * @generate: both
      * @acl: none
      */
-    REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377
+    REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377,
+
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE = 378
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index b71accc..7921016 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2689,6 +2689,13 @@ struct remote_domain_event_callback_agent_lifecycle_msg {
         int                        state;
         int                        reason;
 };
+struct remote_domain_event_callback_channel_lifecycle_msg {
+        int                        callbackID;
+        remote_nonnull_domain      dom;
+        remote_string              channelName;
+        int                        state;
+        int                        reason;
+};
 struct remote_connect_get_all_domain_stats_ret {
         struct {
                 u_int              retStats_len;
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 184f64d..e085358 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -12637,6 +12637,20 @@ VIR_ENUM_IMPL(virshEventAgentLifecycleReason,
               N_("domain started"),
               N_("channel event"))
 
+VIR_ENUM_DECL(virshEventChannelLifecycleState)
+VIR_ENUM_IMPL(virshEventChannelLifecycleState,
+              VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST,
+              N_("unknown"),
+              N_("connected"),
+              N_("disconnected"))
+
+VIR_ENUM_DECL(virshEventChannelLifecycleReason)
+VIR_ENUM_IMPL(virshEventChannelLifecycleReason,
+              VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST,
+              N_("unknown"),
+              N_("domain started"),
+              N_("channel event"))
+
 #define UNKNOWNSTR(str) (str ? str : N_("unsupported value"))
 static void
 virshEventAgentLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -12656,6 +12670,25 @@ virshEventAgentLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
 }
 
 static void
+virshEventChannelLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                                virDomainPtr dom,
+                                const char *channelName,
+                                int state,
+                                int reason,
+                                void *opaque)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAsprintf(&buf, _("event 'channel-lifecycle' for domain %s: name: '%s', "
+                              "state: '%s' reason: '%s'\n"),
+                      virDomainGetName(dom),
+                      channelName,
+                      UNKNOWNSTR(virshEventChannelLifecycleStateTypeToString(state)),
+                      UNKNOWNSTR(virshEventChannelLifecycleReasonTypeToString(reason)));
+    virshEventPrint(opaque, &buf);
+}
+
+static void
 virshEventMigrationIterationPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
                                   virDomainPtr dom,
                                   int iteration,
@@ -12755,6 +12788,8 @@ static vshEventCallback vshEventCallbacks[] = {
       VIR_DOMAIN_EVENT_CALLBACK(virshEventJobCompletedPrint), },
     { "device-removal-failed",
       VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovalFailedPrint), },
+    { "channel-lifecycle",
+      VIR_DOMAIN_EVENT_CALLBACK(virshEventChannelLifecyclePrint), },
 };
 verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));
 
-- 
2.7.4 (Apple Git-66)




More information about the libvir-list mailing list