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 {
VIR_CONNECT_DOMAIN_EVENT_ADDED,
VIR_CONNECT_DOMAIN_EVENT_REMOVED,
};
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 {
VIR_DOMAIN_EVENT_STARTED
VIR_DOMAIN_EVENT_SUSPENDED
VIR_DOMAIN_EVENT_RESUMED
VIR_DOMAIN_EVENT_STOPPED
VIR_DOMAIN_EVENT_SAVED,
VIR_DOMAIN_EVENT_RESTORED,
};
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.
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 :|