diff --git a/qubes/app.py b/qubes/app.py index 2709ccc1..8df36dc5 100644 --- a/qubes/app.py +++ b/qubes/app.py @@ -106,6 +106,7 @@ class VirConnectWrapper(object): is_dead = not self._conn.isAlive() if is_dead: self._conn = libvirt.open(self._conn.getURI()) + # TODO: re-register event handlers return is_dead def _wrap_domain(self, ret): @@ -213,6 +214,33 @@ class VMMConnection(object): self.init_vmm_connection() return self._xs + def register_event_handlers(self, app): + '''Register libvirt event handlers, which will translate libvirt + events into qubes.events. This function should be called only in + 'qubesd' process and only when mainloop has been already set. + ''' + self._libvirt_conn.domainEventRegisterAny( + None, # any domain + libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, + self._domain_event_callback, + app + ) + + @staticmethod + def _domain_event_callback(_conn, domain, event, _detail, opaque): + '''Generic libvirt event handler (virConnectDomainEventCallback), + translate libvirt event into qubes.events. + ''' + app = opaque + try: + vm = app.domains[domain.name()] + except KeyError: + # ignore events for unknown domains + return + + if event == libvirt.VIR_DOMAIN_EVENT_STOPPED: + vm.fire_event('domain-shutdown') + def __del__(self): if self._libvirt_conn: self._libvirt_conn.close() diff --git a/qubes/tools/qubesd.py b/qubes/tools/qubesd.py index eb789c94..4fc7c914 100644 --- a/qubes/tools/qubesd.py +++ b/qubes/tools/qubesd.py @@ -176,11 +176,17 @@ def sighandler(loop, signame, server, server_internal): parser = qubes.tools.QubesArgumentParser(description='Qubes OS daemon') -def main(args=None): - args = parser.parse_args(args) - loop = asyncio.get_event_loop() +def main(args=None): + loop = asyncio.get_event_loop() libvirtaio.virEventRegisterAsyncIOImpl(loop=loop) + try: + args = parser.parse_args(args) + except: + loop.close() + raise + + args.app.vmm.register_event_handlers(args.app) try: os.unlink(QUBESD_SOCK) diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index 456cbc17..06ab69c1 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -195,6 +195,13 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): *other arguments are as in :py:meth:`start`* + .. event:: domain-shutdown (subject, event) + + Fired when domain has been shut down. + + :param subject: Event emitter (the qube object) + :param event: Event name (``'domain-shutdown'``) + .. event:: domain-pre-shutdown (subject, event, force) Fired at the beginning of :py:meth:`shutdown` method.