From ceed4507eb0872249970a46d780466eb6494a611 Mon Sep 17 00:00:00 2001 From: Marek Marczykowski Date: Fri, 9 Mar 2012 01:52:28 +0100 Subject: [PATCH] dom0/qvm-network: implement dynamic switching in property setter (#478) Also add to it missing parts: firewall reload and netid attr set (+perms for it) --- dom0/qvm-core/qubes.py | 81 +++++++++++++++++++++++++++++++--------- dom0/qvm-tools/qvm-prefs | 13 +------ 2 files changed, 64 insertions(+), 30 deletions(-) diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index 2d8ae4c9..9f826829 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -232,7 +232,7 @@ class QubesVm(object): "template_vm": { "default": None, 'order': 10 }, # order >= 20: have template set "uses_default_netvm": { "default": True, 'order': 20 }, - "netvm": { "default": None, 'order': 20 }, + "netvm": { "default": None, "attr": "_netvm", 'order': 20 }, "label": { "attr": "_label", "default": QubesVmLabels["red"], 'order': 20 }, "memory": { "default": default_memory, 'order': 20 }, "maxmem": { "default": None, 'order': 25 }, @@ -369,6 +369,47 @@ class QubesVm(object): os.symlink (new_label.icon_path, self.icon_path) subprocess.call(['sudo', 'xdg-icon-resource', 'forceupdate']) + @property + def netvm(self): + return self._netvm + + # Don't know how properly call setter from base class, so workaround it... + @netvm.setter + def netvm(self, new_netvm): + self._set_netvm(new_netvm) + + def _set_netvm(self, new_netvm): + if self.netvm is not None: + self.netvm.connected_vms.pop(self.qid) + if self.is_running(): + subprocess.call(["xl", "network-detach", self.name, "0"], stderr=subprocess.PIPE) + if hasattr(self.netvm, 'post_vm_net_detach'): + self.netvm.post_vm_net_detach(self) + + if new_netvm is None: + # Set also firewall to block all traffic as discussed in #370 + if os.path.exists(self.firewall_conf): + shutil.copy(self.firewall_conf, "%s/backup/%s-firewall-%s.xml" + % (qubes_base_dir, self.name, time.strftime('%Y-%m-%d-%H:%M:%S'))) + self.write_firewall_conf({'allow': False, 'allowDns': False, + 'allowIcmp': False, 'rules': []}) + else: + new_netvm.connected_vms[self.qid]=self + + self._netvm = new_netvm + + if new_netvm is None: + return + + if self.is_running(): + if not new_netvm.is_running(): + new_netvm.start() + # refresh IP, DNS etc + self.create_xenstore_entries() + self.attach_network() + if hasattr(self.netvm, 'post_vm_net_attach'): + self.netvm.post_vm_net_attach(self) + @property def ip(self): if self.netvm is not None: @@ -441,22 +482,6 @@ class QubesVm(object): raise QubesException ("Change 'updateable' flag is not supported. Please use qvm-create.") - def set_netvm(self, netvm): - if self.netvm is not None: - self.netvm.connected_vms.pop(self.qid) - - if netvm is None: - # Set also firewall to block all traffic as discussed in #370 - if os.path.exists(self.firewall_conf): - shutil.copy(self.firewall_conf, "%s/backup/%s-firewall-%s.xml" - % (qubes_base_dir, self.name, time.strftime('%Y-%m-%d-%H:%M:%S'))) - self.write_firewall_conf({'allow': False, 'allowDns': False, - 'allowIcmp': False, 'rules': []}) - else: - netvm.connected_vms[self.qid]=self - - self.netvm = netvm - def pre_rename(self, new_name): pass @@ -1811,6 +1836,25 @@ class QubesProxyVm(QubesNetVm): def type(self): return "ProxyVM" + def _set_netvm(self, new_netvm): + old_netvm = self.netvm + super(QubesProxyVm, self)._set_netvm(new_netvm) + if self.netvm is not None: + self.netvm.add_external_ip_permission(self.get_xid()) + self.write_netvm_domid_entry() + if old_netvm is not None: + old_netvm.remove_external_ip_permission(self.get_xid()) + + def post_vm_net_attach(self, vm): + """ Called after some VM net-attached to this ProxyVm """ + + self.write_iptables_xenstore_entry() + + def post_vm_net_detach(self, vm): + """ Called after some VM net-detached from this ProxyVm """ + + self.write_iptables_xenstore_entry() + def start(self, debug_console = False, verbose = False, preparing_dvm = False): if dry_run: return @@ -2530,7 +2574,8 @@ class QubesVmCollection(dict): else: netvm = self[netvm_qid] - vm.netvm = netvm + # directly set internal attr to not call setters... + vm._netvm = netvm if netvm: netvm.connected_vms[vm.qid] = vm diff --git a/dom0/qvm-tools/qvm-prefs b/dom0/qvm-tools/qvm-prefs index 7fc55c4f..08d06156 100755 --- a/dom0/qvm-tools/qvm-prefs +++ b/dom0/qvm-tools/qvm-prefs @@ -150,18 +150,7 @@ def set_netvm(vms, vm, args): exit (1) vm.uses_default_netvm = False - vm.set_netvm(netvm) - if not vm.is_running(): - return - # this can fail if VM was not connected to any NetVM - subprocess.call(["xl", "network-detach", vm.name, "0"], stderr=subprocess.PIPE) - if vm.netvm is None: - return - if not vm.netvm.is_running(): - subprocess.check_call(["qvm-start", vm.netvm.name]) - # refresh IP, DNS etc - vm.create_xenstore_entries() - vm.attach_network(verbose = True) + vm.netvm = netvm def set_updateable(vms, vm, args): if vm.is_updateable():