[libvirt] [RFC] events scripts support

We would like to introduce a way to configure system wide a script which would be called when some event happens. The script is a single executable set as a libvirtd option by the system administrator (assuming one runs the system libvirtd) or the user (assuming a user run libvirtd). The script could be invoked on daemon events, for example starting stopping, or reloading (SIGHUP), on domain events for example before a domain starts, or after its stops, and possibly on other kind of events detected by the daemon (storage or interface ...) My current thinking is to add the following two variables to libvirtd.conf: # Event scripts # An optional path to a script handling various kind of events like # domain start, domain end, pre and post migration, etc... # The events_script must be a path to the script or binary handling # the # events. # The events_set is a list of space separated name for the event type # the script should receive # # events_script="/etc/libvirt/events" # events_set="daemon domain" The script aruguments would be - the object kind: e.g. "domain" - the object name: e.g. the domain name - the event itself: e.g. "start" - sub event qualifier: e.g. "before" - an optional extra information for example in case of migration the destination or source So for example if the two variables as set as sugegsted, /etc/libvirt/events domain foo start before would be run by the daemon before the lunch of a domain which could have been initiated by the user when running "virsh foo start". The script exec return value is expected to be 0 unless indicating an error, in that case the libvirtd command would fail, for example if the command launched for "virsh foo start" failed with an error value the domain won't be started. This is a new kind of API in libvirt(d) so I'm submitting this for review. There could be some challenging issues, for example naming i.e. is the object "external" name like 'foo' the right thing to pass or should we also provide the uuid, making sure the arguments for the scripts and the behaviour is generic enough, and also how to handle potential recursion and avoid deadlock if the events script happen to use libvirt. I hope to have some initial patches by tomorrow, but I'm probably forgetting things, so feedback welcome ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Mar 23, 2010 at 12:17:50PM +0100, Daniel Veillard wrote:
We would like to introduce a way to configure system wide a script which would be called when some event happens. The script is a single executable set as a libvirtd option by the system administrator (assuming one runs the system libvirtd) or the user (assuming a user run libvirtd). The script could be invoked on daemon events, for example starting stopping, or reloading (SIGHUP), on domain events for example before a domain starts, or after its stops, and possibly on other kind of events detected by the daemon (storage or interface ...)
I'd really like to avoid calling this events. This is really a means to insert synchronous hooks into certain key places like domain startup. This is only really going to be usable for hypervisors/drivers where libvirt is in total control of guest startup, which means QEMU, LXC & UML. It'll never work for things like VMWare, Xen, VirtualBox, etc and it will also be fairly limited in interactions with the network, node device drivers, and possibly even storage. This is quite distinct from what the libvirt API refers to as events, which are asynchronous wrt the operation that occurred. The plus side of these type of events is that (from an architectural point of view) they can be implemented for pretty any of the libvirt hypervisor drivers. I think it would be useful to have a libvirt-events daemon that listened for these async events via our public API & invoked scripts upon certain scenarios. This is obviously separate from the synchronous hooks. The synchronous hooks will also be limited in that they must be fast to execute, and must not call back into libvirt - that would likely deadlock since this is synchronous. The separate events daemon providing async scripts would have freedom for long running operations & calling back into libvirt. I think we do need to support both approaches long term, but with the async events being the general purpose option, and the sync hook here being driver specific limited use cases.
My current thinking is to add the following two variables to libvirtd.conf:
# Event scripts # An optional path to a script handling various kind of events like # domain start, domain end, pre and post migration, etc... # The events_script must be a path to the script or binary handling # the # events. # The events_set is a list of space separated name for the event type # the script should receive # # events_script="/etc/libvirt/events" # events_set="daemon domain"
I think this really belongs in the QEMU driver, since I don't think this can be generalized to other drivers.
The script aruguments would be
- the object kind: e.g. "domain"
If this is considered QEMU specific, we don't need 'domain' here
- the object name: e.g. the domain name - the event itself: e.g. "start" - sub event qualifier: e.g. "before" - an optional extra information for example in case of migration the destination or source
That sounds sufficient. Since this is synchronous
So for example if the two variables as set as sugegsted,
/etc/libvirt/events domain foo start before
would be run by the daemon before the lunch of a domain which could have been initiated by the user when running "virsh foo start".
The script exec return value is expected to be 0 unless indicating an error, in that case the libvirtd command would fail, for example if the command launched for "virsh foo start" failed with an error value the domain won't be started.
This is a new kind of API in libvirt(d) so I'm submitting this for review. There could be some challenging issues, for example naming i.e. is the object "external" name like 'foo' the right thing to pass or should we also provide the uuid, making sure the arguments for the scripts and the behaviour is generic enough, and also how to handle potential recursion and avoid deadlock if the events script happen to use libvirt.
You have to mandate that synchronous hooks never call back into libvirt, allowing them todo so will be unfeasible. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

libvir-list-bounces@redhat.com wrote on 03/23/2010 08:12:57 AM:
Please respond to "Daniel P. Berrange"
This is a new kind of API in libvirt(d) so I'm submitting this for review. There could be some challenging issues, for example naming i.e. is the object "external" name like 'foo' the right thing to pass or should we also provide the uuid, making sure the arguments for the scripts and the behaviour is generic enough, and also how to handle potential recursion and avoid deadlock if the events script happen to use libvirt.
You have to mandate that synchronous hooks never call back into libvirt, allowing them todo so will be unfeasible.
Right. Since libvirt maintains all information about a VM the 'temptation' may be there to 'need' to pull information about the VM from within that script. I guess deadlocks would be typical. Stefan
Daniel -- |: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/:|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org:| |: http://autobuild.org -o- http://search.cpan.org/~danberr/:| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Tue, Mar 23, 2010 at 08:42:25AM -0400, Stefan Berger wrote:
libvir-list-bounces@redhat.com wrote on 03/23/2010 08:12:57 AM:
Please respond to "Daniel P. Berrange"
This is a new kind of API in libvirt(d) so I'm submitting this for review. There could be some challenging issues, for example naming i.e. is the object "external" name like 'foo' the right thing to pass or should we also provide the uuid, making sure the arguments for the scripts and the behaviour is generic enough, and also how to handle potential recursion and avoid deadlock if the events script happen to use libvirt.
You have to mandate that synchronous hooks never call back into libvirt, allowing them todo so will be unfeasible.
Right. Since libvirt maintains all information about a VM the 'temptation' may be there to 'need' to pull information about the VM from within that script. I guess deadlocks would be typical.
The XML config for the guest could perhaps be passed on stdin, but really these synchronous hooks should not be used for anything too complex - an asynch event is better for more complex tasks. These hooks should only be used for something which absolutely needs to be synchronous, in order to prevent the operation continuing. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Tue, 2010-03-23 at 12:12 +0000, Daniel P. Berrange wrote:
I think it would be useful to have a libvirt-events daemon that listened for these async events via our public API & invoked scripts upon certain scenarios. This is obviously separate from the synchronous hooks.
FWIW, a few days ago I wrote a small event watcher perl script based on one of the test scripts in libvirt-perl to print out machine start and stop events and the used interface name. The main program looks like this: ###################### my $ev = Sys::Virt::Event::Simple->new(); my $conn = Sys::Virt->new(uri => $URI); my @events; $conn->domain_event_register( sub { my $con = shift; my $dom = shift; my $event = shift; my $detail = shift; printf("event handler: " . $con->get_uri() . ", " . $dom->get_name() . ", $event, $detail\n"); push @events, [$con, $dom, $event, $detail]; }); while (1) { my $no_of_ev = int(@events); $ev->run_once(); printf("no of ev : $no_of_ev \n" ); printf("uri : " . $events[$no_of_ev]->[0]->get_uri()); printf("\n" ); printf("name : " . $events[$no_of_ev]->[1]->get_name()); printf("\n" ); my $xmldesc = $events[$no_of_ev]->[1]->get_xml_description(); my $ifname = get_ifname($xmldesc); print "ifname = $ifname\n"; printf("\n" ); } $conn->domain_event_deregister; $conn = undef; ###################### Current output looks like this: ###################### event handler: qemu:///system, f12a, 2, 0 no of ev : 0 uri : qemu:///system name : f12a ifname = macvtap0 event handler: qemu:///system, f12, 5, 0 no of ev : 1 uri : qemu:///system name : f12 ifname = macvtap1 ###################### Having an architected events daemon in libvirt would certainly be a good idea in my opinion. -- Best regards, Gerhard Stenzel, ----------------------------------------------------------------------------------------------------------------------------------- IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martin Jetter Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On Tue, Mar 23, 2010 at 12:12:57PM +0000, Daniel P. Berrange wrote:
On Tue, Mar 23, 2010 at 12:17:50PM +0100, Daniel Veillard wrote:
We would like to introduce a way to configure system wide a script which would be called when some event happens. The script is a single executable set as a libvirtd option by the system administrator (assuming one runs the system libvirtd) or the user (assuming a user run libvirtd). The script could be invoked on daemon events, for example starting stopping, or reloading (SIGHUP), on domain events for example before a domain starts, or after its stops, and possibly on other kind of events detected by the daemon (storage or interface ...)
I'd really like to avoid calling this events. This is really a means
okay that's confusing and 'hook' is a better term
to insert synchronous hooks into certain key places like domain startup. This is only really going to be usable for hypervisors/drivers where libvirt is in total control of guest startup, which means QEMU, LXC & UML. It'll never work for things like VMWare, Xen, VirtualBox, etc and it will also be fairly limited in interactions with the network, node device drivers, and possibly even storage.
I would not presume too much about storage and network. I'm just opening the idea that some hooks may come from there in the future.
The synchronous hooks will also be limited in that they must be fast to execute, and must not call back into libvirt - that would likely deadlock since this is synchronous. The separate events daemon providing
Yeah the deadlocking problem is something I raised in my mail.
I think we do need to support both approaches long term, but with the async events being the general purpose option, and the sync hook here being driver specific limited use cases.
Still that's something I would like to see exposed for LXC too.
My current thinking is to add the following two variables to libvirtd.conf:
# Event scripts # An optional path to a script handling various kind of events like # domain start, domain end, pre and post migration, etc... # The events_script must be a path to the script or binary handling # the # events. # The events_set is a list of space separated name for the event type # the script should receive # # events_script="/etc/libvirt/events" # events_set="daemon domain"
I think this really belongs in the QEMU driver, since I don't think this can be generalized to other drivers.
I disagree, this can be used for generic daemon events as I suggested like shutdown or restart, plus usable for lxc at least.
The script aruguments would be
- the object kind: e.g. "domain"
If this is considered QEMU specific, we don't need 'domain' here
I don't want this to be QEmu specific. But I think we need to provide the driver in case of qemu/lxc/... I think the first string should match one of the values registered in hooks_set="daemon domain"
- the object name: e.g. the domain name - the event itself: e.g. "start" - sub event qualifier: e.g. "before" - an optional extra information for example in case of migration the destination or source
That sounds sufficient. Since this is synchronous
we probably need the uuid of the object if available ('-' otherwise) and the driver name in case of a domain (or future network/storage) alternatively passing the object XML as the hook script stdin is probably the simplest way to convey a complete set of informations.
So for example if the two variables as set as sugegsted,
/etc/libvirt/events domain foo start before
would be run by the daemon before the lunch of a domain which could have been initiated by the user when running "virsh foo start".
The script exec return value is expected to be 0 unless indicating an error, in that case the libvirtd command would fail, for example if the command launched for "virsh foo start" failed with an error value the domain won't be started.
This is a new kind of API in libvirt(d) so I'm submitting this for review. There could be some challenging issues, for example naming i.e. is the object "external" name like 'foo' the right thing to pass or should we also provide the uuid, making sure the arguments for the scripts and the behaviour is generic enough, and also how to handle potential recursion and avoid deadlock if the events script happen to use libvirt.
You have to mandate that synchronous hooks never call back into libvirt, allowing them todo so will be unfeasible.
yeah, it's getting clear that going back to libvirt will untenable. Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Mar 23, 2010 at 03:15:27PM +0100, Daniel Veillard wrote:
On Tue, Mar 23, 2010 at 12:12:57PM +0000, Daniel P. Berrange wrote:
On Tue, Mar 23, 2010 at 12:17:50PM +0100, Daniel Veillard wrote:
We would like to introduce a way to configure system wide a script which would be called when some event happens. The script is a single executable set as a libvirtd option by the system administrator (assuming one runs the system libvirtd) or the user (assuming a user run libvirtd). The script could be invoked on daemon events, for example starting stopping, or reloading (SIGHUP), on domain events for example before a domain starts, or after its stops, and possibly on other kind of events detected by the daemon (storage or interface ...)
I'd really like to avoid calling this events. This is really a means
okay that's confusing and 'hook' is a better term
to insert synchronous hooks into certain key places like domain startup. This is only really going to be usable for hypervisors/drivers where libvirt is in total control of guest startup, which means QEMU, LXC & UML. It'll never work for things like VMWare, Xen, VirtualBox, etc and it will also be fairly limited in interactions with the network, node device drivers, and possibly even storage.
I would not presume too much about storage and network. I'm just opening the idea that some hooks may come from there in the future.
The synchronous hooks will also be limited in that they must be fast to execute, and must not call back into libvirt - that would likely deadlock since this is synchronous. The separate events daemon providing
Yeah the deadlocking problem is something I raised in my mail.
I think we do need to support both approaches long term, but with the async events being the general purpose option, and the sync hook here being driver specific limited use cases.
Still that's something I would like to see exposed for LXC too.
My current thinking is to add the following two variables to libvirtd.conf:
# Event scripts # An optional path to a script handling various kind of events like # domain start, domain end, pre and post migration, etc... # The events_script must be a path to the script or binary handling # the # events. # The events_set is a list of space separated name for the event type # the script should receive # # events_script="/etc/libvirt/events" # events_set="daemon domain"
I think this really belongs in the QEMU driver, since I don't think this can be generalized to other drivers.
I disagree, this can be used for generic daemon events as I suggested like shutdown or restart, plus usable for lxc at least.
The script aruguments would be
- the object kind: e.g. "domain"
If this is considered QEMU specific, we don't need 'domain' here
I don't want this to be QEmu specific. But I think we need to provide the driver in case of qemu/lxc/... I think the first string should match one of the values registered in hooks_set="daemon domain"
It is fine if different drivers implement a similar scheme, just that the hook location must be separate for each driver. For example, consider someone sets up a hook for QEMU /etc/libvirt/events/myhook.sh then in the next release we enable these hooks for LXC too. The myhook.sh script they provided cannot be assumed to work with the LXC driver. Thus we need to have separate hook directoriess for each driver. They should of course all follow the same design for sake of consistency. In the same way that we standardized on /etc/libvirt/$DRIVERNAME/ for XML config files, we should standardize on /etc/libvirt/hooks/$DRIVERNAME/ for the hook scripts directory location. We don't need to make this directory configurable in the libvirtd.conf - it should be a fixed location & on by default - no config required.
- the object name: e.g. the domain name - the event itself: e.g. "start" - sub event qualifier: e.g. "before" - an optional extra information for example in case of migration the destination or source
That sounds sufficient. Since this is synchronous
we probably need the uuid of the object if available ('-' otherwise) and the driver name in case of a domain (or future network/storage) alternatively passing the object XML as the hook script stdin is probably the simplest way to convey a complete set of informations.
UUID is worthwhile, but I think driver name should be used to set the actual directory in which the hook lives, rather than being a parameter. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (4)
-
Daniel P. Berrange
-
Daniel Veillard
-
Gerhard Stenzel
-
Stefan Berger