]> xenbits.xensource.com Git - libvirt.git/commitdiff
Introduce job completed event
authorJiri Denemark <jdenemar@redhat.com>
Wed, 17 Feb 2016 20:20:11 +0000 (21:20 +0100)
committerJiri Denemark <jdenemar@redhat.com>
Tue, 8 Mar 2016 15:26:00 +0000 (16:26 +0100)
The VIR_DOMAIN_EVENT_ID_JOB_COMPLETED event will be triggered once a job
(such as migration) finishes and it will contain statistics for the job
as one would get by calling virDomainGetJobStats. Thanks to this event
it is now possible to get statistics of a completed migration of a
transient domain on the source host.

Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
daemon/remote.c
include/libvirt/libvirt-domain.h
src/conf/domain_event.c
src/conf/domain_event.h
src/libvirt-domain.c
src/libvirt_private.syms
src/remote/remote_driver.c
src/remote/remote_protocol.x
src/remote_protocol-structs
tools/virsh-domain.c

index 17783fa652978fcec8a90d35fbb967a09f967581..f5ca2acc98e2d3bd024e20009d05ae05ae798f7a 100644 (file)
@@ -1099,6 +1099,43 @@ remoteRelayDomainEventMigrationIteration(virConnectPtr conn,
 }
 
 
+static int
+remoteRelayDomainEventJobCompleted(virConnectPtr conn,
+                                   virDomainPtr dom,
+                                   virTypedParameterPtr params,
+                                   int nparams,
+                                   void *opaque)
+{
+    daemonClientEventCallbackPtr callback = opaque;
+    remote_domain_event_callback_job_completed_msg data;
+
+    if (callback->callbackID < 0 ||
+        !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+        return -1;
+
+    VIR_DEBUG("Relaying domain migration completed event %s %d, "
+              "callback %d, params %p %d",
+              dom->name, dom->id, callback->callbackID, params, nparams);
+
+    /* build return data */
+    memset(&data, 0, sizeof(data));
+    data.callbackID = callback->callbackID;
+    make_nonnull_domain(&data.dom, dom);
+
+    if (virTypedParamsSerialize(params, nparams,
+                                (virTypedParameterRemotePtr *) &data.params.params_val,
+                                &data.params.params_len,
+                                VIR_TYPED_PARAM_STRING_OKAY) < 0)
+        return -1;
+
+    remoteDispatchObjectEventSend(callback->client, remoteProgram,
+                                  REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED,
+                                  (xdrproc_t)xdr_remote_domain_event_callback_job_completed_msg,
+                                  &data);
+    return 0;
+}
+
+
 static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventLifecycle),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventReboot),
@@ -1121,6 +1158,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventAgentLifecycle),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceAdded),
     VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration),
+    VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventJobCompleted),
 };
 
 verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
index 79c25df9e59df39d6539513518c01169bc228db3..8ea3df6138fba61e05dfeb1e9aad0614eed38634 100644 (file)
@@ -3320,6 +3320,29 @@ typedef void (*virConnectDomainEventMigrationIterationCallback)(virConnectPtr co
                                                                 int iteration,
                                                                 void *opaque);
 
+/**
+ * virConnectDomainEventJobCompletedCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @params: job statistics stored as an array of virTypedParameter
+ * @nparams: size of the params array
+ * @opaque: application specific data
+ *
+ * This callback occurs when a job (such as migration) running on the domain
+ * is completed. The params array will contain statistics of the just completed
+ * job as virDomainGetJobStats would return. The callback must not free @params
+ * (the array will be freed once the callback finishes).
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_JOB_COMPLETED with
+ * virConnectDomainEventRegisterAny().
+ */
+typedef void (*virConnectDomainEventJobCompletedCallback)(virConnectPtr conn,
+                                                          virDomainPtr dom,
+                                                          virTypedParameterPtr params,
+                                                          int nparams,
+                                                          void *opaque);
+
 /**
  * VIR_DOMAIN_TUNABLE_CPU_VCPUPIN:
  *
@@ -3620,6 +3643,7 @@ typedef enum {
     VIR_DOMAIN_EVENT_ID_AGENT_LIFECYCLE = 18,/* virConnectDomainEventAgentLifecycleCallback */
     VIR_DOMAIN_EVENT_ID_DEVICE_ADDED = 19,   /* virConnectDomainEventDeviceAddedCallback */
     VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION = 20, /* virConnectDomainEventMigrationIterationCallback */
+    VIR_DOMAIN_EVENT_ID_JOB_COMPLETED = 21,  /* virConnectDomainEventJobCompletedCallback */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_ID_LAST
index 5cb3ccd5b4f3de25ca35d111335a98d7a4c8ff6a..a9107e5f5ed48333482a0129b80b2d7fdc2abf09 100644 (file)
@@ -57,7 +57,7 @@ static virClassPtr virDomainEventTunableClass;
 static virClassPtr virDomainEventAgentLifecycleClass;
 static virClassPtr virDomainEventDeviceAddedClass;
 static virClassPtr virDomainEventMigrationIterationClass;
-
+static virClassPtr virDomainEventJobCompletedClass;
 
 static void virDomainEventDispose(void *obj);
 static void virDomainEventLifecycleDispose(void *obj);
@@ -76,6 +76,7 @@ static void virDomainEventTunableDispose(void *obj);
 static void virDomainEventAgentLifecycleDispose(void *obj);
 static void virDomainEventDeviceAddedDispose(void *obj);
 static void virDomainEventMigrationIterationDispose(void *obj);
+static void virDomainEventJobCompletedDispose(void *obj);
 
 static void
 virDomainEventDispatchDefaultFunc(virConnectPtr conn,
@@ -246,6 +247,14 @@ struct _virDomainEventMigrationIteration {
 typedef struct _virDomainEventMigrationIteration virDomainEventMigrationIteration;
 typedef virDomainEventMigrationIteration *virDomainEventMigrationIterationPtr;
 
+struct _virDomainEventJobCompleted {
+    virDomainEvent parent;
+
+    virTypedParameterPtr params;
+    int nparams;
+};
+typedef struct _virDomainEventJobCompleted virDomainEventJobCompleted;
+typedef virDomainEventJobCompleted *virDomainEventJobCompletedPtr;
 
 static int
 virDomainEventsOnceInit(void)
@@ -352,6 +361,12 @@ virDomainEventsOnceInit(void)
                       sizeof(virDomainEventMigrationIteration),
                       virDomainEventMigrationIterationDispose)))
         return -1;
+    if (!(virDomainEventJobCompletedClass =
+          virClassNew(virDomainEventClass,
+                      "virDomainEventJobCompleted",
+                      sizeof(virDomainEventJobCompleted),
+                      virDomainEventJobCompletedDispose)))
+        return -1;
     return 0;
 }
 
@@ -519,6 +534,15 @@ virDomainEventMigrationIterationDispose(void *obj)
     VIR_DEBUG("obj=%p", event);
 };
 
+static void
+virDomainEventJobCompletedDispose(void *obj)
+{
+    virDomainEventJobCompletedPtr event = obj;
+    VIR_DEBUG("obj=%p", event);
+
+    virTypedParamsFree(event->params, event->nparams);
+}
+
 
 static void *
 virDomainEventNew(virClassPtr klass,
@@ -1394,6 +1418,53 @@ virDomainEventMigrationIterationNewFromDom(virDomainPtr dom,
                                                iteration);
 }
 
+/* This function consumes @params, the caller must not free it.
+ */
+static virObjectEventPtr
+virDomainEventJobCompletedNew(int id,
+                              const char *name,
+                              const unsigned char *uuid,
+                              virTypedParameterPtr params,
+                              int nparams)
+{
+    virDomainEventJobCompletedPtr ev;
+
+    if (virDomainEventsInitialize() < 0)
+        goto error;
+
+    if (!(ev = virDomainEventNew(virDomainEventJobCompletedClass,
+                                 VIR_DOMAIN_EVENT_ID_JOB_COMPLETED,
+                                 id, name, uuid)))
+        goto error;
+
+    ev->params = params;
+    ev->nparams = nparams;
+
+    return (virObjectEventPtr) ev;
+
+ error:
+    virTypedParamsFree(params, nparams);
+    return NULL;
+}
+
+virObjectEventPtr
+virDomainEventJobCompletedNewFromObj(virDomainObjPtr obj,
+                                     virTypedParameterPtr params,
+                                     int nparams)
+{
+    return virDomainEventJobCompletedNew(obj->def->id, obj->def->name,
+                                         obj->def->uuid, params, nparams);
+}
+
+virObjectEventPtr
+virDomainEventJobCompletedNewFromDom(virDomainPtr dom,
+                                     virTypedParameterPtr params,
+                                     int nparams)
+{
+    return virDomainEventJobCompletedNew(dom->id, dom->name, dom->uuid,
+                                         params, nparams);
+}
+
 
 /* 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
@@ -1685,6 +1756,18 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
             goto cleanup;
         }
 
+    case VIR_DOMAIN_EVENT_ID_JOB_COMPLETED:
+        {
+            virDomainEventJobCompletedPtr ev;
+
+            ev = (virDomainEventJobCompletedPtr) event;
+            ((virConnectDomainEventJobCompletedCallback) cb)(conn, dom,
+                                                             ev->params,
+                                                             ev->nparams,
+                                                             cbopaque);
+            goto cleanup;
+        }
+
     case VIR_DOMAIN_EVENT_ID_LAST:
         break;
     }
index b7cddb5a509b07a7433b1033ddbc983f3d027c18..3eb13c818796754be3f6541f4938e906ff8e4202 100644 (file)
@@ -217,6 +217,16 @@ virObjectEventPtr
 virDomainEventMigrationIterationNewFromDom(virDomainPtr dom,
                                            int iteration);
 
+virObjectEventPtr
+virDomainEventJobCompletedNewFromObj(virDomainObjPtr obj,
+                                     virTypedParameterPtr params,
+                                     int nparams);
+
+virObjectEventPtr
+virDomainEventJobCompletedNewFromDom(virDomainPtr dom,
+                                     virTypedParameterPtr params,
+                                     int nparams);
+
 int
 virDomainEventStateRegister(virConnectPtr conn,
                             virObjectEventStatePtr state,
index 9491845758570c879e28b18c4b4133ec76a48e90..ca32dc124bde28ad2a16f8e7bf7ddbea6f1085a2 100644 (file)
@@ -8873,7 +8873,9 @@ virDomainGetJobInfo(virDomainPtr domain, virDomainJobInfoPtr info)
  * when libvirtd is restarted. Note that time information returned for
  * completed migrations may be completely irrelevant unless both source and
  * destination hosts have synchronized time (i.e., NTP daemon is running on
- * both of them).
+ * both of them). The statistics of a completed job can also be obtained by
+ * listening to a VIR_DOMAIN_EVENT_ID_JOB_COMPLETED event (on the source host
+ * in case of a migration job).
  *
  * Returns 0 in case of success and -1 in case of failure.
  */
index 3a1b9e1fe1b15c2e322413a6eee24acb0ac0ea0e..c8a2f0a9b15edd65db971dbf02904fe5c4e53c5d 100644 (file)
@@ -508,6 +508,8 @@ virDomainEventIOErrorNewFromDom;
 virDomainEventIOErrorNewFromObj;
 virDomainEventIOErrorReasonNewFromDom;
 virDomainEventIOErrorReasonNewFromObj;
+virDomainEventJobCompletedNewFromDom;
+virDomainEventJobCompletedNewFromObj;
 virDomainEventLifecycleNew;
 virDomainEventLifecycleNewFromDef;
 virDomainEventLifecycleNewFromDom;
index d84d2c1cda97a8e96a37d30e4098dc38c764f977..2daa50786d2237ed0e7c0aa322f48068816331cc 100644 (file)
@@ -343,6 +343,11 @@ remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog,
                                                  virNetClientPtr client,
                                                  void *evdata, void *opaque);
 
+static void
+remoteDomainBuildEventCallbackJobCompleted(virNetClientProgramPtr prog,
+                                           virNetClientPtr client,
+                                           void *evdata, void *opaque);
+
 static void
 remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
                                  virNetClientPtr client ATTRIBUTE_UNUSED,
@@ -519,6 +524,10 @@ static virNetClientProgramEvent remoteEvents[] = {
       remoteConnectNotifyEventConnectionClosed,
       sizeof(remote_connect_event_connection_closed_msg),
       (xdrproc_t)xdr_remote_connect_event_connection_closed_msg },
+    { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED,
+      remoteDomainBuildEventCallbackJobCompleted,
+      sizeof(remote_domain_event_callback_job_completed_msg),
+      (xdrproc_t)xdr_remote_domain_event_callback_job_completed_msg },
 };
 
 static void
@@ -5383,6 +5392,39 @@ remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog ATT
 }
 
 
+static void
+remoteDomainBuildEventCallbackJobCompleted(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+                                           virNetClientPtr client ATTRIBUTE_UNUSED,
+                                           void *evdata,
+                                           void *opaque)
+{
+    virConnectPtr conn = opaque;
+    remote_domain_event_callback_job_completed_msg *msg = evdata;
+    struct private_data *priv = conn->privateData;
+    virDomainPtr dom;
+    virObjectEventPtr event = NULL;
+    virTypedParameterPtr params = NULL;
+    int nparams = 0;
+
+    if (virTypedParamsDeserialize((virTypedParameterRemotePtr) msg->params.params_val,
+                                  msg->params.params_len,
+                                  REMOTE_DOMAIN_JOB_STATS_MAX,
+                                  &params, &nparams) < 0)
+        return;
+
+    if (!(dom = get_nonnull_domain(conn, msg->dom))) {
+        virTypedParamsFree(params, nparams);
+        return;
+    }
+
+    event = virDomainEventJobCompletedNewFromDom(dom, params, nparams);
+
+    virObjectUnref(dom);
+
+    remoteEventQueue(priv, event, msg->callbackID);
+}
+
+
 static void
 remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
                                  virNetClientPtr client ATTRIBUTE_UNUSED,
index c6dd51e57c317ba9917bba12c197cab392c04e63..952686c5a61b00be2aea64ffaaa1ec5c8d7afb41 100644 (file)
@@ -3232,6 +3232,12 @@ struct remote_domain_event_callback_migration_iteration_msg {
     int iteration;
 };
 
+struct remote_domain_event_callback_job_completed_msg {
+    int callbackID;
+    remote_nonnull_domain dom;
+    remote_typed_param params<REMOTE_DOMAIN_JOB_STATS_MAX>;
+};
+
 /*----- Protocol. -----*/
 
 /* Define the program number, protocol version and procedure numbers here. */
@@ -5728,5 +5734,11 @@ enum remote_procedure {
      * @generate: none
      * @acl: none
      */
-    REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED = 362
+    REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED = 362,
+
+    /**
+     * @generate: both
+     * @acl: none
+     */
+    REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED = 363
 };
index 6c1cf5d16ee28711f403d1e61228f784adaddfcb..070338c40053c746347ad99a28c501dd16c96c80 100644 (file)
@@ -2700,6 +2700,14 @@ struct remote_domain_event_callback_migration_iteration_msg {
         remote_nonnull_domain      dom;
         int                        iteration;
 };
+struct remote_domain_event_callback_job_completed_msg {
+        int                        callbackID;
+        remote_nonnull_domain      dom;
+        struct {
+                u_int              params_len;
+                remote_typed_param * params_val;
+        } params;
+};
 enum remote_procedure {
         REMOTE_PROC_CONNECT_OPEN = 1,
         REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -3063,4 +3071,5 @@ enum remote_procedure {
         REMOTE_PROC_CONNECT_CLOSE_CALLBACK_REGISTER = 360,
         REMOTE_PROC_CONNECT_CLOSE_CALLBACK_UNREGISTER = 361,
         REMOTE_PROC_CONNECT_EVENT_CONNECTION_CLOSED = 362,
+        REMOTE_PROC_DOMAIN_EVENT_CALLBACK_JOB_COMPLETED = 363,
 };
index 979f115e84ec91a19485b3529f555340a619756d..f66faca14fc6a0753a302fc49d4e6d66d2cba353 100644 (file)
@@ -11975,6 +11975,29 @@ virshEventMigrationIterationPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
     virshEventPrint(opaque, &buf);
 }
 
+static void
+virshEventJobCompletedPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+                            virDomainPtr dom,
+                            virTypedParameterPtr params,
+                            int nparams,
+                            void *opaque)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    size_t i;
+    char *value;
+
+    virBufferAsprintf(&buf, _("event 'job-completed' for domain %s:\n"),
+                      virDomainGetName(dom));
+    for (i = 0; i < nparams; i++) {
+        value = virTypedParameterToString(&params[i]);
+        if (value) {
+            virBufferAsprintf(&buf, "\t%s: %s\n", params[i].field, value);
+            VIR_FREE(value);
+        }
+    }
+    virshEventPrint(opaque, &buf);
+}
+
 static vshEventCallback vshEventCallbacks[] = {
     { "lifecycle",
       VIR_DOMAIN_EVENT_CALLBACK(virshEventLifecyclePrint), },
@@ -12016,6 +12039,8 @@ static vshEventCallback vshEventCallbacks[] = {
       VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceAddedPrint), },
     { "migration-iteration",
       VIR_DOMAIN_EVENT_CALLBACK(virshEventMigrationIterationPrint), },
+    { "job-completed",
+      VIR_DOMAIN_EVENT_CALLBACK(virshEventJobCompletedPrint), },
 };
 verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));