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 | 44 ++++++++++++++++++
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, 347 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..9a5c664 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3965,6 +3965,49 @@ 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 =
+ VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_DOMAIN_STARTED, /* state changed
due to domain start */
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL =
+ VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL, /* 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 hypervisor must support serial notification, and this is
+ * currently limited to modern versions of qemu.
+ *
+ * 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 +4049,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..eb783cb 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);
@@ -574,6 +579,10 @@ static virNetClientProgramEvent remoteEvents[] = {
remoteNodeDeviceBuildEventUpdate,
sizeof(remote_node_device_event_update_msg),
(xdrproc_t)xdr_remote_node_device_event_update_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 },
};
static void
@@ -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)