From d61d24b055964cdc68639c7fd581cf708aebc373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Thu, 21 May 2020 05:03:25 +0200 Subject: [PATCH] Fire property-reset event when default value might change Those are only some cases, the most obvious ones: - defaults inherited from a template - xid and start_time on domain start/stop - IP related properties - icon QubesOS/qubes-issues#5834 --- qubes/ext/core_features.py | 4 +++ qubes/vm/mix/net.py | 53 ++++++++++++++++++++++++++++++++++++++ qubes/vm/qubesvm.py | 8 ++++++ qubes/vm/templatevm.py | 24 +++++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/qubes/ext/core_features.py b/qubes/ext/core_features.py index fc799353..f541e642 100644 --- a/qubes/ext/core_features.py +++ b/qubes/ext/core_features.py @@ -67,8 +67,12 @@ class CoreFeatures(qubes.ext.Extension): def set_servicevm_feature(self, subject): if getattr(subject, 'provides_network', False): subject.features['servicevm'] = 1 + # icon is calculated based on this feature + subject.fire_event('property-reset:icon', name='icon') elif 'servicevm' in subject.features: 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') def on_property_set(self, subject, event, name, newvalue, oldvalue=None): diff --git a/qubes/vm/mix/net.py b/qubes/vm/mix/net.py index 313261b0..77277d76 100644 --- a/qubes/vm/mix/net.py +++ b/qubes/vm/mix/net.py @@ -475,6 +475,59 @@ class NetVMMixin(qubes.events.Emitter): # pylint: disable=unused-argument 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') def on_domain_qdb_create(self, event): ''' Fills the QubesDB with firewall entries. ''' diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index 9fc300b7..aca16905 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -965,6 +965,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): else: 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') def on_property_pre_set_kernel(self, event, name, newvalue, oldvalue=None): # pylint: disable=unused-argument @@ -1142,6 +1145,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): self.libvirt_domain.createWithFlags( 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: # missing IOMMU? if self.virt_mode == 'hvm' and \ @@ -1250,6 +1256,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): except qubes.storage.StoragePoolException: self.log.exception('Failed to stop storage for domain %s', self.name) + self.fire_event('property-reset:xid', name='xid') + self.fire_event('property-reset:start_time', name='start_time') @asyncio.coroutine def shutdown(self, force=False, wait=False, timeout=None): diff --git a/qubes/vm/templatevm.py b/qubes/vm/templatevm.py index f63e2172..01ab5278 100644 --- a/qubes/vm/templatevm.py +++ b/qubes/vm/templatevm.py @@ -85,3 +85,27 @@ class TemplateVM(QubesVM): } } 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)