events: merge fire_event and fire_event_pre functions

Those functions really do very similar things - lets merge them and add
simple parameter.
This commit is contained in:
Marek Marczykowski-Górecki 2017-06-23 17:29:09 +02:00
parent aed6de4937
commit 6238254f49
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
10 changed files with 34 additions and 65 deletions

View File

@ -22,10 +22,10 @@ parent class and then for it's child. For each class, first are called handlers
defined in it's source, then handlers from extensions and last the callers added
manually.
There is second method, :py:meth:`qubes.events.Emitter.fire_event_pre`, which
fires events in reverse order. It is suitable for events fired before some
action is performed. You may at your own responsibility raise exceptions from
such events to try to prevent such action.
The :py:meth:`qubes.events.Emitter.fire_event` method have keyword argument
`pre_event`, which fires events in reverse order. It is suitable for events
fired before some action is performed. You may at your own responsibility raise
exceptions from such events to try to prevent such action.
Events handlers may yield values. Those values are aggregated and returned
to the caller as a list of those values. See below for details.

View File

@ -250,10 +250,12 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name
value = self.type(value)
if has_oldvalue:
instance.fire_event_pre('property-pre-set:' + self.__name__,
instance.fire_event('property-pre-set:' + self.__name__,
pre_event=True,
name=self.__name__, newvalue=value, oldvalue=oldvalue)
else:
instance.fire_event_pre('property-pre-set:' + self.__name__,
instance.fire_event('property-pre-set:' + self.__name__,
pre_event=True,
name=self.__name__, newvalue=value)
instance._property_init(self, value) # pylint: disable=protected-access
@ -276,14 +278,16 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name
has_oldvalue = False
if has_oldvalue:
instance.fire_event_pre('property-pre-del:' + self.__name__,
instance.fire_event('property-pre-del:' + self.__name__,
pre_event=True,
name=self.__name__, oldvalue=oldvalue)
delattr(instance, self._attr_name)
instance.fire_event('property-del:' + self.__name__,
name=self.__name__, oldvalue=oldvalue)
else:
instance.fire_event_pre('property-pre-del:' + self.__name__,
instance.fire_event('property-pre-del:' + self.__name__,
pre_event=True,
name=self.__name__)
instance.fire_event('property-del:' + self.__name__,
name=self.__name__)

View File

@ -181,8 +181,8 @@ class AbstractQubesAPI(object):
def fire_event_for_permission(self, **kwargs):
'''Fire an event on the source qube to check for permission'''
return self.src.fire_event_pre('mgmt-permission:' + self.method,
dest=self.dest, arg=self.arg, **kwargs)
return self.src.fire_event('mgmt-permission:' + self.method,
pre_event=True, dest=self.dest, arg=self.arg, **kwargs)
def fire_event_for_filter(self, iterable, **kwargs):
'''Fire an event on the source qube to filter for permission'''

View File

@ -476,7 +476,7 @@ class VMCollection(object):
vm = self[key]
if not vm.is_halted():
raise qubes.exc.QubesVMNotHaltedError(vm)
self.app.fire_event_pre('domain-pre-delete', vm=vm)
self.app.fire_event('domain-pre-delete', pre_event=True, vm=vm)
try:
vm.libvirt_domain.undefine()
except libvirt.libvirtError as e:

View File

@ -180,7 +180,7 @@ class DeviceCollection(object):
raise DeviceAlreadyAttached(
'device {!s} of class {} already attached to {!s}'.format(
device, self._bus, self._vm))
self._vm.fire_event_pre('device-pre-attach:'+self._bus,
self._vm.fire_event('device-pre-attach:'+self._bus, pre_event=True,
device=device, options=device_assignment.options)
if device_assignment.persistent:
self._set.add(device_assignment)
@ -208,7 +208,8 @@ class DeviceCollection(object):
device_assignment.ident, self._bus, self._vm))
device = device_assignment.device
self._vm.fire_event_pre('device-pre-detach:'+self._bus, device=device)
self._vm.fire_event('device-pre-detach:' + self._bus,
pre_event=True, device=device)
if device in self._set:
device_assignment.persistent = True
self._set.discard(device_assignment)

View File

@ -134,16 +134,19 @@ class Emitter(object, metaclass=EmitterMeta):
# pylint: disable=no-member
self.__handlers__[event].remove(func)
def _fire_event_in_order(self, order, event, kwargs):
def _fire_event(self, event, kwargs, pre_event=False):
'''Fire event for classes in given order.
Do not use this method. Use :py:meth:`fire_event` or
:py:meth:`fire_event_pre`.
Do not use this method. Use :py:meth:`fire_event`.
'''
if not self.events_enabled:
return []
order = itertools.chain((self,), self.__class__.__mro__)
if not pre_event:
order = reversed(list(order))
effects = []
for i in order:
try:
@ -161,46 +164,21 @@ class Emitter(object, metaclass=EmitterMeta):
effects.extend(effect)
return effects
def fire_event(self, event, **kwargs):
def fire_event(self, event, pre_event=False, **kwargs):
'''Call all handlers for an event.
Handlers are called for class and all parent classes, in **reversed**
or **true** (depending on *pre_event* parameter)
method resolution order. For each class first are called bound handlers
(specified in class definition), then handlers from extensions. Aside
from above, remaining order is undefined.
.. seealso::
:py:meth:`fire_event_pre`
:param str event: event identifier
:param pre_event: is this -pre- event? reverse handlers calling order
:returns: list of effects
All *kwargs* are passed verbatim. They are different for different
events.
'''
return self._fire_event_in_order(
itertools.chain(reversed(self.__class__.__mro__), (self,)),
event, kwargs)
def fire_event_pre(self, event, **kwargs):
'''Call all handlers for an event.
Handlers are called for class and all parent classes, in **true**
method resolution order. This is intended for ``-pre-`` events, where
order of invocation should be reversed.
.. seealso::
:py:meth:`fire_event`
:param str event: event identifier
:returns: list of effects
All *kwargs* are passed verbatim. They are different for different
events.
'''
return self._fire_event_in_order(
itertools.chain((self,), self.__class__.__mro__),
event, kwargs)
return self._fire_event(event, kwargs, pre_event=pre_event)

View File

@ -159,17 +159,6 @@ class TestEmitter(qubes.events.Emitter):
self.fired_events[(event, ev_kwargs)] += 1
return effects
def fire_event_pre(self, event, **kwargs):
effects = super(TestEmitter, self).fire_event_pre(event, **kwargs)
ev_kwargs = frozenset(
(key,
frozenset(value.items()) if isinstance(value, dict)
else tuple(value) if isinstance(value, list)
else value)
for key, value in kwargs.items()
)
self.fired_events[(event, ev_kwargs)] += 1
return effects
def expectedFailureIfTemplate(templates):
"""

View File

@ -76,7 +76,6 @@ class AdminAPITestCase(qubes.tests.QubesTestCase):
self.emitter = qubes.tests.TestEmitter()
self.app.domains[0].fire_event = self.emitter.fire_event
self.app.domains[0].fire_event_pre = self.emitter.fire_event_pre
def tearDown(self):
self.base_dir_patch2.stop()
@ -1793,8 +1792,6 @@ class TC_00_VMs(AdminAPITestCase):
def test_590_firewall_reload(self):
self.vm.firewall.save = unittest.mock.Mock()
self.app.domains['test-vm1'].fire_event = self.emitter.fire_event
self.app.domains['test-vm1'].fire_event_pre = \
self.emitter.fire_event_pre
value = self.call_mgmt_func(b'admin.vm.firewall.Reload',
b'test-vm1', b'')
self.assertIsNone(value)

View File

@ -73,7 +73,6 @@ class TC_00_Emitter(qubes.tests.QubesTestCase):
emitter = TestEmitter()
emitter.events_enabled = True
emitter.fire_event('testevent')
effect = emitter.fire_event('testevent')
@ -129,8 +128,8 @@ class TC_00_Emitter(qubes.tests.QubesTestCase):
['testevent_1'])
with self.subTest('fire_event_pre'):
effect = emitter.fire_event_pre('testevent')
effect2 = emitter2.fire_event_pre('testevent')
effect = emitter.fire_event('testevent', pre_event=True)
effect2 = emitter2.fire_event('testevent', pre_event=True)
self.assertEqual(list(effect),
['testevent_2', 'testevent_1'])
self.assertEqual(list(effect2),

View File

@ -847,7 +847,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
self.log.info('Starting {}'.format(self.name))
self.fire_event_pre('domain-pre-start',
self.fire_event('domain-pre-start',
pre_event=True,
start_guid=start_guid, mem_required=mem_required)
yield from self.storage.verify()
@ -935,7 +936,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
if self.is_halted():
raise qubes.exc.QubesVMNotStartedError(self)
self.fire_event_pre('domain-pre-shutdown', force=force)
self.fire_event('domain-pre-shutdown', pre_event=True, force=force)
self.libvirt_domain.shutdown()
@ -1071,7 +1072,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
raise qubes.exc.QubesVMError(
self, 'Domain {!r}: qrexec not connected'.format(self.name))
self.fire_event_pre('domain-cmd-pre-run', start_guid=gui)
self.fire_event('domain-cmd-pre-run', pre_event=True, start_guid=gui)
return (yield from asyncio.create_subprocess_exec(
qubes.config.system_path['qrexec_client_path'],