[libvirt] PATCH: Add domain event "detail" information

Daniel P. Berrange berrange at redhat.com
Fri Nov 14 17:44:29 UTC 2008


As per our earlier discussion today, this patch expands the callback for
domain events so that it also gets a event type specific 'detail' field.
This is also kept as an int, and we define enumerations for the possible
values associated with each type. If a event type has no detail, 0 is
passed.

The RESTORED and SAVED event types disappear in this patch and just become
another piece of 'detail' to the STOPPED and STARTED events. I have also
renamed ADDED & REMOVED to DEFINED and UNDEFINED to match terminology we
have elsewhere & because the names were confusing me

Easiest to just look at the final set:

typedef enum {
      VIR_DOMAIN_EVENT_DEFINED = 0,
      VIR_DOMAIN_EVENT_UNDEFINED = 1,
      VIR_DOMAIN_EVENT_STARTED = 2,
      VIR_DOMAIN_EVENT_SUSPENDED = 3,
      VIR_DOMAIN_EVENT_RESUMED = 4,
      VIR_DOMAIN_EVENT_STOPPED = 5,
} virDomainEventType;

typedef enum {
    VIR_DOMAIN_EVENT_STARTED_BOOTED = 0,   /* Normal startup from boot */
    VIR_DOMAIN_EVENT_STARTED_MIGRATED = 1, /* Incoming migration from another host */
    VIR_DOMAIN_EVENT_STARTED_RESTORED = 2, /* Restored from a state file */
} virDomainEventStartedDetailType;

typedef enum {
    VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN = 0,  /* Normal shutdown */
    VIR_DOMAIN_EVENT_STOPPED_DESTROYED = 1, /* Forced poweroff from host */
    VIR_DOMAIN_EVENT_STOPPED_CRASHED = 2,   /* Guest crashed */
    VIR_DOMAIN_EVENT_STOPPED_MIGRATED = 3,  /* Migrated off to another host */
    VIR_DOMAIN_EVENT_STOPPED_SAVED = 4,     /* Saved to a state file */
    VIR_DOMAIN_EVENT_STOPPED_FAILED = 5,    /* Host emulator/mgmt failed */
} virDomainEventStoppedDetailType;

typedef enum {
    VIR_DOMAIN_EVENT_DEFINED_ADDED = 0,     /* Newly created config file */
    VIR_DOMAIN_EVENT_DEFINED_UPDATED = 1,   /* Changed config file */
} virDomainEventDefinedDetailType;

I don't make use of 'CRASHED' in QEMU driver yet. It might be useful in
Xen though - when a PV guest crashes, Xen stops the domain running, but
leaves it there in a shutoff state, but marked as crashed.

Now using the C event-test program you can see the effects:

  myDomainEventCallback1 EVENT: Domain F9x86_64(2) Started Booted
  myDomainEventCallback2 EVENT: Domain F9x86_64(2) Started Booted
  myDomainEventCallback1 EVENT: Domain F9x86_64(-1) Stopped Destroyed
  myDomainEventCallback2 EVENT: Domain F9x86_64(-1) Stopped Destroyed
  myDomainEventCallback1 EVENT: Domain F9x86_64(3) Started Booted
  myDomainEventCallback2 EVENT: Domain F9x86_64(3) Started Booted
  myDomainEventCallback1 EVENT: Domain F9x86_64(3) Suspended 
  myDomainEventCallback2 EVENT: Domain F9x86_64(3) Suspended 
  myDomainEventCallback1 EVENT: Domain F9x86_64(3) Resumed 
  myDomainEventCallback2 EVENT: Domain F9x86_64(3) Resumed 
  myDomainEventCallback1 EVENT: Domain F9x86_64(-1) Stopped Shutdown
  myDomainEventCallback2 EVENT: Domain F9x86_64(-1) Stopped Shutdown

Of the following sequence of actions

  virsh start F9x86_64
  virsh destroy F9x86_64
  virsh start F9x86_64
  virsh suspend F9x86_64
  virsh resume F9x86_64
  virsh shutdown F9x86_64

For the last 'shutdown' operation, you'll see the same if you just run
a graceful shutdown inside the guest itself.

NB, I've not tested saved/restored because my install of KVM is not new
enough to support that correctly, but I expect it to work without trouble.
Likewise for migration.

A word about migration...

 - The destination host first gets a STARTED event, with detail MIGRATED
   when it starts running
 - The source host then gets a STOPPED event with detail MIGRATED when
   it completes
 - The destination host then gets a RESUMED event, on success, and
   a STOPPED event with detail FAILED if migration aborts.

Daniel

 examples/domain-events/events-c/event-test.c       |   78 +++++++++++++++----
 examples/domain-events/events-python/event-test.py |    8 +-
 include/libvirt/libvirt.h                          |   29 ++++++-
 include/libvirt/libvirt.h.in                       |   29 ++++++-
 python/libvir.c                                    |    6 +
 qemud/qemud.h                                      |    1 
 qemud/remote.c                                     |   22 +++--
 qemud/remote_protocol.c                            |    2 
 qemud/remote_protocol.h                            |    1 
 qemud/remote_protocol.x                            |    1 
 src/domain_event.c                                 |    4 -
 src/domain_event.h                                 |    6 +
 src/qemu_driver.c                                  |   82 +++++++++++++++------
 src/remote_internal.c                              |   29 ++++---
 18 files changed, 366 insertions(+), 118 deletions(-)



diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c
--- a/examples/domain-events/events-c/event-test.c
+++ b/examples/domain-events/events-c/event-test.c
@@ -35,9 +35,9 @@ void *t_opaque = NULL;
 /* Prototypes */
 const char *eventToString(int event);
 int myDomainEventCallback1 (virConnectPtr conn, virDomainPtr dom,
-                            int event, void *opaque);
+                            int event, int detail, void *opaque);
 int myDomainEventCallback2 (virConnectPtr conn, virDomainPtr dom,
-                            int event, void *opaque);
+                            int event, int detail, void *opaque);
 int myEventAddHandleFunc  (int fd, int event,
                            virEventHandleCallback cb, void *opaque);
 void myEventUpdateHandleFunc(int fd, int event);
@@ -58,11 +58,11 @@ const char *eventToString(int event) {
 const char *eventToString(int event) {
     const char *ret = NULL;
     switch(event) {
-        case VIR_DOMAIN_EVENT_ADDED:
-            ret ="Added";
+        case VIR_DOMAIN_EVENT_DEFINED:
+            ret ="Defined";
             break;
-        case VIR_DOMAIN_EVENT_REMOVED:
-            ret ="Removed";
+        case VIR_DOMAIN_EVENT_UNDEFINED:
+            ret ="Undefined";
             break;
         case VIR_DOMAIN_EVENT_STARTED:
             ret ="Started";
@@ -76,14 +76,56 @@ const char *eventToString(int event) {
         case VIR_DOMAIN_EVENT_STOPPED:
             ret ="Stopped";
             break;
-        case VIR_DOMAIN_EVENT_SAVED:
-            ret ="Saved";
-            break;
-        case VIR_DOMAIN_EVENT_RESTORED:
-            ret ="Restored";
-            break;
         default:
             ret ="Unknown Event";
+    }
+    return ret;
+}
+
+static const char *eventDetailToString(int event, int detail) {
+    const char *ret = "";
+    switch(event) {
+        case VIR_DOMAIN_EVENT_DEFINED:
+            if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED)
+                ret = "Added";
+            else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED)
+                ret = "Updated";
+            break;
+        case VIR_DOMAIN_EVENT_STARTED:
+            switch (detail) {
+            case VIR_DOMAIN_EVENT_STARTED_BOOTED:
+                ret = "Booted";
+                break;
+            case VIR_DOMAIN_EVENT_STARTED_MIGRATED:
+                ret = "Migrated";
+                break;
+            case VIR_DOMAIN_EVENT_STARTED_RESTORED:
+                ret = "Restored";
+                break;
+            }
+            break;
+        case VIR_DOMAIN_EVENT_STOPPED:
+            switch (detail) {
+            case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN:
+                ret = "Shutdown";
+                break;
+            case VIR_DOMAIN_EVENT_STOPPED_DESTROYED:
+                ret = "Destroyed";
+                break;
+            case VIR_DOMAIN_EVENT_STOPPED_CRASHED:
+                ret = "Crashed";
+                break;
+            case VIR_DOMAIN_EVENT_STOPPED_MIGRATED:
+                ret = "Migrated";
+                break;
+            case VIR_DOMAIN_EVENT_STOPPED_SAVED:
+                ret = "Failed";
+                break;
+            case VIR_DOMAIN_EVENT_STOPPED_FAILED:
+                ret = "Failed";
+                break;
+            }
+            break;
     }
     return ret;
 }
@@ -91,20 +133,24 @@ int myDomainEventCallback1 (virConnectPt
 int myDomainEventCallback1 (virConnectPtr conn ATTRIBUTE_UNUSED,
                             virDomainPtr dom,
                             int event,
+                            int detail,
                             void *opaque ATTRIBUTE_UNUSED)
 {
-    printf("%s EVENT: Domain %s(%d) %s\n", __FUNCTION__, virDomainGetName(dom),
-           virDomainGetID(dom), eventToString(event));
+    printf("%s EVENT: Domain %s(%d) %s %s\n", __FUNCTION__, virDomainGetName(dom),
+           virDomainGetID(dom), eventToString(event),
+           eventDetailToString(event, detail));
     return 0;
 }
 
 int myDomainEventCallback2 (virConnectPtr conn ATTRIBUTE_UNUSED,
                             virDomainPtr dom,
                             int event,
+                            int detail,
                             void *opaque ATTRIBUTE_UNUSED)
 {
-    printf("%s EVENT: Domain %s(%d) %s\n", __FUNCTION__, virDomainGetName(dom),
-           virDomainGetID(dom), eventToString(event));
+    printf("%s EVENT: Domain %s(%d) %s %s\n", __FUNCTION__, virDomainGetName(dom),
+           virDomainGetID(dom), eventToString(event),
+           eventDetailToString(event, detail));
     return 0;
 }
 
diff --git a/examples/domain-events/events-python/event-test.py b/examples/domain-events/events-python/event-test.py
--- a/examples/domain-events/events-python/event-test.py
+++ b/examples/domain-events/events-python/event-test.py
@@ -32,11 +32,11 @@ def eventToString(event):
                      "Restored" );
     return eventStrings[event];
 
-def myDomainEventCallback1 (conn, dom, event, opaque):
-    print "myDomainEventCallback1 EVENT: Domain %s(%s) %s" % (dom.name(), dom.ID(), eventToString(event))
+def myDomainEventCallback1 (conn, dom, event, detail, opaque):
+    print "myDomainEventCallback1 EVENT: Domain %s(%s) %s %d" % (dom.name(), dom.ID(), eventToString(event), detail)
 
-def myDomainEventCallback2 (conn, dom, event, opaque):
-    print "myDomainEventCallback2 EVENT: Domain %s(%s) %s" % (dom.name(), dom.ID(), eventToString(event))
+def myDomainEventCallback2 (conn, dom, event, detail, opaque):
+    print "myDomainEventCallback2 EVENT: Domain %s(%s) %s %d" % (dom.name(), dom.ID(), eventToString(event), detail)
 
 #####################################################
 # EventImpl Functions
diff --git a/include/libvirt/libvirt.h b/include/libvirt/libvirt.h
--- a/include/libvirt/libvirt.h
+++ b/include/libvirt/libvirt.h
@@ -1004,21 +1004,41 @@ virDomainPtr            virDomainCreateL
  * a virDomainEventType is emitted during domain lifecycle events
  */
 typedef enum {
-      VIR_DOMAIN_EVENT_ADDED = 0,
-      VIR_DOMAIN_EVENT_REMOVED = 1,
+      VIR_DOMAIN_EVENT_DEFINED = 0,
+      VIR_DOMAIN_EVENT_UNDEFINED = 1,
       VIR_DOMAIN_EVENT_STARTED = 2,
       VIR_DOMAIN_EVENT_SUSPENDED = 3,
       VIR_DOMAIN_EVENT_RESUMED = 4,
       VIR_DOMAIN_EVENT_STOPPED = 5,
-      VIR_DOMAIN_EVENT_SAVED = 6,
-      VIR_DOMAIN_EVENT_RESTORED = 7,
 } virDomainEventType;
+
+typedef enum {
+    VIR_DOMAIN_EVENT_STARTED_BOOTED = 0,   /* Normal startup from boot */
+    VIR_DOMAIN_EVENT_STARTED_MIGRATED = 1, /* Incoming migration from another host */
+    VIR_DOMAIN_EVENT_STARTED_RESTORED = 2, /* Restored from a state file */
+} virDomainEventStartedDetailType;
+
+typedef enum {
+    VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN = 0,  /* Normal shutdown */
+    VIR_DOMAIN_EVENT_STOPPED_DESTROYED = 1, /* Forced poweroff from host */
+    VIR_DOMAIN_EVENT_STOPPED_CRASHED = 2,   /* Guest crashed */
+    VIR_DOMAIN_EVENT_STOPPED_MIGRATED = 3,  /* Migrated off to another host */
+    VIR_DOMAIN_EVENT_STOPPED_SAVED = 4,     /* Saved to a state file */
+    VIR_DOMAIN_EVENT_STOPPED_FAILED = 5,    /* Host emulator/mgmt failed */
+} virDomainEventStoppedDetailType;
+
+typedef enum {
+    VIR_DOMAIN_EVENT_DEFINED_ADDED = 0,     /* Newly created config file */
+    VIR_DOMAIN_EVENT_DEFINED_UPDATED = 1,   /* Changed config file */
+} virDomainEventDefinedDetailType;
+
 
 /**
  * virConnectDomainEventCallback:
  * @conn: virConnect connection
  * @dom: The domain on which the event occured
  * @event: The specfic virDomainEventType which occured
+ * @detail: event specific detail information
  * @opaque: opaque user data
  *
  * A callback function to be registered, and called when a domain event occurs
@@ -1026,6 +1046,7 @@ typedef int (*virConnectDomainEventCallb
 typedef int (*virConnectDomainEventCallback)(virConnectPtr conn,
                                              virDomainPtr dom,
                                              int event,
+                                             int detail,
                                              void *opaque);
 
 int virConnectDomainEventRegister(virConnectPtr conn,
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1004,21 +1004,41 @@ virDomainPtr            virDomainCreateL
  * a virDomainEventType is emitted during domain lifecycle events
  */
 typedef enum {
-      VIR_DOMAIN_EVENT_ADDED = 0,
-      VIR_DOMAIN_EVENT_REMOVED = 1,
+      VIR_DOMAIN_EVENT_DEFINED = 0,
+      VIR_DOMAIN_EVENT_UNDEFINED = 1,
       VIR_DOMAIN_EVENT_STARTED = 2,
       VIR_DOMAIN_EVENT_SUSPENDED = 3,
       VIR_DOMAIN_EVENT_RESUMED = 4,
       VIR_DOMAIN_EVENT_STOPPED = 5,
-      VIR_DOMAIN_EVENT_SAVED = 6,
-      VIR_DOMAIN_EVENT_RESTORED = 7,
 } virDomainEventType;
+
+typedef enum {
+    VIR_DOMAIN_EVENT_STARTED_BOOTED = 0,   /* Normal startup from boot */
+    VIR_DOMAIN_EVENT_STARTED_MIGRATED = 1, /* Incoming migration from another host */
+    VIR_DOMAIN_EVENT_STARTED_RESTORED = 2, /* Restored from a state file */
+} virDomainEventStartedDetailType;
+
+typedef enum {
+    VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN = 0,  /* Normal shutdown */
+    VIR_DOMAIN_EVENT_STOPPED_DESTROYED = 1, /* Forced poweroff from host */
+    VIR_DOMAIN_EVENT_STOPPED_CRASHED = 2,   /* Guest crashed */
+    VIR_DOMAIN_EVENT_STOPPED_MIGRATED = 3,  /* Migrated off to another host */
+    VIR_DOMAIN_EVENT_STOPPED_SAVED = 4,     /* Saved to a state file */
+    VIR_DOMAIN_EVENT_STOPPED_FAILED = 5,    /* Host emulator/mgmt failed */
+} virDomainEventStoppedDetailType;
+
+typedef enum {
+    VIR_DOMAIN_EVENT_DEFINED_ADDED = 0,     /* Newly created config file */
+    VIR_DOMAIN_EVENT_DEFINED_UPDATED = 1,   /* Changed config file */
+} virDomainEventDefinedDetailType;
+
 
 /**
  * virConnectDomainEventCallback:
  * @conn: virConnect connection
  * @dom: The domain on which the event occured
  * @event: The specfic virDomainEventType which occured
+ * @detail: event specific detail information
  * @opaque: opaque user data
  *
  * A callback function to be registered, and called when a domain event occurs
@@ -1026,6 +1046,7 @@ typedef int (*virConnectDomainEventCallb
 typedef int (*virConnectDomainEventCallback)(virConnectPtr conn,
                                              virDomainPtr dom,
                                              int event,
+                                             int detail,
                                              void *opaque);
 
 int virConnectDomainEventRegister(virConnectPtr conn,
diff --git a/python/libvir.c b/python/libvir.c
--- a/python/libvir.c
+++ b/python/libvir.c
@@ -1538,6 +1538,7 @@ libvirt_virConnectDomainEventCallback(vi
 libvirt_virConnectDomainEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       virDomainPtr dom,
                                       int event,
+                                      int detail,
                                       void *opaque)
 {
     PyObject *pyobj_ret;
@@ -1595,9 +1596,10 @@ libvirt_virConnectDomainEventCallback(vi
     /* Call the Callback Dispatcher */
     pyobj_ret = PyObject_CallMethod(pyobj_conn_inst,
                                     (char*)"dispatchDomainEventCallbacks",
-                                    (char*)"Oi",
+                                    (char*)"Oii",
                                     pyobj_dom_inst,
-                                    event);
+                                    event,
+                                    detail);
 
     Py_DECREF(pyobj_dom_inst);
 
diff --git a/qemud/qemud.h b/qemud/qemud.h
--- a/qemud/qemud.h
+++ b/qemud/qemud.h
@@ -190,6 +190,7 @@ int remoteRelayDomainEvent (virConnectPt
 int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
                             virDomainPtr dom,
                             int event,
+                            int detail,
                             void *opaque);
 
 #endif
diff --git a/qemud/remote.c b/qemud/remote.c
--- a/qemud/remote.c
+++ b/qemud/remote.c
@@ -80,7 +80,8 @@ static void
 static void
 remoteDispatchDomainEventSend (struct qemud_client *client,
                                virDomainPtr dom,
-                               virDomainEventType event);
+                               int event,
+                               int detail);
 
 /* This function gets called from qemud when it detects an incoming
  * remote protocol message.  At this point, client->buffer contains
@@ -413,15 +414,16 @@ remoteDispatchError (struct qemud_client
 }
 
 int remoteRelayDomainEvent (virConnectPtr conn ATTRIBUTE_UNUSED,
-                                   virDomainPtr dom,
-                                   int event,
-                                   void *opaque)
+                            virDomainPtr dom,
+                            int event,
+                            int detail,
+                            void *opaque)
 {
     struct qemud_client *client = opaque;
-    REMOTE_DEBUG("Relaying domain event %d", event);
+    REMOTE_DEBUG("Relaying domain event %d %d", event, detail);
 
     if(client) {
-        remoteDispatchDomainEventSend (client, dom, event);
+        remoteDispatchDomainEventSend (client, dom, event, detail);
         qemudDispatchClientWrite(client->server,client);
     }
     return 0;
@@ -3762,8 +3764,9 @@ remoteDispatchDomainEventsDeregister (st
 
 static void
 remoteDispatchDomainEventSend (struct qemud_client *client,
-                         virDomainPtr dom,
-                         virDomainEventType event)
+                               virDomainPtr dom,
+                               int event,
+                               int detail)
 {
     remote_message_header rep;
     XDR xdr;
@@ -3799,7 +3802,8 @@ remoteDispatchDomainEventSend (struct qe
 
     /* build return data */
     make_nonnull_domain (&data.dom, dom);
-    data.event = (int) event;
+    data.event = event;
+    data.detail = detail;
 
     if (!xdr_remote_domain_event_ret(&xdr, &data)) {
         remoteDispatchError (client, NULL, "%s", _("serialise return struct"));
diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c
--- a/qemud/remote_protocol.c
+++ b/qemud/remote_protocol.c
@@ -2024,6 +2024,8 @@ xdr_remote_domain_event_ret (XDR *xdrs, 
                  return FALSE;
          if (!xdr_int (xdrs, &objp->event))
                  return FALSE;
+         if (!xdr_int (xdrs, &objp->detail))
+                 return FALSE;
         return TRUE;
 }
 
diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h
--- a/qemud/remote_protocol.h
+++ b/qemud/remote_protocol.h
@@ -1130,6 +1130,7 @@ struct remote_domain_event_ret {
 struct remote_domain_event_ret {
         remote_nonnull_domain dom;
         int event;
+        int detail;
 };
 typedef struct remote_domain_event_ret remote_domain_event_ret;
 #define REMOTE_PROGRAM 0x20008086
diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x
--- a/qemud/remote_protocol.x
+++ b/qemud/remote_protocol.x
@@ -1007,6 +1007,7 @@ struct remote_domain_event_ret {
 struct remote_domain_event_ret {
     remote_nonnull_domain dom;
     int event;
+    int detail;
 };
 
 /*----- Protocol. -----*/
diff --git a/src/domain_event.c b/src/domain_event.c
--- a/src/domain_event.c
+++ b/src/domain_event.c
@@ -198,7 +198,8 @@ int
 int
 virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue,
                                 virDomainPtr dom,
-                                virDomainEventType event)
+                                int event,
+                                int detail)
 {
     virDomainEventPtr domEvent;
 
@@ -214,6 +215,7 @@ virDomainEventCallbackQueuePush(virDomai
     }
     domEvent->dom = dom;
     domEvent->event = event;
+    domEvent->detail = detail;
 
     /* Make space on queue */
     if (VIR_REALLOC_N(evtQueue->events,
diff --git a/src/domain_event.h b/src/domain_event.h
--- a/src/domain_event.h
+++ b/src/domain_event.h
@@ -58,7 +58,8 @@ int virDomainEventCallbackListRemove(vir
  */
 struct _virDomainEvent {
     virDomainPtr dom;
-    virDomainEventType event;
+    int event;
+    int detail;
 };
 typedef struct _virDomainEvent virDomainEvent;
 typedef virDomainEvent *virDomainEventPtr;
@@ -72,7 +73,8 @@ typedef virDomainEventQueue *virDomainEv
 
 int virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue,
                                     virDomainPtr dom,
-                                    virDomainEventType event);
+                                    int event,
+                                    int detail);
 
 virDomainEventPtr
 virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue);
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -107,7 +107,8 @@ static int qemudSetNonBlock(int fd) {
 
 static void qemudDomainEventDispatch (struct qemud_driver *driver,
                                       virDomainObjPtr vm,
-                                      virDomainEventType evt);
+                                      int event,
+                                      int detail);
 
 static void qemudDispatchVMEvent(int fd,
                                  int events,
@@ -137,13 +138,19 @@ qemudAutostartConfigs(struct qemud_drive
     unsigned int i;
 
     for (i = 0 ; i < driver->domains.count ; i++) {
-        if (driver->domains.objs[i]->autostart &&
-            !virDomainIsActive(driver->domains.objs[i]) &&
-            qemudStartVMDaemon(NULL, driver, driver->domains.objs[i], NULL) < 0) {
-            virErrorPtr err = virGetLastError();
-            qemudLog(QEMUD_ERR, _("Failed to autostart VM '%s': %s\n"),
-                     driver->domains.objs[i]->def->name,
-                     err ? err->message : NULL);
+        virDomainObjPtr vm = driver->domains.objs[i];
+        if (vm->autostart &&
+            !virDomainIsActive(vm)) {
+            int ret = qemudStartVMDaemon(NULL, driver, vm, NULL);
+            if (ret < 0) {
+                virErrorPtr err = virGetLastError();
+                qemudLog(QEMUD_ERR, _("Failed to autostart VM '%s': %s\n"),
+                         vm->def->name,
+                         err ? err->message : NULL);
+            } else {
+                qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED,
+                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
+            }
         }
     }
 }
@@ -945,7 +952,6 @@ static int qemudStartVMDaemon(virConnect
             qemudShutdownVMDaemon(conn, driver, vm);
             return -1;
         }
-        qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED);
     }
 
     return ret;
@@ -1030,6 +1036,9 @@ static int qemudDispatchVMLog(struct qem
 static int qemudDispatchVMLog(struct qemud_driver *driver, virDomainObjPtr vm, int fd) {
     if (qemudVMData(driver, vm, fd) < 0) {
         qemudShutdownVMDaemon(NULL, driver, vm);
+        qemudDomainEventDispatch(driver, vm,
+                                 VIR_DOMAIN_EVENT_STOPPED,
+                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
         if (!vm->persistent)
             virDomainRemoveInactive(&driver->domains,
                                     vm);
@@ -1040,7 +1049,9 @@ static int qemudDispatchVMFailure(struct
 static int qemudDispatchVMFailure(struct qemud_driver *driver, virDomainObjPtr vm,
                                   int fd ATTRIBUTE_UNUSED) {
     qemudShutdownVMDaemon(NULL, driver, vm);
-    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED);
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STOPPED,
+                             VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains,
                                 vm);
@@ -1513,6 +1524,9 @@ static virDomainPtr qemudDomainCreate(vi
                                 vm);
         return NULL;
     }
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STARTED,
+                             VIR_DOMAIN_EVENT_STARTED_BOOTED);
 
     dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
     if (dom) dom->id = vm->def->id;
@@ -1543,7 +1557,7 @@ static int qemudDomainSuspend(virDomainP
     }
     vm->state = VIR_DOMAIN_PAUSED;
     qemudDebug("Reply %s", info);
-    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SUSPENDED);
+    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SUSPENDED, 0);
     VIR_FREE(info);
     return 0;
 }
@@ -1572,7 +1586,7 @@ static int qemudDomainResume(virDomainPt
     }
     vm->state = VIR_DOMAIN_RUNNING;
     qemudDebug("Reply %s", info);
-    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESUMED);
+    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESUMED, 0);
     VIR_FREE(info);
     return 0;
 }
@@ -1611,7 +1625,9 @@ static int qemudDomainDestroy(virDomainP
     }
 
     qemudShutdownVMDaemon(dom->conn, driver, vm);
-    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED);
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STOPPED,
+                             VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains,
                                 vm);
@@ -1942,10 +1958,12 @@ static int qemudDomainSave(virDomainPtr 
 
     /* Shut it down */
     qemudShutdownVMDaemon(dom->conn, driver, vm);
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STOPPED,
+                             VIR_DOMAIN_EVENT_STOPPED_SAVED);
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains,
                                 vm);
-    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SAVED);
     return 0;
 }
 
@@ -2240,6 +2258,10 @@ static int qemudDomainRestore(virConnect
         return -1;
     }
 
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STARTED,
+                             VIR_DOMAIN_EVENT_STARTED_RESTORED);
+
     /* If it was running before, resume it now. */
     if (header.was_running) {
         char *info;
@@ -2252,7 +2274,6 @@ static int qemudDomainRestore(virConnect
         vm->state = VIR_DOMAIN_RUNNING;
     }
 
-    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESTORED);
     return 0;
 }
 
@@ -2312,6 +2333,7 @@ static int qemudDomainStart(virDomainPtr
 static int qemudDomainStart(virDomainPtr dom) {
     struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
     virDomainObjPtr vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    int ret;
 
     if (!vm) {
         qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
@@ -2319,7 +2341,13 @@ static int qemudDomainStart(virDomainPtr
         return -1;
     }
 
-    return qemudStartVMDaemon(dom->conn, driver, vm, NULL);
+    ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL);
+    if (ret < 0)
+        return ret;
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STARTED,
+                             VIR_DOMAIN_EVENT_STARTED_BOOTED);
+    return 0;
 }
 
 
@@ -3340,7 +3368,8 @@ qemudDomainEventDeregister (virConnectPt
 
 static void qemudDomainEventDispatch (struct qemud_driver *driver,
                                       virDomainObjPtr vm,
-                                      virDomainEventType evt)
+                                      int event,
+                                      int detail)
 {
     int i;
     virDomainEventCallbackListPtr cbList;
@@ -3354,11 +3383,11 @@ static void qemudDomainEventDispatch (st
                                             vm->def->uuid);
             if (dom) {
                 dom->id = virDomainIsActive(vm) ? vm->def->id : -1;
-                DEBUG("Dispatching callback %p %p event %d",
-                        cbList->callbacks[i],
-                        cbList->callbacks[i]->cb, evt);
+                DEBUG("Dispatching callback %p %p event %d detail %d",
+                      cbList->callbacks[i],
+                      cbList->callbacks[i]->cb, event, detail);
                 cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
-                                         dom, evt,
+                                         dom, event, detail,
                                          cbList->callbacks[i]->opaque);
                 virDomainFree(dom);
             }
@@ -3507,6 +3536,9 @@ qemudDomainMigratePrepare2 (virConnectPt
 
         return -1;
     }
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STARTED,
+                             VIR_DOMAIN_EVENT_STARTED_MIGRATED);
 
     return 0;
 }
@@ -3578,6 +3610,9 @@ qemudDomainMigratePerform (virDomainPtr 
 
     /* Clean up the source domain. */
     qemudShutdownVMDaemon (dom->conn, driver, vm);
+    qemudDomainEventDispatch(driver, vm,
+                             VIR_DOMAIN_EVENT_STOPPED,
+                             VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains, vm);
 
@@ -3612,9 +3647,14 @@ qemudDomainMigrateFinish2 (virConnectPtr
         dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
         VIR_FREE(info);
         vm->state = VIR_DOMAIN_RUNNING;
+        qemudDomainEventDispatch(driver, vm,
+                                 VIR_DOMAIN_EVENT_RESUMED, 0);
         return dom;
     } else {
         qemudShutdownVMDaemon (dconn, driver, vm);
+        qemudDomainEventDispatch(driver, vm,
+                                 VIR_DOMAIN_EVENT_STOPPED,
+                                 VIR_DOMAIN_EVENT_STOPPED_FAILED);
         if (!vm->persistent)
             virDomainRemoveInactive(&driver->domains, vm);
         return NULL;
diff --git a/src/remote_internal.c b/src/remote_internal.c
--- a/src/remote_internal.c
+++ b/src/remote_internal.c
@@ -5154,7 +5154,7 @@ remoteRegister (void)
  */
 static int
 remoteDomainReadEvent(virConnectPtr conn, XDR *xdr,
-                      virDomainPtr *dom, int *event)
+                      virDomainPtr *dom, int *event, int *detail)
 {
     remote_domain_event_ret ret;
     memset (&ret, 0, sizeof ret);
@@ -5168,6 +5168,7 @@ remoteDomainReadEvent(virConnectPtr conn
 
     *dom = get_nonnull_domain(conn,ret.dom);
     *event = ret.event;
+    *detail = ret.detail;
 
     return 0;
 }
@@ -5176,15 +5177,16 @@ remoteDomainProcessEvent(virConnectPtr c
 remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr)
 {
     virDomainPtr dom;
-    int event,i;
-    struct private_data *priv = conn->privateData;
-
-    if(!remoteDomainReadEvent(conn, xdr, &dom, &event)) {
+    int event, detail, i;
+    struct private_data *priv = conn->privateData;
+
+    if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail)) {
         DEBUG0("Calling domain event callbacks (no queue)");
         for(i=0 ; i < priv->callbackList->count ; i++) {
-           if( priv->callbackList->callbacks[i] )
-               priv->callbackList->callbacks[i]->cb(conn, dom, event,
-                                     priv->callbackList->callbacks[i]->opaque);
+            if (priv->callbackList->callbacks[i] )
+                priv->callbackList->callbacks[i]->cb(
+                    conn, dom, event, detail,
+                    priv->callbackList->callbacks[i]->opaque);
         }
     }
 }
@@ -5193,13 +5195,13 @@ remoteDomainQueueEvent(virConnectPtr con
 remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr)
 {
     virDomainPtr dom;
-    int event;
-    struct private_data *priv = conn->privateData;
-
-    if(!remoteDomainReadEvent(conn, xdr, &dom, &event))
+    int event, detail;
+    struct private_data *priv = conn->privateData;
+
+    if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail))
     {
         if( virDomainEventCallbackQueuePush(priv->domainEvents,
-                                            dom, event) < 0 ) {
+                                            dom, event, detail) < 0 ) {
             DEBUG("%s", "Error adding event to queue");
         }
     }
@@ -5292,6 +5294,7 @@ remoteDomainEventQueueFlush(int timer AT
                priv->callbackList->callbacks[i]->cb(domEvent->dom->conn,
                                                     domEvent->dom,
                                                     domEvent->event,
+                                                    domEvent->detail,
                                                     user_data);
            }
         }


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list