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 defined in it's source, then handlers from extensions and last the callers added
manually. manually.
There is second method, :py:meth:`qubes.events.Emitter.fire_event_pre`, which The :py:meth:`qubes.events.Emitter.fire_event` method have keyword argument
fires events in reverse order. It is suitable for events fired before some `pre_event`, which fires events in reverse order. It is suitable for events
action is performed. You may at your own responsibility raise exceptions from fired before some action is performed. You may at your own responsibility raise
such events to try to prevent such action. exceptions from such events to try to prevent such action.
Events handlers may yield values. Those values are aggregated and returned Events handlers may yield values. Those values are aggregated and returned
to the caller as a list of those values. See below for details. 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) value = self.type(value)
if has_oldvalue: 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) name=self.__name__, newvalue=value, oldvalue=oldvalue)
else: 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) name=self.__name__, newvalue=value)
instance._property_init(self, value) # pylint: disable=protected-access 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 has_oldvalue = False
if has_oldvalue: 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) name=self.__name__, oldvalue=oldvalue)
delattr(instance, self._attr_name) delattr(instance, self._attr_name)
instance.fire_event('property-del:' + self.__name__, instance.fire_event('property-del:' + self.__name__,
name=self.__name__, oldvalue=oldvalue) name=self.__name__, oldvalue=oldvalue)
else: else:
instance.fire_event_pre('property-pre-del:' + self.__name__, instance.fire_event('property-pre-del:' + self.__name__,
pre_event=True,
name=self.__name__) name=self.__name__)
instance.fire_event('property-del:' + self.__name__, instance.fire_event('property-del:' + self.__name__,
name=self.__name__) name=self.__name__)

View File

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

View File

@ -476,7 +476,7 @@ class VMCollection(object):
vm = self[key] vm = self[key]
if not vm.is_halted(): if not vm.is_halted():
raise qubes.exc.QubesVMNotHaltedError(vm) 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: try:
vm.libvirt_domain.undefine() vm.libvirt_domain.undefine()
except libvirt.libvirtError as e: except libvirt.libvirtError as e:

View File

@ -180,7 +180,7 @@ class DeviceCollection(object):
raise DeviceAlreadyAttached( raise DeviceAlreadyAttached(
'device {!s} of class {} already attached to {!s}'.format( 'device {!s} of class {} already attached to {!s}'.format(
device, self._bus, self._vm)) 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) device=device, options=device_assignment.options)
if device_assignment.persistent: if device_assignment.persistent:
self._set.add(device_assignment) self._set.add(device_assignment)
@ -208,7 +208,8 @@ class DeviceCollection(object):
device_assignment.ident, self._bus, self._vm)) device_assignment.ident, self._bus, self._vm))
device = device_assignment.device 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: if device in self._set:
device_assignment.persistent = True device_assignment.persistent = True
self._set.discard(device_assignment) self._set.discard(device_assignment)

View File

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

View File

@ -159,17 +159,6 @@ class TestEmitter(qubes.events.Emitter):
self.fired_events[(event, ev_kwargs)] += 1 self.fired_events[(event, ev_kwargs)] += 1
return effects 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): def expectedFailureIfTemplate(templates):
""" """

View File

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

View File

@ -73,7 +73,6 @@ class TC_00_Emitter(qubes.tests.QubesTestCase):
emitter = TestEmitter() emitter = TestEmitter()
emitter.events_enabled = True emitter.events_enabled = True
emitter.fire_event('testevent')
effect = emitter.fire_event('testevent') effect = emitter.fire_event('testevent')
@ -129,8 +128,8 @@ class TC_00_Emitter(qubes.tests.QubesTestCase):
['testevent_1']) ['testevent_1'])
with self.subTest('fire_event_pre'): with self.subTest('fire_event_pre'):
effect = emitter.fire_event_pre('testevent') effect = emitter.fire_event('testevent', pre_event=True)
effect2 = emitter2.fire_event_pre('testevent') effect2 = emitter2.fire_event('testevent', pre_event=True)
self.assertEqual(list(effect), self.assertEqual(list(effect),
['testevent_2', 'testevent_1']) ['testevent_2', 'testevent_1'])
self.assertEqual(list(effect2), 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.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) start_guid=start_guid, mem_required=mem_required)
yield from self.storage.verify() yield from self.storage.verify()
@ -935,7 +936,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
if self.is_halted(): if self.is_halted():
raise qubes.exc.QubesVMNotStartedError(self) 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() self.libvirt_domain.shutdown()
@ -1071,7 +1072,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
raise qubes.exc.QubesVMError( raise qubes.exc.QubesVMError(
self, 'Domain {!r}: qrexec not connected'.format(self.name)) 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( return (yield from asyncio.create_subprocess_exec(
qubes.config.system_path['qrexec_client_path'], qubes.config.system_path['qrexec_client_path'],