[libvirt] [RFC] Events API

Daniel P. Berrange berrange at redhat.com
Fri Sep 19 09:54:39 UTC 2008

On Thu, Sep 18, 2008 at 12:45:07PM -0400, David Lively wrote:
> Hi -
>   We have some folks looking into the implementation of events (just VM
> state transition events, for now) in libvirtd.  I've been assuming that
> events will be XML strings, something like:
>    <event type="domain-state-transition" timestamp="xxxxx">
>      <domain-id>22</domain-id>
>      <old-state>nostate</old-state>
>      <new-state>running</new-state>
>    </event>
> where the contents of the <event> element are determined by the event
> type, and the attributes type and timestamp are required.   
>   Originally, I was thinking one would listen for events by registering
> a callback, something like:
>     int virConnectAddEventHandler(virConnPtr conn, char **filter,
> virEventHandler handler, void *arg)
> where filter is either NULL, indicating interest in all events, or else
> a NULL-terminated vector of event type names, allowing filtering by
> event type. void handler(conn, const char *eventXML, arg) would be
> called for each matching event.

I think I'd prefer to have properly typed event callbacks for each
type of event we're dealing with, and to register callbacks against
the object being tracked. We also don't want to do transitions
on all the states - eg transitions between nostate & running are
happening many times a second - its not useful to track that IMHO.

Against a virConnectPtr object I'd expect to be able to register 
to get an event upon

 - A new domain object coming into existance
 - A existing domain object going out of existance

So, you could register a callback, call Rich's virConnectListAllDomains()
once, and then rely on the callbacks from that point onwards to keep 
your list of domains up2date. So in case of listening for domains:

   enum {
   typedef int (*virConnectDomainEventCallback)(virConnectPtr conn,
                                                virDomainPtr dom,
                                                int event,
                                                void *opaque);

   int virCOnnectDomainEventRegister(virConnectPtr conn,
                                     virConnectDomainEventCallback cb,
                                     void *opaque);

There would eventually be equivalent API for virNetworkPtr objects
and virStoragePoolPtr objects, to track addition & removal of them.

Against a virDomainPtr object, I'd expect to be able to register 
to get an event upon the significant state transitions. If we 
exclude the transition between nonstate & running which just happens
far to often to be practical to track, I don't see a need to filter
the events further - just have the callback get all events against
that domain object.

    enum {
    typedef int (*virDomainLifecycleEventCallback)(virDomainPtr dom,
                                                   int event,
                                                   void *opaque);
    virDomainLifecycleEventRegister(virDomainPtr dom,
                                    virDomainLifecycleEventCallback cb,
                                    void *opaque);

>   I'm a little concerned that a vector of event type names isn't really
> adequate for specifying a filter.  Does this need to be more general
> (XPathString exprs??)

IMHO, XML / xpath is rather overkill for getting lifecycle events.

>   But my larger concern is that an asynchronous callback mechanism (as
> proposed above) assumes the presence of some thread / process from which
> to make the callbacks.  ???This works fine in the libvirtd context, but
> not outside of it.  For instance, we build a "client only" version of
> libvirt with ONLY the remote driver, which currently doesn't require
> pthreads at all.  Introducing asynchronous callbacks into the API means
> pthreads is now required for this.

I wouldn't want to use threads for this - any application which is
structured  in such a way as to be able to make use of async events
will have some kind of event loop implementation. We merely need to
provoide a way to hook libvirt into that event loop. We already have
the API defined for this - src/event.h, and have an demonstration
impl that the daemon uses qemud/event.c.  So we'd want to validate
this src/event.h API contract by doing a proof-of concept impl with
an external Glib event loop and if it proves sane, then make the
event.h file part of the public API.

Applications could either craft their event loop impl themselves, or
we can provide some add-on pre-built helper libraries with common
impls. eg, an optional libvirt-glib library which comes with a
pre-built event impl for applications which use glib. Likewise a
libvirt-qt helper. That'd cover pretty much all common GUI apps.

This approach has been used very successfully by DBus to avoid tieing
dbus to a specific event loop impl.

>   I'm not sure how much requiring this extra thread matters. If it does,
> we could always define a synchronous delivery mechanism instead.  For
> instance, we could have a virDeliverEvents(conn) call to make the
> callbacks for any outstanding events.  Or we could just dispense with
> callbacks altogether, and return a readable (pipe) fd from which the
> client can read events.

I don't like the idea of exposing an FD as I consider this to be 
internal impl details. Allowing apps to see it will constrain our
abilty to change internals. So I prefer to have the applicaiton 
provide an event loop impl, which we can call into to register FDs
or timeout as & when libvirt deems neccessary.

|: 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