[libvirt] Re: [PATCH 06/12] Domain Events - qemu driver

Daniel P. Berrange berrange at redhat.com
Sun Oct 19 19:35:26 UTC 2008


On Fri, Oct 17, 2008 at 12:02:52PM -0400, Ben Guthro wrote:
>  Register for, and dispatch domain event callbacks
> 
>  qemu_conf.h   |    3 ++
>  qemu_driver.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 77 insertions(+), 2 deletions(-)

> diff --git a/src/qemu_conf.h b/src/qemu_conf.h
> index cfd7d35..d06c4d7 100644
> --- a/src/qemu_conf.h
> +++ b/src/qemu_conf.h
> @@ -63,6 +63,9 @@ struct qemud_driver {
>      char *vncListen;
>  
>      virCapsPtr caps;
> +
> +    /* An array of callbacks */
> +    virDomainEventCallbackListPtr domainEventCallbacks;
>  };
>  
>  
> diff --git a/src/qemu_driver.c b/src/qemu_driver.c
> index a86b787..9792541 100644
> --- a/src/qemu_driver.c
> +++ b/src/qemu_driver.c
> @@ -159,6 +159,10 @@ qemudStartup(void) {
>      /* Don't have a dom0 so start from 1 */
>      qemu_driver->nextvmid = 1;
>  
> +    /* Init callback list */
> +    if(VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
> +        return -1;
> +
>      if (!uid) {
>          if (asprintf(&qemu_driver->logDir,
>                       "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
> @@ -301,6 +305,9 @@ qemudShutdown(void) {
>      VIR_FREE(qemu_driver->autostartDir);
>      VIR_FREE(qemu_driver->vncTLSx509certdir);
>  
> +    /* Free domain callback list */
> +    virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
> +
>      if (qemu_driver->brctl)
>          brShutdown(qemu_driver->brctl);
>  
> @@ -742,6 +749,8 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
>      return -1;
>  }
>  
> +static virDomainPtr qemudDomainLookupByName(virConnectPtr conn, const char *name);
> +
>  static int qemudStartVMDaemon(virConnectPtr conn,
>                                struct qemud_driver *driver,
>                                virDomainObjPtr vm,
> @@ -756,6 +765,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
>      unsigned int qemuCmdFlags;
>      fd_set keepfd;
>      const char *emulator;
> +    virDomainPtr dom;
>  
>      FD_ZERO(&keepfd);
>  
> @@ -918,6 +928,11 @@ static int qemudStartVMDaemon(virConnectPtr conn,
>              qemudShutdownVMDaemon(conn, driver, vm);
>              return -1;
>          }
> +        dom = qemudDomainLookupByName(conn,vm->def->name);
> +        if(dom)
> +            virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STARTED);
> +        else
> +            DEBUG0("Warning - dom is NULL at domain start");
>      }
>  
>      return ret;
> @@ -1503,6 +1518,7 @@ static int qemudDomainSuspend(virDomainPtr dom) {
>      }
>      vm->state = VIR_DOMAIN_PAUSED;
>      qemudDebug("Reply %s", info);
> +    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SUSPENDED);
>      VIR_FREE(info);
>      return 0;
>  }
> @@ -1531,6 +1547,7 @@ static int qemudDomainResume(virDomainPtr dom) {
>      }
>      vm->state = VIR_DOMAIN_RUNNING;
>      qemudDebug("Reply %s", info);
> +    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESUMED);
>      VIR_FREE(info);
>      return 0;
>  }
> @@ -1572,7 +1589,7 @@ static int qemudDomainDestroy(virDomainPtr dom) {
>      if (!vm->persistent)
>          virDomainRemoveInactive(&driver->domains,
>                                  vm);
> -
> +    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STOPPED);
>      return 0;
>  }
>  
> @@ -1903,7 +1920,7 @@ static int qemudDomainSave(virDomainPtr dom,
>      if (!vm->persistent)
>          virDomainRemoveInactive(&driver->domains,
>                                  vm);
> -
> +    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SAVED);
>      return 0;
>  }
>  
> @@ -2104,6 +2121,7 @@ static int qemudDomainRestore(virConnectPtr conn,
>      struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
>      virDomainDefPtr def;
>      virDomainObjPtr vm;
> +    virDomainPtr    dom;
>      int fd;
>      int ret;
>      char *xml;
> @@ -2210,6 +2228,11 @@ static int qemudDomainRestore(virConnectPtr conn,
>          vm->state = VIR_DOMAIN_RUNNING;
>      }
>  
> +    dom = virDomainLookupByID(conn, def->id);
> +    if(dom) {
> +        virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESTORED);
> +        VIR_FREE(dom);
> +    }
>      return 0;
>  }
>  
> @@ -3051,6 +3074,52 @@ done:
>  }
>  
>  
> +static int qemudDomainEventRegister (virConnectPtr conn,
> +                                     void *callback,
> +                                     void *opaque)
> +{
> +    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
> +
> +    return virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks, callback, opaque);
> +}
> +
> +static int qemudDomainEventDeregister (virConnectPtr conn,
> +                                 void *callback)
> +{
> +    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
> +
> +    return virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks, callback);
> +}
> +
> +static void qemudDomainEventDispatch (virDomainPtr dom,
> +                                      virDomainEventType evt)
> +{
> +    int i;
> +    struct qemud_driver *driver;
> +    virDomainEventCallbackListPtr cbList;
> +
> +    if(!dom->conn) {
> +        DEBUG0("Invalid conn");
> +        return;
> +    }
> +    driver = (struct qemud_driver *)dom->conn->privateData;
> +
> +    if(!driver) {
> +        DEBUG0("Invalid driver");
> +        return;
> +    }
> +    cbList = driver->domainEventCallbacks;
> +
> +    for(i=0;i<cbList->count;i++) {
> +        if(cbList->callbacks[i] && cbList->callbacks[i]->cb)
> +            DEBUG("Dispatching callback %p %p event %d", cbList->callbacks[i], cbList->callbacks[i]->cb, evt);
> +            cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
> +                                     dom, evt,
> +                                     cbList->callbacks[i]->opaque);
> +    }
> +
> +}

THis all basically works fine, but there's one tiny missing bit. If
a domain shuts down from an external trigger - eg guest admin does a
'shutdown -h', or host admin does 'kill -TERM $qemu', then no STOPPED
event is fired. For this we need to hook into the qemudDispatchVMFailure()
method.

This introduces a small problem though - we don't have a 'virDomainPtr'
object here, so we can't call the generic virDispatchDomainEvent()
method. Of course virDispatchDomainEvent() just delegates back into
the driver - in this case qemudDomainEventDispatch(), which has no
hard requirement to have a 'virDomainPtr' object. Each registered
callback has a 'virConnectPtr' object associated with it, so we can
simply fetch a virDomainPtr as required.

To demonstrate this I'm attching a patch which applies ontop of yours
to make this method call directly. With this, I think we can remove
the 'domainEventDispatch' field in driver.h - though obviously the
other non-QEMU drivers need changing to match too.

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -105,6 +105,10 @@ static int qemudSetNonBlock(int fd) {
     return -1;
 }
 
+
+static void qemudDomainEventDispatch (struct qemud_driver *driver,
+                                      virDomainObjPtr vm,
+                                      virDomainEventType evt);
 
 static void qemudDispatchVMEvent(int fd, int events, void *opaque);
 static int qemudStartVMDaemon(virConnectPtr conn,
@@ -930,7 +934,7 @@ static int qemudStartVMDaemon(virConnect
         }
         dom = qemudDomainLookupByName(conn,vm->def->name);
         if(dom)
-            virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STARTED);
+            qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED);
         else
             DEBUG0("Warning - dom is NULL at domain start");
     }
@@ -1027,6 +1031,7 @@ 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);
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains,
                                 vm);
@@ -1518,7 +1523,7 @@ static int qemudDomainSuspend(virDomainP
     }
     vm->state = VIR_DOMAIN_PAUSED;
     qemudDebug("Reply %s", info);
-    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SUSPENDED);
+    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SUSPENDED);
     VIR_FREE(info);
     return 0;
 }
@@ -1547,7 +1552,7 @@ static int qemudDomainResume(virDomainPt
     }
     vm->state = VIR_DOMAIN_RUNNING;
     qemudDebug("Reply %s", info);
-    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESUMED);
+    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESUMED);
     VIR_FREE(info);
     return 0;
 }
@@ -1586,10 +1591,10 @@ static int qemudDomainDestroy(virDomainP
     }
 
     qemudShutdownVMDaemon(dom->conn, driver, vm);
+    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED);
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains,
                                 vm);
-    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STOPPED);
     return 0;
 }
 
@@ -1920,7 +1925,7 @@ static int qemudDomainSave(virDomainPtr 
     if (!vm->persistent)
         virDomainRemoveInactive(&driver->domains,
                                 vm);
-    virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SAVED);
+    qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SAVED);
     return 0;
 }
 
@@ -2230,7 +2235,7 @@ static int qemudDomainRestore(virConnect
 
     dom = virDomainLookupByID(conn, def->id);
     if(dom) {
-        virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESTORED);
+        qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESTORED);
         VIR_FREE(dom);
     }
     return 0;
@@ -3090,31 +3095,28 @@ static int qemudDomainEventDeregister (v
     return virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks, callback);
 }
 
-static void qemudDomainEventDispatch (virDomainPtr dom,
+static void qemudDomainEventDispatch (struct qemud_driver *driver,
+                                      virDomainObjPtr vm,
                                       virDomainEventType evt)
 {
     int i;
-    struct qemud_driver *driver;
     virDomainEventCallbackListPtr cbList;
 
-    if(!dom->conn) {
-        DEBUG0("Invalid conn");
-        return;
-    }
-    driver = (struct qemud_driver *)dom->conn->privateData;
-
-    if(!driver) {
-        DEBUG0("Invalid driver");
-        return;
-    }
     cbList = driver->domainEventCallbacks;
 
     for(i=0;i<cbList->count;i++) {
-        if(cbList->callbacks[i] && cbList->callbacks[i]->cb)
-            DEBUG("Dispatching callback %p %p event %d", cbList->callbacks[i], cbList->callbacks[i]->cb, evt);
-            cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
-                                     dom, evt,
-                                     cbList->callbacks[i]->opaque);
+        if(cbList->callbacks[i] && cbList->callbacks[i]->cb) {
+            virConnectPtr conn = cbList->callbacks[i]->conn;
+            virDomainPtr dom = virGetDomain(conn, vm->def->name, 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);
+                cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
+                                         dom, evt,
+                                         cbList->callbacks[i]->opaque);
+                virDomainFree(dom);
+            }
+        }
     }
 
 }
@@ -3191,7 +3193,7 @@ static virDriver qemuDriver = {
 #endif
     qemudDomainEventRegister, /* domainEventRegister */
     qemudDomainEventDeregister, /* domainEventDeregister */
-    qemudDomainEventDispatch, /* domainEventDispatch */
+    NULL,
 };
 
 


Regards,
Daniel
-- 
|: 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