]> xenbits.xensource.com Git - libvirt.git/commitdiff
event: Add guest agent lifecycle event
authorPeter Krempa <pkrempa@redhat.com>
Wed, 19 Nov 2014 09:32:20 +0000 (10:32 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Mon, 24 Nov 2014 14:39:17 +0000 (15:39 +0100)
As qemu is now able to notify us about change of the channel state used
for communication with the guest agent we now can more precisely track
the state of the guest agent.

To allow notifying management apps this patch implements a new event
that will be triggered on changes of the guest agent state.

daemon/remote.c
include/libvirt/libvirt-domain.h
src/conf/domain_event.c
src/conf/domain_event.h
src/libvirt_private.syms
src/remote/remote_driver.c
src/remote/remote_protocol.x
src/remote_protocol-structs
tools/virsh-domain.c

index 1d7082ea84e6c1794f7605de7308968544e00ff7..18f493d97ff02d28f4bb7e9cbe6c3231099fc7ac 100644 (file)
@@ -1008,6 +1008,41 @@ remoteRelayDomainEventTunable(virConnectPtr conn,
 }
 
 
+static int
+remoteRelayDomainEventAgentLifecycle(virConnectPtr conn,
+                                     virDomainPtr dom,
+                                     int state,
+                                     int reason,
+                                     void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
+    remote_domain_event_callback_agent_lifecycle_msg data;
+
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+        return -1;
+
+    VIR_DEBUG("Relaying domain agent lifecycle event %s %d, callback %d, "
+              " state %d, reason %d",
+              dom->name, dom->id, callback->callbackID, state, reason);
+
+    /* build return data */
+    memset(&data, 0, sizeof(data));
+    data.callbackID = callback->callbackID;
+    make_nonnull_domain(&data.dom, dom);
+
+    data.state = state;
+    data.reason = reason;
+
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
+                                  REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE,
+                                  (xdrproc_t)xdr_remote_domain_event_callback_agent_lifecycle_msg,
+                                  &data);
+
+    return 0;
+}
+
+
 static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@@ -1027,6 +1062,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemoved),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventBlockJob2),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventTunable),
+    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventAgentLifecycle),
 };
 
 verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
index 1fac2a39383522d7353260cafc3d86db9dc9c784..298d7f41c521f709c2e99865f9ee609034aa28b5 100644 (file)
@@ -3332,6 +3332,46 @@ typedef void (*virConnectDomainEventTunableCallback)(virConnectPtr conn,
                                                      void *opaque);
 
 
+typedef enum {
+    VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_CONNECTED = 1, /* agent connected */
+    VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_DISCONNECTED = 2, /* agent disconnected */
+
+# ifdef VIR_ENUM_SENTINELS
+    VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_LAST
+# endif
+} virConnectDomainEventAgentLifecycleState;
+
+typedef enum {
+    VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_UNKNOWN = 0, /* unknown state change reason */
+    VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_DOMAIN_STARTED = 1, /* state changed due to domain start */
+    VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL = 2, /* channel state changed */
+
+# ifdef VIR_ENUM_SENTINELS
+    VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_LAST
+# endif
+} virConnectDomainEventAgentLifecycleReason;
+
+/**
+ * virConnectDomainEventAgentLifecycleCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @state: new state of the guest agent, one of virConnectDomainEventAgentLifecycleState
+ * @reason: reason for state change; one of virConnectDomainEventAgentLifecycleReason
+ * @opaque: application specified data
+ *
+ * This callback occurs when libvirt detects a change in the state of a guest
+ * agent.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventAgentLifecycleCallback)(virConnectPtr conn,
+                                                            virDomainPtr dom,
+                                                            int state,
+                                                            int reason,
+                                                            void *opaque);
+
+
 /**
  * VIR_DOMAIN_EVENT_CALLBACK:
  *
@@ -3367,6 +3407,7 @@ typedef enum {
     VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED = 15, /* virConnectDomainEventDeviceRemovedCallback */
     VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2 = 16,    /* virConnectDomainEventBlockJobCallback */
     VIR_DOMAIN_EVENT_ID_TUNABLE = 17,        /* virConnectDomainEventTunableCallback */
+    VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE = 18,/* virConnectDomainEventAgentLifecycleCallback */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_ID_LAST
index 3504b34abd44898096a0e936289f731db0df650b..d1042bfc925b3ff2876ba9abd90898ef0b1ac94c 100644 (file)
@@ -54,6 +54,7 @@ static virClassPtr virDomainEventDeviceRemovedClass;
 static virClassPtr virDomainEventPMClass;
 static virClassPtr virDomainQemuMonitorEventClass;
 static virClassPtr virDomainEventTunableClass;
+static virClassPtr virDomainEventAgentLifecycleClass;
 
 
 static void virDomainEventDispose(void *obj);
@@ -70,6 +71,7 @@ static void virDomainEventDeviceRemovedDispose(void *obj);
 static void virDomainEventPMDispose(void *obj);
 static void virDomainQemuMonitorEventDispose(void *obj);
 static void virDomainEventTunableDispose(void *obj);
+static void virDomainEventAgentLifecycleDispose(void *obj);
 
 static void
 virDomainEventDispatchDefaultFunc(virConnectPtr conn,
@@ -215,6 +217,15 @@ struct _virDomainEventTunable {
 typedef struct _virDomainEventTunable virDomainEventTunable;
 typedef virDomainEventTunable *virDomainEventTunablePtr;
 
+struct _virDomainEventAgentLifecycle {
+    virDomainEvent parent;
+
+    int state;
+    int reason;
+};
+typedef struct _virDomainEventAgentLifecycle virDomainEventAgentLifecycle;
+typedef virDomainEventAgentLifecycle *virDomainEventAgentLifecyclePtr;
+
 
 static int
 virDomainEventsOnceInit(void)
@@ -303,6 +314,12 @@ virDomainEventsOnceInit(void)
                       sizeof(virDomainEventTunable),
                       virDomainEventTunableDispose)))
         return -1;
+    if (!(virDomainEventAgentLifecycleClass =
+          virClassNew(virDomainEventClass,
+                      "virDomainEventAgentLifecycle",
+                      sizeof(virDomainEventAgentLifecycle),
+                      virDomainEventAgentLifecycleDispose)))
+        return -1;
     return 0;
 }
 
@@ -447,6 +464,13 @@ virDomainEventTunableDispose(void *obj)
     virTypedParamsFree(event->params, event->nparams);
 }
 
+static void
+virDomainEventAgentLifecycleDispose(void *obj)
+{
+    virDomainEventAgentLifecyclePtr event = obj;
+    VIR_DEBUG("obj=%p", event);
+};
+
 
 static void *
 virDomainEventNew(virClassPtr klass,
@@ -1202,6 +1226,49 @@ virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom,
                                           devAlias);
 }
 
+
+static virObjectEventPtr
+virDomainEventAgentLifecycleNew(int id,
+                                const char *name,
+                                const unsigned char *uuid,
+                                int state,
+                                int reason)
+{
+    virDomainEventAgentLifecyclePtr ev;
+
+    if (virDomainEventsInitialize() < 0)
+        return NULL;
+
+    if (!(ev = virDomainEventNew(virDomainEventAgentLifecycleClass,
+                                 VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE,
+                                 id, name, uuid)))
+        return NULL;
+
+    ev->state = state;
+    ev->reason = reason;
+
+    return (virObjectEventPtr)ev;
+}
+
+virObjectEventPtr
+virDomainEventAgentLifecycleNewFromObj(virDomainObjPtr obj,
+                                       int state,
+                                       int reason)
+{
+    return virDomainEventAgentLifecycleNew(obj->def->id, obj->def->name,
+                                           obj->def->uuid, state, reason);
+}
+
+virObjectEventPtr
+virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom,
+                                       int state,
+                                       int reason)
+{
+    return virDomainEventAgentLifecycleNew(dom->id, dom->name, dom->uuid,
+                                           state, reason);
+}
+
+
 /* This function consumes the params so caller don't have to care about
  * freeing it even if error occurs. The reason is to not have to do deep
  * copy of params.
@@ -1459,6 +1526,17 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
             goto cleanup;
         }
 
+    case VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE:
+        {
+            virDomainEventAgentLifecyclePtr agentLifecycleEvent;
+            agentLifecycleEvent = (virDomainEventAgentLifecyclePtr)event;
+            ((virConnectDomainEventAgentLifecycleCallback)cb)(conn, dom,
+                                                              agentLifecycleEvent->state,
+                                                              agentLifecycleEvent->reason,
+                                                              cbopaque);
+            goto cleanup;
+        }
+
     case VIR_DOMAIN_EVENT_ID_LAST:
         break;
     }
index dc0109cf67286d3406029552059fe06a9232ae9f..534ff9eb4acbe006ac83df35c64e807b6ae4941e 100644 (file)
@@ -193,6 +193,15 @@ virDomainEventTunableNewFromDom(virDomainPtr dom,
                                 virTypedParameterPtr params,
                                 int nparams);
 
+virObjectEventPtr
+virDomainEventAgentLifecycleNewFromObj(virDomainObjPtr obj,
+                                       int state,
+                                       int reason);
+
+virObjectEventPtr
+virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom,
+                                       int state,
+                                       int reason);
 
 int
 virDomainEventStateRegister(virConnectPtr conn,
index daf4dd74fa74ec62c46c3032cfbaacbbe0ca4e9e..f58be3ece1a51a59eb103d81507eff8fe026f59b 100644 (file)
@@ -437,6 +437,8 @@ virDomainXMLOptionNew;
 
 
 # conf/domain_event.h
+virDomainEventAgentLifecycleNewFromDom;
+virDomainEventAgentLifecycleNewFromObj;
 virDomainEventBalloonChangeNewFromDom;
 virDomainEventBalloonChangeNewFromObj;
 virDomainEventBlockJob2NewFromDom;
index 04e536062c2a4009345c4726046e34c5357145a1..88f8743bb109967658bea779be69b38433f9efeb 100644 (file)
@@ -334,6 +334,11 @@ remoteDomainBuildEventCallbackTunable(virNetClientProgramPtr prog,
                                       virNetClientPtr client,
                                       void *evdata, void *opaque);
 
+static void
+remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog,
+                                             virNetClientPtr client,
+                                             void *evdata, void *opaque);
+
 static void
 remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
                                  virNetClientPtr client ATTRIBUTE_UNUSED,
@@ -489,6 +494,10 @@ static virNetClientProgramEvent remoteEvents[] = {
       remoteDomainBuildEventCallbackTunable,
       sizeof(remote_domain_event_callback_tunable_msg),
       (xdrproc_t)xdr_remote_domain_event_callback_tunable_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE,
+      remoteDomainBuildEventCallbackAgentLifecycle,
+      sizeof(remote_domain_event_callback_agent_lifecycle_msg),
+      (xdrproc_t)xdr_remote_domain_event_callback_agent_lifecycle_msg },
 };
 
 
@@ -5482,6 +5491,28 @@ remoteDomainBuildEventCallbackTunable(virNetClientProgramPtr prog ATTRIBUTE_UNUS
 }
 
 
+static void
+remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                             virNetClientPtr client ATTRIBUTE_UNUSED,
+                                             void *evdata, void *opaque)
+{
+    virConnectPtr conn = opaque;
+    remote_domain_event_callback_agent_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 = virDomainEventAgentLifecycleNewFromDom(dom, msg->state,
+                                                   msg->reason);
+
+    virDomainFree(dom);
+
+    remoteEventQueue(priv, event, msg->callbackID);
+}
+
 static void
 remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
                                  virNetClientPtr client ATTRIBUTE_UNUSED,
index ebf453071a6959fa7e5cfc3fcb00e1308af0a759..85c95f5daaf2f70472e89be710dc3ac9908b4d22 100644 (file)
@@ -3108,6 +3108,14 @@ struct remote_connect_get_all_domain_stats_args {
     unsigned int flags;
 };
 
+struct remote_domain_event_callback_agent_lifecycle_msg {
+    int callbackID;
+    remote_nonnull_domain dom;
+
+    int state;
+    int reason;
+};
+
 struct remote_connect_get_all_domain_stats_ret {
     remote_domain_stats_record retStats<REMOTE_DOMAIN_LIST_MAX>;
 };
@@ -5506,5 +5514,11 @@ enum remote_procedure {
      * @generate: none
      * @acl: connect:write
      */
-    REMOTE_PROC_NODE_ALLOC_PAGES = 347
+    REMOTE_PROC_NODE_ALLOC_PAGES = 347,
+
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE = 348
 };
index 362baf99a77840f0e4e5d702035dbafb3b5f7584..9769b2a07370eb10de02af4020a3e30884f9dd18 100644 (file)
@@ -2573,6 +2573,12 @@ struct remote_connect_get_all_domain_stats_args {
         u_int                      stats;
         u_int                      flags;
 };
+struct remote_domain_event_callback_agent_lifecycle_msg {
+        int                        callbackID;
+        remote_nonnull_domain      dom;
+        int                        state;
+        int                        reason;
+};
 struct remote_connect_get_all_domain_stats_ret {
         struct {
                 u_int              retStats_len;
@@ -2927,4 +2933,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_BLOCK_COPY = 345,
         REMOTE_PROC_DOMAIN_EVENT_CALLBACK_TUNABLE = 346,
         REMOTE_PROC_NODE_ALLOC_PAGES = 347,
+        REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE = 348,
 };
index 0572275ffc39667463bbabb18ac05a3485a7ec5e..4f03956e30146e30dddea8db5fdd4c84ba2d8748 100644 (file)
@@ -11672,6 +11672,43 @@ vshEventTunablePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
         vshEventDone(data->ctl);
 }
 
+VIR_ENUM_DECL(vshEventAgentLifecycleState)
+VIR_ENUM_IMPL(vshEventAgentLifecycleState,
+              VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_STATE_LAST,
+              N_("unknown"),
+              N_("connected"),
+              N_("disconnected"))
+
+VIR_ENUM_DECL(vshEventAgentLifecycleReason)
+VIR_ENUM_IMPL(vshEventAgentLifecycleReason,
+              VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_LAST,
+              N_("unknown"),
+              N_("domain started"),
+              N_("channel event"))
+
+#define UNKNOWNSTR(str) (str ? str : N_("unsupported value"))
+static void
+vshEventAgentLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                            virDomainPtr dom,
+                            int state,
+                            int reason,
+                            void *opaque)
+{
+    vshDomEventData *data = opaque;
+
+    if (!data->loop && *data->count)
+        return;
+    vshPrint(data->ctl,
+             _("event 'agent-lifecycle' for domain %s: state: '%s' reason: '%s'\n"),
+             virDomainGetName(dom),
+             UNKNOWNSTR(vshEventAgentLifecycleStateTypeToString(state)),
+             UNKNOWNSTR(vshEventAgentLifecycleReasonTypeToString(reason)));
+
+    (*data->count)++;
+    if (!data->loop)
+        vshEventDone(data->ctl);
+}
+
 static vshEventCallback vshEventCallbacks[] = {
     { "lifecycle",
       VIR_DOMAIN_EVENT_CALLBACK(vshEventLifecyclePrint), },
@@ -11707,6 +11744,8 @@ static vshEventCallback vshEventCallbacks[] = {
       VIR_DOMAIN_EVENT_CALLBACK(vshEventBlockJobPrint), },
     { "tunable",
       VIR_DOMAIN_EVENT_CALLBACK(vshEventTunablePrint), },
+    { "agent-lifecycle",
+      VIR_DOMAIN_EVENT_CALLBACK(vshEventAgentLifecyclePrint), },
 };
 verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));