dom0/core: major rework of QubesVm.__init__ and serialization

No more manually set attributes, each in different way. Now there is one dict
with attrs, defaults, used also for object serialization to XML.
This commit is contained in:
Marek Marczykowski 2012-03-08 11:22:46 +01:00
parent 9360a18b0c
commit 8433931822

View File

@ -200,141 +200,141 @@ class QubesVm(object):
Note that qid is not the same as Xen's domid! Note that qid is not the same as Xen's domid!
""" """
def __init__(self, qid, name, def _get_attrs_config(self):
dir_path, conf_file = None, """ Object attributes for serialization/deserialization
uses_default_netvm = True, inner dict keys:
netvm = None, - order: initialization order (to keep dependency intact)
installed_by_rpm = False, attrs without order will be evaluated at the end
updateable = False, - default: default value used when attr not given to object constructor
label = None, - attr: set value to this attribute instead of parameter name
root_img = None, - eval: assign result of this expression instead of value directly;
private_img = None, local variable 'value' contains attribute value (or default if it was not given)
memory = default_memory, - save: use evaluation result as value for XML serialization; only attrs with 'save' key will be saved in XML
maxmem = None, - save_skip: if present and evaluates to true, attr will be omitted in XML
template_vm = None, - save_attr: save to this XML attribute instead of parameter name
firewall_conf = None, """
volatile_img = None,
pcidevs = None,
internal = False,
vcpus = None,
kernel = None,
uses_default_kernel = True,
kernelopts = "",
uses_default_kernelopts = True,
mac = None,
include_in_backups = True,
services = None):
attrs = {
assert qid < qubes_max_qid, "VM id out of bounds!" # __qid cannot be accessed by setattr, so must be set manually in __init__
self.__qid = qid "qid": { "attr": "_qid", "order": 0 },
self.name = name "name": { "order": 1 },
"dir_path": { "default": None, "order": 2 },
self.dir_path = dir_path "conf_file": { "eval": 'self.absolute_path(value, self.name + ".conf")', 'order': 3 },
# order >= 10: have base attrs set
self.conf_file = self.absolute_path(conf_file, name + ".conf") "root_img": { "eval": 'self.absolute_path(value, default_root_img)', 'order': 10 },
"private_img": { "eval": 'self.absolute_path(value, default_private_img)', 'order': 10 },
self.uses_default_netvm = uses_default_netvm "volatile_img": { "eval": 'self.absolute_path(value, default_volatile_img)', 'order': 10 },
self.netvm = netvm "firewall_conf": { "eval": 'self.absolute_path(value, default_firewall_conf_file)', 'order': 10 },
if netvm is not None: "installed_by_rpm": { "default": False, 'order': 10 },
netvm.connected_vms[qid] = self "updateable": { "default": False, 'order': 10 },
"template_vm": { "default": None, 'order': 10 },
self._mac = mac # order >= 20: have template set
"uses_default_netvm": { "default": True, 'order': 20 },
# We use it in remove from disk to avoid removing rpm files (for templates) "netvm": { "default": None, 'order': 20 },
self.installed_by_rpm = installed_by_rpm "label": { "attr": "_label", "default": QubesVmLabels["red"], 'order': 20 },
"memory": { "default": default_memory, 'order': 20 },
# Setup standard VM storage; some VM types may not use them all "maxmem": { "default": None, 'order': 20 },
self.root_img = self.absolute_path(root_img, default_root_img) "pcidevs": { "default": '[]', 'order': 20, "eval": \
'[] if value in ["none", None] else eval(value) if value.find("[") >= 0 else eval("[" + value + "]")' },
self.volatile_img = self.absolute_path(volatile_img, default_volatile_img) # Internal VM (not shown in qubes-manager, doesn't create appmenus entries
"internal": { "default": False },
self.private_img = self.absolute_path(private_img, default_private_img) "vcpus": { "default": None },
"kernel": { "default": None, 'eval': \
self.firewall_conf = self.absolute_path(firewall_conf, default_firewall_conf_file) 'self.template_vm.kernel if self.template_vm is not None else value' },
"uses_default_kernel": { "default": True },
self.updateable = updateable "uses_default_kernelopts": { "default": True },
self.include_in_backups = include_in_backups "kernelopts": { "default": "", "eval": \
'value if not self.uses_default_kernelopts else default_kernelopts_pcidevs if len(self.pcidevs) > 0 else default_kernelopts' },
self._label = label if label is not None else QubesVmLabels["red"] "mac": { "attr": "_mac", "default": None },
if self.dir_path is not None: "include_in_backups": { "default": True },
self.icon_path = self.dir_path + "/icon.png" "services": { "default": {}, "eval": "eval(str(value))" },
else: ##### Internal attributes - will be overriden in __init__ regardless of args
self.icon_path = None "appmenus_templates_dir": { "eval": \
'self.dir_path + "/" + default_appmenus_templates_subdir if self.updateable else ' + \
# PCI devices - used only by NetVM 'self.template_vm.appmenus_templates_dir if self.template_vm is not None else None' },
if pcidevs is None or pcidevs == "none": "config_file_template": { "eval": "config_template_pv" },
self.pcidevs = [] "icon_path": { "eval": 'self.dir_path + "/icon.png" if self.dir_path is not None else None' },
elif pcidevs.find('[') < 0: "kernels_dir": { 'eval': 'self.template_vm.kernels_dir if self.template_vm is not None else ' + \
# Backward compatibility 'qubes_kernels_base_dir + "/" + self.kernel if self.kernel is not None else ' + \
self.pcidevs = eval('[' + pcidevs + ']')
else:
self.pcidevs = eval(pcidevs)
self.memory = memory
if maxmem is None:
host = QubesHost()
total_mem_mb = host.memory_total/1024
self.maxmem = total_mem_mb/2
else:
self.maxmem = maxmem
self.template_vm = template_vm
if template_vm is not None:
if updateable:
print >> sys.stderr, "ERROR: Template based VM cannot be updateable!"
return False
if not template_vm.is_template():
print >> sys.stderr, "ERROR: template_qid={0} doesn't point to a valid TemplateVM".\
format(template_vm.qid)
return False
template_vm.appvms[qid] = self
else:
assert self.root_img is not None, "Missing root_img for standalone VM!"
self.kernel = kernel
if template_vm is not None:
self.kernels_dir = template_vm.kernels_dir
self.kernel = template_vm.kernel
elif self.kernel is not None:
self.kernels_dir = qubes_kernels_base_dir + "/" + self.kernel
else:
# for backward compatibility (or another rare case): kernel=None -> kernel in VM dir # for backward compatibility (or another rare case): kernel=None -> kernel in VM dir
self.kernels_dir = self.dir_path + "/" + default_kernels_subdir 'self.dir_path + "/" + default_kernels_subdir' },
}
self.uses_default_kernel = uses_default_kernel ### Mark attrs for XML inclusion
# Simple string attrs
for prop in ['qid', 'name', 'dir_path', 'memory', 'maxmem', 'pcidevs', 'vcpus', 'internal',\
'uses_default_kernel', 'kernel', 'uses_default_kernelopts',\
'kernelopts', 'services', 'updateable', 'installed_by_rpm',\
'uses_default_netvm', 'include_in_backups' ]:
attrs[prop]['save'] = 'str(self.%s)' % prop
# Simple paths
for prop in ['conf_file', 'root_img', 'volatile_img', 'private_img']:
attrs[prop]['save'] = 'self.relative_path(self.%s)' % prop
attrs[prop]['save_skip'] = 'self.%s is None' % prop
self.appmenus_templates_dir = None attrs['mac']['save'] = 'str(self._mac)'
if updateable: attrs['mac']['save_skip'] = 'self._mac is None'
self.appmenus_templates_dir = self.dir_path + "/" + default_appmenus_templates_subdir
elif template_vm is not None: attrs['netvm']['save'] = 'str(self.netvm.qid) if self.netvm is not None else "none"'
self.appmenus_templates_dir = template_vm.appmenus_templates_dir attrs['netvm']['save_attr'] = "netvm_qid"
attrs['template_vm']['save'] = 'str(self.template_vm.qid) if self.template_vm and not self.is_updateable() else "none"'
attrs['template_vm']['save_attr'] = "template_qid"
attrs['label']['save'] = 'self.label.name'
return attrs
def __init__(self, **kwargs):
attrs = self._get_attrs_config()
for attr_name in sorted(attrs, key=lambda _x: attrs[_x]['order'] if 'order' in attrs[_x] else 1000):
attr_config = attrs[attr_name]
attr = attr_name
if 'attr' in attr_config:
attr = attr_config['attr']
value = None
if attr_name not in kwargs:
if 'default' in attr_config:
value = attr_config['default']
else:
value = kwargs[attr_name]
if 'eval' in attr_config:
setattr(self, attr, eval(attr_config['eval']))
else:
#print "setting %s to %s" % (attr, value)
setattr(self, attr, value)
#Init private attrs
self.__qid = self._qid
assert self.__qid < qubes_max_qid, "VM id out of bounds!"
assert self.name is not None
if self.netvm is not None:
self.netvm.connected_vms[self.qid] = self
# Not in generic way to not create QubesHost() to frequently
if self.maxmem is None:
qubes_host = QubesHost()
total_mem_mb = qubes_host.memory_total/1024
self.maxmem = total_mem_mb/2
# By default allow use all VCPUs # By default allow use all VCPUs
if vcpus is None: if self.vcpus is None:
qubes_host = QubesHost() qubes_host = QubesHost()
self.vcpus = qubes_host.no_cpus self.vcpus = qubes_host.no_cpus
else:
self.vcpus = vcpus
self.uses_default_kernelopts = uses_default_kernelopts # Some additional checks for template based VM
if self.uses_default_kernelopts: if self.template_vm is not None:
if len(self.pcidevs) > 0: if self.updateable:
self.kernelopts = default_kernelopts_pcidevs print >> sys.stderr, "ERROR: Template based VM cannot be updateable!"
return False
if not self.template_vm.is_template():
print >> sys.stderr, "ERROR: template_qid={0} doesn't point to a valid TemplateVM".\
format(self.template_vm.qid)
return False
self.template_vm.appvms[self.qid] = self
else: else:
self.kernelopts = default_kernelopts assert self.root_img is not None, "Missing root_img for standalone VM!"
else:
self.kernelopts = kernelopts
self.services = {}
if services is not None:
self.services = eval(str(services))
# Internal VM (not shown in qubes-manager, doesn't create appmenus entries
self.internal = internal
self.xid = -1 self.xid = -1
self.xid = self.get_xid() self.xid = self.get_xid()
@ -485,7 +485,7 @@ class QubesVm(object):
self.appmenus_templates_dir = self.appmenus_templates_dir.replace(old_dirpath, new_dirpath) self.appmenus_templates_dir = self.appmenus_templates_dir.replace(old_dirpath, new_dirpath)
if self.icon_path is not None: if self.icon_path is not None:
self.icon_path = self.icon_path.replace(old_dirpath, new_dirpath) self.icon_path = self.icon_path.replace(old_dirpath, new_dirpath)
if self.kernels_dir is not None: if hasattr(self, 'kernels_dir') and self.kernels_dir is not None:
self.kernels_dir = self.kernels_dir.replace(old_dirpath, new_dirpath) self.kernels_dir = self.kernels_dir.replace(old_dirpath, new_dirpath)
self.post_rename(old_name) self.post_rename(old_name)
@ -1413,25 +1413,16 @@ class QubesVm(object):
def get_xml_attrs(self): def get_xml_attrs(self):
attrs = {} attrs = {}
attrs["qid"] = str(self.qid) attrs_config = self._get_attrs_config()
attrs["name"] = self.name for attr in attrs_config:
attrs["dir_path"] = self.dir_path attr_config = attrs_config[attr]
# Simple paths if 'save' in attr_config:
for prop in ['conf_file', 'root_img', 'volatile_img', 'private_img']: if 'save_skip' in attr_config and eval(attr_config['save_skip']):
if hasattr(self, prop): continue
attrs[prop] = self.relative_path(self.__getattribute__(prop)) if 'save_attr' in attr_config:
# Simple string attrs attrs[attr_config['save_attr']] = eval(attr_config['save'])
for prop in ['memory', 'maxmem', 'pcidevs', 'vcpus', 'internal',\ else:
'uses_default_kernel', 'kernel', 'uses_default_kernelopts',\ attrs[attr] = eval(attr_config['save'])
'kernelopts', 'services', 'updateable', 'installed_by_rpm',\
'uses_default_netvm', 'include_in_backups' ]:
if hasattr(self, prop):
attrs[prop] = str(self.__getattribute__(prop))
if self._mac is not None:
attrs["mac"] = str(self._mac)
attrs["netvm_qid"] = str(self.netvm.qid) if self.netvm is not None else "none"
attrs["template_qid"] = str(self.template_vm.qid) if self.template_vm and not self.is_updateable() else "none"
attrs["label"] = self.label.name
return attrs return attrs
def create_xml_element(self): def create_xml_element(self):