Merge branch 'rename-property-del-reset'

* rename-property-del-reset:
  Fire property-reset event when default value might change
  Convert handler to use property-reset instead of property-del
  Remove leftovers of default_fw_netvm
  Deprecate property-del:name events and introduce property-reset:name instead
This commit is contained in:
Marek Marczykowski-Górecki 2020-05-24 02:17:28 +02:00
commit eba628e90f
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
12 changed files with 158 additions and 37 deletions

View File

@ -284,6 +284,10 @@ class property: # pylint: disable=redefined-builtin,invalid-name
has_oldvalue = False has_oldvalue = False
if has_oldvalue: if has_oldvalue:
instance.fire_event('property-pre-reset:' + self.__name__,
pre_event=True,
name=self.__name__, oldvalue=oldvalue)
# deprecated, to be removed in Qubes 5.0
instance.fire_event('property-pre-del:' + self.__name__, instance.fire_event('property-pre-del:' + self.__name__,
pre_event=True, pre_event=True,
name=self.__name__, oldvalue=oldvalue) name=self.__name__, oldvalue=oldvalue)
@ -291,13 +295,23 @@ class property: # pylint: disable=redefined-builtin,invalid-name
delattr(instance, self._attr_name) delattr(instance, self._attr_name)
except AttributeError: except AttributeError:
pass pass
instance.fire_event('property-reset:' + self.__name__,
name=self.__name__, oldvalue=oldvalue)
# deprecated, to be removed in Qubes 5.0
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('property-pre-reset:' + self.__name__,
pre_event=True,
name=self.__name__)
# deprecated, to be removed in Qubes 5.0
instance.fire_event('property-pre-del:' + self.__name__, instance.fire_event('property-pre-del:' + self.__name__,
pre_event=True, pre_event=True,
name=self.__name__) name=self.__name__)
instance.fire_event('property-reset:' + self.__name__,
name=self.__name__)
# deprecated, to be removed in Qubes 5.0
instance.fire_event('property-del:' + self.__name__, instance.fire_event('property-del:' + self.__name__,
name=self.__name__) name=self.__name__)
@ -470,6 +484,9 @@ class PropertyHolder(qubes.events.Emitter):
Fired when property gets deleted (is set to default). Signature is Fired when property gets deleted (is set to default). Signature is
variable, *oldvalue* is present only if there was an old value. variable, *oldvalue* is present only if there was an old value.
This event is deprecated and will be removed in Qubes 5.0.
Use property-reset instead.
:param name: Property name :param name: Property name
:param oldvalue: Old value of the property :param oldvalue: Old value of the property
@ -479,6 +496,31 @@ class PropertyHolder(qubes.events.Emitter):
Fired before property gets deleted (is set to default). Signature Fired before property gets deleted (is set to default). Signature
is variable, *oldvalue* is present only if there was an old value. is variable, *oldvalue* is present only if there was an old value.
This event is deprecated and will be removed in Qubes 5.0.
Use property-pre-reset instead.
:param name: Property name
:param oldvalue: Old value of the property
.. event:: property-reset:<propname> \
(subject, event, name[, oldvalue])
Fired when property gets reset to the (possibly dynamic) default.
This even may be also fired when the property is already in
"default" state, but the calculated default value changes.
Signature is variable, *oldvalue* is present only if there was an
old value.
:param name: Property name
:param oldvalue: Old value of the property
.. event:: property-pre-reset:<propname> \
(subject, event, name[, oldvalue])
Fired before property gets reset to the (possibly dynamic) default.
Signature is variable, *oldvalue* is present only if there was an
old value.
:param name: Property name :param name: Property name
:param oldvalue: Old value of the property :param oldvalue: Old value of the property

View File

@ -1523,20 +1523,6 @@ class Qubes(qubes.PropertyHolder):
'is not running ({!r}).'.format( 'is not running ({!r}).'.format(
name, newvalue.name)) name, newvalue.name))
@qubes.events.handler('property-set:default_fw_netvm')
def on_property_set_default_fw_netvm(self, event, name, newvalue,
oldvalue=None):
# pylint: disable=unused-argument,invalid-name
for vm in self.domains:
if hasattr(vm, 'provides_network') and vm.provides_network and \
hasattr(vm, 'netvm') and vm.property_is_default('netvm'):
# fire property-del:netvm as it is responsible for resetting
# netvm to it's default value
vm.fire_event('property-pre-del:netvm', pre_event=True,
name='netvm', oldvalue=oldvalue)
vm.fire_event('property-del:netvm',
name='netvm', oldvalue=oldvalue)
@qubes.events.handler('property-set:default_netvm') @qubes.events.handler('property-set:default_netvm')
def on_property_set_default_netvm(self, event, name, newvalue, def on_property_set_default_netvm(self, event, name, newvalue,
oldvalue=None): oldvalue=None):
@ -1544,9 +1530,7 @@ class Qubes(qubes.PropertyHolder):
for vm in self.domains: for vm in self.domains:
if hasattr(vm, 'provides_network') and not vm.provides_network and \ if hasattr(vm, 'provides_network') and not vm.provides_network and \
hasattr(vm, 'netvm') and vm.property_is_default('netvm'): hasattr(vm, 'netvm') and vm.property_is_default('netvm'):
# fire property-del:netvm as it is responsible for resetting # fire property-reset:netvm as it is responsible for resetting
# netvm to it's default value # netvm to it's default value
vm.fire_event('property-pre-del:netvm', pre_event=True, vm.fire_event('property-reset:netvm',
name='netvm', oldvalue=oldvalue)
vm.fire_event('property-del:netvm',
name='netvm', oldvalue=oldvalue) name='netvm', oldvalue=oldvalue)

View File

@ -48,9 +48,8 @@ class AUDIO(qubes.ext.Extension):
self.on_property_set(vm, event, name='audiovm', self.on_property_set(vm, event, name='audiovm',
newvalue=vm.audiovm) newvalue=vm.audiovm)
# property-del <=> property-reset-to-default @qubes.ext.handler('property-reset:audiovm')
@qubes.ext.handler('property-del:audiovm') def on_property_reset(self, subject, event, name, oldvalue=None):
def on_property_del(self, subject, event, name, oldvalue=None):
newvalue = getattr(subject, 'audiovm', None) newvalue = getattr(subject, 'audiovm', None)
self.on_property_set(subject, event, name, newvalue, oldvalue) self.on_property_set(subject, event, name, newvalue, oldvalue)

View File

@ -67,16 +67,20 @@ class CoreFeatures(qubes.ext.Extension):
def set_servicevm_feature(self, subject): def set_servicevm_feature(self, subject):
if getattr(subject, 'provides_network', False): if getattr(subject, 'provides_network', False):
subject.features['servicevm'] = 1 subject.features['servicevm'] = 1
# icon is calculated based on this feature
subject.fire_event('property-reset:icon', name='icon')
elif 'servicevm' in subject.features: elif 'servicevm' in subject.features:
del subject.features['servicevm'] del subject.features['servicevm']
# icon is calculated based on this feature
subject.fire_event('property-reset:icon', name='icon')
@qubes.ext.handler('property-set:provides_network') @qubes.ext.handler('property-set:provides_network')
def on_property_set(self, subject, event, name, newvalue, oldvalue=None): def on_property_set(self, subject, event, name, newvalue, oldvalue=None):
# pylint: disable=unused-argument # pylint: disable=unused-argument
self.set_servicevm_feature(subject) self.set_servicevm_feature(subject)
@qubes.ext.handler('property-del:provides_network') @qubes.ext.handler('property-reset:provides_network')
def on_property_del(self, subject, event, name): def on_property_reset(self, subject, event, name):
# pylint: disable=unused-argument # pylint: disable=unused-argument
self.set_servicevm_feature(subject) self.set_servicevm_feature(subject)

View File

@ -58,9 +58,8 @@ class GUI(qubes.ext.Extension):
if 'guivm-' + vm.guivm.name not in vm.tags: if 'guivm-' + vm.guivm.name not in vm.tags:
self.on_property_set(vm, event, name='guivm', newvalue=vm.guivm) self.on_property_set(vm, event, name='guivm', newvalue=vm.guivm)
# property-del <=> property-reset-to-default @qubes.ext.handler('property-reset:guivm')
@qubes.ext.handler('property-del:guivm') def on_property_reset(self, subject, event, name, oldvalue=None):
def on_property_del(self, subject, event, name, oldvalue=None):
newvalue = getattr(subject, 'guivm', None) newvalue = getattr(subject, 'guivm', None)
self.on_property_set(subject, event, name, newvalue, oldvalue) self.on_property_set(subject, event, name, newvalue, oldvalue)

View File

@ -329,8 +329,8 @@ class Rule(qubes.PropertyHolder):
if newvalue not in ('icmp',): if newvalue not in ('icmp',):
self.icmptype = qubes.property.DEFAULT self.icmptype = qubes.property.DEFAULT
@qubes.events.handler('property-del:proto') @qubes.events.handler('property-reset:proto')
def on_del_proto(self, event, name, oldvalue): def on_reset_proto(self, event, name, oldvalue):
# pylint: disable=unused-argument # pylint: disable=unused-argument
self.dstports = qubes.property.DEFAULT self.dstports = qubes.property.DEFAULT
self.icmptype = qubes.property.DEFAULT self.icmptype = qubes.property.DEFAULT

View File

@ -170,8 +170,12 @@ class TC_10_property(qubes.tests.QubesTestCase):
self.assertEventFired(self.holder, 'property-pre-del:testprop1', self.assertEventFired(self.holder, 'property-pre-del:testprop1',
kwargs={'name': 'testprop1', 'oldvalue': 'testvalue'}) kwargs={'name': 'testprop1', 'oldvalue': 'testvalue'})
self.assertEventFired(self.holder, 'property-pre-reset:testprop1',
kwargs={'name': 'testprop1', 'oldvalue': 'testvalue'})
self.assertEventFired(self.holder, 'property-del:testprop1', self.assertEventFired(self.holder, 'property-del:testprop1',
kwargs={'name': 'testprop1', 'oldvalue': 'testvalue'}) kwargs={'name': 'testprop1', 'oldvalue': 'testvalue'})
self.assertEventFired(self.holder, 'property-reset:testprop1',
kwargs={'name': 'testprop1', 'oldvalue': 'testvalue'})
def test_081_delete_by_assign(self): def test_081_delete_by_assign(self):
self.holder.testprop1 = 'testvalue' self.holder.testprop1 = 'testvalue'
@ -203,8 +207,12 @@ class TC_10_property(qubes.tests.QubesTestCase):
self.assertEqual(holder.testprop1, 'defaultvalue') self.assertEqual(holder.testprop1, 'defaultvalue')
self.assertEventFired(holder, 'property-pre-del:testprop1', kwargs={ self.assertEventFired(holder, 'property-pre-del:testprop1', kwargs={
'name': 'testprop1', 'oldvalue': 'testvalue'}) 'name': 'testprop1', 'oldvalue': 'testvalue'})
self.assertEventFired(holder, 'property-pre-reset:testprop1', kwargs={
'name': 'testprop1', 'oldvalue': 'testvalue'})
self.assertEventFired(holder, 'property-del:testprop1', kwargs={ self.assertEventFired(holder, 'property-del:testprop1', kwargs={
'name': 'testprop1', 'oldvalue': 'testvalue'}) 'name': 'testprop1', 'oldvalue': 'testvalue'})
self.assertEventFired(holder, 'property-reset:testprop1', kwargs={
'name': 'testprop1', 'oldvalue': 'testvalue'})
def test_090_write_once_set(self): def test_090_write_once_set(self):
class MyTestHolder(qubes.tests.TestEmitter, qubes.PropertyHolder): class MyTestHolder(qubes.tests.TestEmitter, qubes.PropertyHolder):

View File

@ -112,8 +112,8 @@ class AppVM(qubes.vm.qubesvm.QubesVM):
''' # pylint: disable=unused-argument ''' # pylint: disable=unused-argument
assert self.template assert self.template
@qubes.events.handler('property-pre-del:template') @qubes.events.handler('property-pre-reset:template')
def on_property_pre_del_template(self, event, name, oldvalue=None): def on_property_pre_reset_template(self, event, name, oldvalue=None):
'''Forbid deleting template of running VM '''Forbid deleting template of running VM
''' # pylint: disable=unused-argument,no-self-use ''' # pylint: disable=unused-argument,no-self-use
raise qubes.exc.QubesValueError('Cannot unset template') raise qubes.exc.QubesValueError('Cannot unset template')

View File

@ -134,7 +134,7 @@ class DispVM(qubes.vm.qubesvm.QubesVM):
assert self.template assert self.template
@qubes.events.handler('property-pre-set:template', @qubes.events.handler('property-pre-set:template',
'property-pre-del:template') 'property-pre-reset:template')
def on_property_pre_set_template(self, event, name, newvalue=None, def on_property_pre_set_template(self, event, name, newvalue=None,
oldvalue=None): oldvalue=None):
''' Disposable VM cannot have template changed ''' ''' Disposable VM cannot have template changed '''

View File

@ -406,8 +406,8 @@ class NetVMMixin(qubes.events.Emitter):
'/connected-ips6', '/connected-ips6',
' '.join(connected_ips6)) ' '.join(connected_ips6))
@qubes.events.handler('property-pre-del:netvm') @qubes.events.handler('property-pre-reset:netvm')
def on_property_pre_del_netvm(self, event, name, oldvalue=None): def on_property_pre_reset_netvm(self, event, name, oldvalue=None):
''' Sets the the NetVM to default NetVM ''' ''' Sets the the NetVM to default NetVM '''
# pylint: disable=unused-argument # pylint: disable=unused-argument
# we are changing to default netvm # we are changing to default netvm
@ -419,8 +419,8 @@ class NetVMMixin(qubes.events.Emitter):
self.fire_event('property-pre-set:netvm', pre_event=True, self.fire_event('property-pre-set:netvm', pre_event=True,
name='netvm', newvalue=newvalue, oldvalue=oldvalue) name='netvm', newvalue=newvalue, oldvalue=oldvalue)
@qubes.events.handler('property-del:netvm') @qubes.events.handler('property-reset:netvm')
def on_property_del_netvm(self, event, name, oldvalue=None): def on_property_reset_netvm(self, event, name, oldvalue=None):
''' Sets the the NetVM to default NetVM ''' ''' Sets the the NetVM to default NetVM '''
# pylint: disable=unused-argument # pylint: disable=unused-argument
# we are changing to default netvm # we are changing to default netvm
@ -475,6 +475,59 @@ class NetVMMixin(qubes.events.Emitter):
# pylint: disable=unused-argument # pylint: disable=unused-argument
self.reload_firewall_for_vm(vm) self.reload_firewall_for_vm(vm)
@qubes.events.handler('property-set:ip', 'property-reset:ip')
def on_property_set_ip(self, _event, name, newvalue=None, oldvalue=None):
# pylint: disable=unused-argument
if newvalue == oldvalue:
return
if self.provides_network:
self.fire_event('property-reset:gateway', name='gateway')
self.fire_event('property-reset:visible_ip', name='visible_ip')
for vm in self.connected_vms:
vm.fire_event(
'property-reset:visible_gateway', name='visible_gateway')
@qubes.events.handler('property-set:ip6', 'property-reset:ipv6')
def on_property_set_ip6(self, _event, name, newvalue=None, oldvalue=None):
# pylint: disable=unused-argument
if newvalue == oldvalue:
return
if self.provides_network:
self.fire_event('property-reset:gateway6', name='gateway6')
self.fire_event('property-reset:visible_ip6', name='visible_ip6')
for vm in self.connected_vms:
vm.fire_event(
'property-reset:visible_gateway6', name='visible_gateway6')
@qubes.events.handler('feature-set:net.fake-ip')
def on_feature_set_net_fake_ip(self, event, name, newvalue, oldvalue=None):
# pylint: disable=unused-argument
if oldvalue == newvalue:
return
self.fire_event('property-reset:visible_ip', name='visible_ip')
for vm in self.connected_vms:
vm.fire_event(
'property-reset:visible_gateway', name='visible_gateway')
@qubes.events.handler('feature-set:ipv6')
def on_feature_set_ipv6(self, event, name, newvalue, oldvalue=None):
# pylint: disable=unused-argument
if oldvalue == newvalue:
return
self.fire_event('property-reset:visible_ip6', name='visible_ip6')
for vm in self.connected_vms:
vm.fire_event(
'property-reset:visible_gateway6', name='visible_gateway6')
@qubes.events.handler('property-set:provides_network')
def on_property_set_provides(
self, _event, name, newvalue, oldvalue=None):
# pylint: disable=unused-argument
if newvalue == oldvalue:
return
self.fire_event('property-reset:gateway', name='gateway')
self.fire_event('property-reset:gateway6', name='gateway6')
@qubes.events.handler('domain-qdb-create') @qubes.events.handler('domain-qdb-create')
def on_domain_qdb_create(self, event): def on_domain_qdb_create(self, event):
''' Fills the QubesDB with firewall entries. ''' ''' Fills the QubesDB with firewall entries. '''

View File

@ -965,6 +965,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
else: else:
shutil.copy(newvalue.icon_path, self.icon_path) shutil.copy(newvalue.icon_path, self.icon_path)
# icon is calculated based on label
self.fire_event('property-reset:icon', name='icon')
@qubes.events.handler('property-pre-set:kernel') @qubes.events.handler('property-pre-set:kernel')
def on_property_pre_set_kernel(self, event, name, newvalue, oldvalue=None): def on_property_pre_set_kernel(self, event, name, newvalue, oldvalue=None):
# pylint: disable=unused-argument # pylint: disable=unused-argument
@ -1006,8 +1009,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
raise qubes.exc.QubesException( raise qubes.exc.QubesException(
'Failed to set autostart for VM in systemd') 'Failed to set autostart for VM in systemd')
@qubes.events.handler('property-pre-del:autostart') @qubes.events.handler('property-pre-reset:autostart')
def on_property_pre_del_autostart(self, event, name, oldvalue=None): def on_property_pre_reset_autostart(self, event, name, oldvalue=None):
# pylint: disable=unused-argument # pylint: disable=unused-argument
if oldvalue: if oldvalue:
retcode = subprocess.call( retcode = subprocess.call(
@ -1142,6 +1145,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
self.libvirt_domain.createWithFlags( self.libvirt_domain.createWithFlags(
libvirt.VIR_DOMAIN_START_PAUSED) libvirt.VIR_DOMAIN_START_PAUSED)
# the above allocates xid, lets announce that
self.fire_event('property-reset:xid', name='xid')
self.fire_event('property-reset:start_time', name='start_time')
except libvirt.libvirtError as exc: except libvirt.libvirtError as exc:
# missing IOMMU? # missing IOMMU?
if self.virt_mode == 'hvm' and \ if self.virt_mode == 'hvm' and \
@ -1250,6 +1256,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
except qubes.storage.StoragePoolException: except qubes.storage.StoragePoolException:
self.log.exception('Failed to stop storage for domain %s', self.log.exception('Failed to stop storage for domain %s',
self.name) self.name)
self.fire_event('property-reset:xid', name='xid')
self.fire_event('property-reset:start_time', name='start_time')
@asyncio.coroutine @asyncio.coroutine
def shutdown(self, force=False, wait=False, timeout=None): def shutdown(self, force=False, wait=False, timeout=None):

View File

@ -85,3 +85,27 @@ class TemplateVM(QubesVM):
} }
} }
super(TemplateVM, self).__init__(*args, **kwargs) super(TemplateVM, self).__init__(*args, **kwargs)
@qubes.events.handler('property-set:default_user',
'property-set:kernel',
'property-set:kernelopts',
'property-set:vcpus',
'property-set:memory',
'property-set:maxmem',
'property-set:qrexec_timeout',
'property-set:shutdown_timeout',
'property-set:management_dispvm')
def on_property_set_child(self, _event, name, newvalue, oldvalue=None):
"""Send event about default value change to child VMs
(which use default inherited from the template).
This handler is supposed to be set for properties using
`_default_with_template()` function for the default value.
"""
if newvalue == oldvalue:
return
for vm in self.appvms:
if not vm.property_is_default(name):
continue
vm.fire_event('property-reset:' + name, name=name)