QubesVm: introduce hooks for plugins
Besides introducing new VM classes, plugins may influence existing VM behavior. Introduce convenient hooks for it. Without those hooks it still was possible, but in much less correct way - overriding class methods from plugin module.
This commit is contained in:
parent
3ec6d3d237
commit
471896f38f
@ -51,6 +51,23 @@ class QubesVm(object):
|
|||||||
# In which order load this VM type from qubes.xml
|
# In which order load this VM type from qubes.xml
|
||||||
load_order = 100
|
load_order = 100
|
||||||
|
|
||||||
|
# hooks for plugins (modules) which want to influence existing classes,
|
||||||
|
# without introducing new ones
|
||||||
|
hooks_clone_disk_files = []
|
||||||
|
hooks_create_on_disk = []
|
||||||
|
hooks_create_xenstore_entries = []
|
||||||
|
hooks_get_attrs_config = []
|
||||||
|
hooks_get_clone_attrs = []
|
||||||
|
hooks_get_config_params = []
|
||||||
|
hooks_init = []
|
||||||
|
hooks_label_setter = []
|
||||||
|
hooks_netvm_setter = []
|
||||||
|
hooks_post_rename = []
|
||||||
|
hooks_pre_rename = []
|
||||||
|
hooks_remove_from_disk = []
|
||||||
|
hooks_start = []
|
||||||
|
hooks_verify_files = []
|
||||||
|
|
||||||
def get_attrs_config(self):
|
def get_attrs_config(self):
|
||||||
""" Object attributes for serialization/deserialization
|
""" Object attributes for serialization/deserialization
|
||||||
inner dict keys:
|
inner dict keys:
|
||||||
@ -138,6 +155,9 @@ class QubesVm(object):
|
|||||||
attrs['template']['save_attr'] = "template_qid"
|
attrs['template']['save_attr'] = "template_qid"
|
||||||
attrs['label']['save'] = 'self.label.name'
|
attrs['label']['save'] = 'self.label.name'
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_get_attrs_config:
|
||||||
|
attrs = hook(self, attrs)
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def __basic_parse_xml_attr(self, value):
|
def __basic_parse_xml_attr(self, value):
|
||||||
@ -236,6 +256,10 @@ class QubesVm(object):
|
|||||||
self.xid = -1
|
self.xid = -1
|
||||||
self.xid = self.get_xid()
|
self.xid = self.get_xid()
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_init:
|
||||||
|
hook(self)
|
||||||
|
|
||||||
def absolute_path(self, arg, default):
|
def absolute_path(self, arg, default):
|
||||||
if arg is not None and os.path.isabs(arg):
|
if arg is not None and os.path.isabs(arg):
|
||||||
return arg
|
return arg
|
||||||
@ -264,6 +288,10 @@ class QubesVm(object):
|
|||||||
os.symlink (new_label.icon_path, self.icon_path)
|
os.symlink (new_label.icon_path, self.icon_path)
|
||||||
subprocess.call(['sudo', 'xdg-icon-resource', 'forceupdate'])
|
subprocess.call(['sudo', 'xdg-icon-resource', 'forceupdate'])
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_label_setter:
|
||||||
|
hook(self, new_label)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def netvm(self):
|
def netvm(self):
|
||||||
return self._netvm
|
return self._netvm
|
||||||
@ -272,6 +300,9 @@ class QubesVm(object):
|
|||||||
@netvm.setter
|
@netvm.setter
|
||||||
def netvm(self, new_netvm):
|
def netvm(self, new_netvm):
|
||||||
self._set_netvm(new_netvm)
|
self._set_netvm(new_netvm)
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_netvm_setter:
|
||||||
|
hook(self, new_netvm)
|
||||||
|
|
||||||
def _set_netvm(self, new_netvm):
|
def _set_netvm(self, new_netvm):
|
||||||
if self.is_running() and new_netvm is not None and not new_netvm.is_running():
|
if self.is_running() and new_netvm is not None and not new_netvm.is_running():
|
||||||
@ -375,6 +406,10 @@ class QubesVm(object):
|
|||||||
def pre_rename(self, new_name):
|
def pre_rename(self, new_name):
|
||||||
self.remove_appmenus()
|
self.remove_appmenus()
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_pre_rename:
|
||||||
|
hook(self, new_name)
|
||||||
|
|
||||||
def set_name(self, name):
|
def set_name(self, name):
|
||||||
if self.is_running():
|
if self.is_running():
|
||||||
raise QubesException("Cannot change name of running VM!")
|
raise QubesException("Cannot change name of running VM!")
|
||||||
@ -413,6 +448,10 @@ class QubesVm(object):
|
|||||||
def post_rename(self, old_name):
|
def post_rename(self, old_name):
|
||||||
self.create_appmenus(verbose=False)
|
self.create_appmenus(verbose=False)
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_post_rename:
|
||||||
|
hook(self, old_name)
|
||||||
|
|
||||||
def is_template(self):
|
def is_template(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -775,6 +814,10 @@ class QubesVm(object):
|
|||||||
xs.set_permissions('', '{0}/qubes-usb-devices'.format(domain_path),
|
xs.set_permissions('', '{0}/qubes-usb-devices'.format(domain_path),
|
||||||
[{ 'dom': xid }])
|
[{ 'dom': xid }])
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_create_xenstore_entries:
|
||||||
|
hook(self, xid=xid)
|
||||||
|
|
||||||
def get_rootdev(self, source_template=None):
|
def get_rootdev(self, source_template=None):
|
||||||
if self.template:
|
if self.template:
|
||||||
return "'script:snapshot:{dir}/root.img:{dir}/root-cow.img,xvda,r',".format(dir=self.template.dir_path)
|
return "'script:snapshot:{dir}/root.img:{dir}/root-cow.img,xvda,r',".format(dir=self.template.dir_path)
|
||||||
@ -831,6 +874,10 @@ class QubesVm(object):
|
|||||||
print >> sys.stderr, "--> Debug mode: adding 'earlyprintk=xen' to kernel opts"
|
print >> sys.stderr, "--> Debug mode: adding 'earlyprintk=xen' to kernel opts"
|
||||||
args['kernelopts'] += ' earlyprintk=xen'
|
args['kernelopts'] += ' earlyprintk=xen'
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_get_config_params:
|
||||||
|
args = hook(self, args)
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -948,12 +995,19 @@ class QubesVm(object):
|
|||||||
subprocess.check_call ([system_path["qubes_appmenu_create_cmd"], "none", self.name, vmtype])
|
subprocess.check_call ([system_path["qubes_appmenu_create_cmd"], "none", self.name, vmtype])
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
print >> sys.stderr, "Ooops, there was a problem creating appmenus for {0} VM!".format (self.name)
|
print >> sys.stderr, "Ooops, there was a problem creating appmenus for {0} VM!".format (self.name)
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_create_on_disk:
|
||||||
|
hook(self, verbose, source_template=source_template)
|
||||||
|
|
||||||
def get_clone_attrs(self):
|
def get_clone_attrs(self):
|
||||||
return ['kernel', 'uses_default_kernel', 'netvm', 'uses_default_netvm', \
|
attrs = ['kernel', 'uses_default_kernel', 'netvm', 'uses_default_netvm', \
|
||||||
'memory', 'maxmem', 'kernelopts', 'uses_default_kernelopts', 'services', 'vcpus', \
|
'memory', 'maxmem', 'kernelopts', 'uses_default_kernelopts', 'services', 'vcpus', \
|
||||||
'_mac', 'pcidevs', 'include_in_backups', '_label']
|
'_mac', 'pcidevs', 'include_in_backups', '_label']
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_get_clone_attrs:
|
||||||
|
attrs = hook(self, attrs)
|
||||||
|
|
||||||
def clone_attrs(self, src_vm):
|
def clone_attrs(self, src_vm):
|
||||||
self._do_not_reset_firewall = True
|
self._do_not_reset_firewall = True
|
||||||
for prop in self.get_clone_attrs():
|
for prop in self.get_clone_attrs():
|
||||||
@ -1019,6 +1073,10 @@ class QubesVm(object):
|
|||||||
# Create appmenus
|
# Create appmenus
|
||||||
self.create_appmenus(verbose=verbose)
|
self.create_appmenus(verbose=verbose)
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_clone_disk_files:
|
||||||
|
hook(self, verbose, src_vm)
|
||||||
|
|
||||||
def remove_appmenus(self):
|
def remove_appmenus(self):
|
||||||
vmtype = None
|
vmtype = None
|
||||||
if self.is_netvm():
|
if self.is_netvm():
|
||||||
@ -1060,6 +1118,11 @@ class QubesVm(object):
|
|||||||
raise QubesException (
|
raise QubesException (
|
||||||
"VM kernel modules image does not exists: {0}".\
|
"VM kernel modules image does not exists: {0}".\
|
||||||
format(os.path.join(self.kernels_dir, 'modules.img')))
|
format(os.path.join(self.kernels_dir, 'modules.img')))
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_verify_files:
|
||||||
|
hook(self)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def reset_volatile_storage(self, source_template = None, verbose = False):
|
def reset_volatile_storage(self, source_template = None, verbose = False):
|
||||||
@ -1097,6 +1160,10 @@ class QubesVm(object):
|
|||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_remove_from_disk:
|
||||||
|
hook(self)
|
||||||
|
|
||||||
shutil.rmtree (self.dir_path)
|
shutil.rmtree (self.dir_path)
|
||||||
|
|
||||||
def write_firewall_conf(self, conf):
|
def write_firewall_conf(self, conf):
|
||||||
@ -1423,6 +1490,11 @@ class QubesVm(object):
|
|||||||
if vm.is_proxyvm() and vm.is_running():
|
if vm.is_proxyvm() and vm.is_running():
|
||||||
vm.write_iptables_xenstore_entry()
|
vm.write_iptables_xenstore_entry()
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_start:
|
||||||
|
hook(self, verbose = verbose, preparing_dvm = preparing_dvm,
|
||||||
|
start_guid = start_guid, notify_function = notify_function)
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
print >> sys.stderr, "--> Starting the VM..."
|
print >> sys.stderr, "--> Starting the VM..."
|
||||||
xc.domain_unpause(xid)
|
xc.domain_unpause(xid)
|
||||||
|
@ -134,6 +134,10 @@ class QubesHVm(QubesVm):
|
|||||||
f_private.truncate(defaults["hvm_private_img_size"])
|
f_private.truncate(defaults["hvm_private_img_size"])
|
||||||
f_root.close()
|
f_root.close()
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_create_on_disk:
|
||||||
|
hook(self, verbose, source_template=source_template)
|
||||||
|
|
||||||
def remove_from_disk(self):
|
def remove_from_disk(self):
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
@ -218,6 +222,10 @@ class QubesHVm(QubesVm):
|
|||||||
f_private.truncate(defaults["hvm_private_img_size"])
|
f_private.truncate(defaults["hvm_private_img_size"])
|
||||||
f_private.close()
|
f_private.close()
|
||||||
|
|
||||||
|
# fire hooks
|
||||||
|
for hook in self.hooks_verify_files:
|
||||||
|
hook(self)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def reset_volatile_storage(self, **kwargs):
|
def reset_volatile_storage(self, **kwargs):
|
||||||
|
Loading…
Reference in New Issue
Block a user