From 6dd0870ca6166014404cec058cdf19466ec645e8 Mon Sep 17 00:00:00 2001 From: Marek Marczykowski Date: Mon, 6 Jun 2011 01:43:52 +0200 Subject: [PATCH] dom0: Generate Xen VM config file from common template, on each VM start Do not use many different config templates for different types of VMs. Also regenerate config on each VM start to keep in synchronized with qubes.xml --- dom0/misc/vm-template.conf | 28 +++++++ dom0/qvm-core/qubes.py | 160 +++++++++++-------------------------- 2 files changed, 73 insertions(+), 115 deletions(-) create mode 100644 dom0/misc/vm-template.conf diff --git a/dom0/misc/vm-template.conf b/dom0/misc/vm-template.conf new file mode 100644 index 00000000..df138c85 --- /dev/null +++ b/dom0/misc/vm-template.conf @@ -0,0 +1,28 @@ +# +# This is a Xen VM config file for Qubes VM +# DO NOT EDIT - autogenerated by qubes tools +# + +kernel="{kerneldir}/vmlinuz" +ramdisk="{kerneldir}/initramfs" +extra="ro nomodeset xencons=hvc rd_NO_PLYMOUTH 3 {kernelopts}" +root="/dev/mapper/dmroot" + +memory = {mem} +maxmem = {maxmem} +name = "{name}" + +disk = [ {rootdev} + {privatedev} + {volatiledev} + ] + +vif = [ {netdev} ] + +pci = [ {pcidev} ] + +vcpus = {vcpus} + +on_poweroff = 'destroy' +on_reboot = 'destroy' +on_crash = 'destroy' diff --git a/dom0/qvm-core/qubes.py b/dom0/qvm-core/qubes.py index d9e7d101..15dba02f 100755 --- a/dom0/qvm-core/qubes.py +++ b/dom0/qvm-core/qubes.py @@ -68,10 +68,6 @@ default_rootcow_img = "root-cow.img" default_volatile_img = "volatile.img" default_clean_volatile_img = "clean-volatile.img.tar" default_private_img = "private.img" -default_appvms_conf_file = "appvm-template.conf" -default_netvms_conf_file = "netvm-template.conf" -default_standalonevms_conf_file = "standalone-template.conf" -default_templatevm_conf_template = "templatevm.conf" # needed for TemplateVM cloning default_appmenus_templates_subdir = "apps.templates" default_appmenus_template_templates_subdir = "apps-template.templates" default_kernels_subdir = "kernels" @@ -623,38 +619,43 @@ class QubesVm(object): [{ 'dom': xid }]) xs.transaction_end(xs_trans) - def create_config_file(self, source_template = None): + def get_rootdev(self, source_template=None): + if self.template_vm: + return "'script:snapshot:{dir}/root.img:{dir}/root-cow.img,xvda,r',".format(dir=self.template_vm.dir_path) + else: + return "'script:file:{dir}/root.img,xvda,w',".format(dir=self.dir_path) + + def get_config_params(self, source_template=None): + args = {} + args['name'] = self.name + args['kerneldir'] = self.kernels_dir + args['vmdir'] = self.dir_path + args['pcidev'] = self.pcidevs + args['mem'] = str(self.memory) + args['maxmem'] = str(self.maxmem) + args['vcpus'] = str(self.vcpus) + args['netdev'] = '' + args['rootdev'] = self.get_rootdev(source_template=source_template) + args['privatedev'] = "'script:file:{dir}/private.img,xvdb,w',".format(dir=self.dir_path) + args['volatiledev'] = "'script:file:{dir}/volatile.img,xvdc,w',".format(dir=self.dir_path) + args['kernelopts'] = '' + + return args + + def create_config_file(self, file_path = None, source_template = None): + if file_path is None: + file_path = self.conf_file if source_template is None: source_template = self.template_vm - assert source_template is not None - conf_template = None - if self.type == "NetVM": - conf_template = open (source_template.netvms_conf_file, "r") - elif self.updateable: - conf_template = open (source_template.standalonevms_conf_file, "r") - else: - conf_template = open (source_template.appvms_conf_file, "r") - if os.path.isfile(self.conf_file): - shutil.copy(self.conf_file, self.conf_file + ".backup") + f_conf_template = open('/usr/share/qubes/vm-template.conf', 'r') + conf_template = f_conf_template.read() + f_conf_template.close() + + template_params = self.get_config_params(source_template) conf_appvm = open(self.conf_file, "w") - rx_vmname = re.compile (r"%VMNAME%") - rx_vmdir = re.compile (r"%VMDIR%") - rx_template = re.compile (r"%TEMPLATEDIR%") - rx_pcidevs = re.compile (r"%PCIDEVS%") - rx_mem = re.compile (r"%MEM%") - rx_vcpus = re.compile (r"%VCPUS%") - for line in conf_template: - line = rx_vmname.sub (self.name, line) - line = rx_vmdir.sub (self.dir_path, line) - line = rx_template.sub (source_template.dir_path, line) - line = rx_pcidevs.sub (self.pcidevs, line) - line = rx_mem.sub (str(self.memory), line) - line = rx_vcpus.sub (str(self.vcpus), line) - conf_appvm.write(line) - - conf_template.close() + conf_appvm.write(conf_template.format(**template_params)) conf_appvm.close() def create_on_disk(self, verbose, source_template = None): @@ -729,11 +730,6 @@ class QubesVm(object): "VM directory doesn't exist: {0}".\ format(self.dir_path)) - if not os.path.exists (self.conf_file): - raise QubesException ( - "VM config file doesn't exist: {0}".\ - format(self.conf_file)) - if self.is_updateable() and not os.path.exists (self.root_img): raise QubesException ( "VM root image file doesn't exist: {0}".\ @@ -869,6 +865,9 @@ class QubesVm(object): if verbose: print "--> Loading the VM (type = {0})...".format(self.type) + # refresh config file + self.create_config_file() + limit_memlock = resource.getrlimit(resource.RLIMIT_MEMLOCK) # try to increase limit if needed if limit_memlock[0] < int(self.memory) * 1024: @@ -884,8 +883,6 @@ class QubesVm(object): raise MemoryError ("ERROR: insufficient memory to start this VM") xl_cmdline = ['/usr/sbin/xl', 'create', self.conf_file, '-p'] - if not self.is_netvm(): - xl_cmdline += ['maxmem={0}'.format(self.maxmem)] try: subprocess.check_call(xl_cmdline) @@ -1016,10 +1013,6 @@ class QubesTemplateVm(QubesVm): if "updateable" not in kwargs or kwargs["updateable"] is None : kwargs["updateable"] = True - appvms_conf_file = kwargs.pop("appvms_conf_file") if "appvms_conf_file" in kwargs else None - netvms_conf_file = kwargs.pop("netvms_conf_file") if "netvms_conf_file" in kwargs else None - standalonevms_conf_file = kwargs.pop("standalonevms_conf_file") if "standalonevms_conf_file" in kwargs else None - if "label" not in kwargs or kwargs["label"] == None: kwargs["label"] = default_template_label @@ -1033,25 +1026,6 @@ class QubesTemplateVm(QubesVm): # Image for template changes self.rootcow_img = self.dir_path + "/" + default_rootcow_img - if appvms_conf_file is not None and os.path.isabs(appvms_conf_file): - self.appvms_conf_file = appvms_conf_file - else: - self.appvms_conf_file = dir_path + "/" + ( - appvms_conf_file if appvms_conf_file is not None else default_appvms_conf_file) - - if netvms_conf_file is not None and os.path.isabs(netvms_conf_file): - self.netvms_conf_file = netvms_conf_file - else: - self.netvms_conf_file = dir_path + "/" + ( - netvms_conf_file if netvms_conf_file is not None else default_netvms_conf_file) - - if standalonevms_conf_file is not None and os.path.isabs(standalonevms_conf_file): - self.standalonevms_conf_file = standalonevms_conf_file - else: - self.standalonevms_conf_file = dir_path + "/" + ( - standalonevms_conf_file if standalonevms_conf_file is not None else default_standalonevms_conf_file) - - self.templatevm_conf_template = self.dir_path + "/" + default_templatevm_conf_template self.appmenus_templates_dir = self.dir_path + "/" + default_appmenus_templates_subdir self.appmenus_template_templates_dir = self.dir_path + "/" + default_appmenus_template_templates_subdir self.appvms = QubesVmCollection() @@ -1073,6 +1047,8 @@ class QubesTemplateVm(QubesVm): format (appvm.name, self.name)) self.updateable = True + def get_rootdev(self, source_template=None): + return "'script:origin:{dir}/root.img:{dir}/root-cow.img,xvda,w',".format(dir=self.dir_path) def clone_disk_files(self, src_template_vm, verbose): if dry_run: @@ -1086,42 +1062,9 @@ class QubesTemplateVm(QubesVm): os.mkdir (self.dir_path) if verbose: - print "--> Copying the VM config file:\n{0} =*>\n{1}".\ - format(src_template_vm.templatevm_conf_template, self.conf_file) - conf_templatevm_template = open (src_template_vm.templatevm_conf_template, "r") - conf_file = open(self.conf_file, "w") - rx_templatename = re.compile (r"%TEMPLATENAME%") - rx_mem = re.compile (r"%MEM%") - rx_vcpus = re.compile (r"%VCPUS%") - - for line in conf_templatevm_template: - line = rx_templatename.sub (self.name, line) - line = rx_mem.sub (str(self.memory), line) - line = rx_vcpus.sub (str(self.vcpus), line) - conf_file.write(line) - - conf_templatevm_template.close() - conf_file.close() - - if verbose: - print "--> Copying the VM config template :\n{0} ==>\n{1}".\ - format(src_template_vm.templatevm_conf_template, self.templatevm_conf_template) - shutil.copy (src_template_vm.templatevm_conf_template, self.templatevm_conf_template) - - if verbose: - print "--> Copying the VM config template :\n{0} ==>\n{1}".\ - format(src_template_vm.appvms_conf_file, self.appvms_conf_file) - shutil.copy (src_template_vm.appvms_conf_file, self.appvms_conf_file) - - if verbose: - print "--> Copying the VM config template :\n{0} ==>\n{1}".\ - format(src_template_vm.netvms_conf_file, self.netvms_conf_file) - shutil.copy (src_template_vm.netvms_conf_file, self.netvms_conf_file) - - if verbose: - print "--> Copying the VM config template :\n{0} ==>\n{1}".\ - format(src_template_vm.standalonevms_conf_file, self.standalonevms_conf_file) - shutil.copy (src_template_vm.standalonevms_conf_file, self.standalonevms_conf_file) + print "--> Creating VM config file: {0}".\ + format(self.conf_file) + self.create_config_file(source_template=src_template_vm) if verbose: print "--> Copying the template's private image:\n{0} ==>\n{1}".\ @@ -1212,16 +1155,6 @@ class QubesTemplateVm(QubesVm): "VM directory doesn't exist: {0}".\ format(self.dir_path)) - if not os.path.exists (self.conf_file): - raise QubesException ( - "VM config file doesn't exist: {0}".\ - format(self.conf_file)) - - if not os.path.exists (self.appvms_conf_file): - raise QubesException ( - "Appvm template config file doesn't exist: {0}".\ - format(self.appvms_conf_file)) - if not os.path.exists (self.root_img): raise QubesException ( "VM root image file doesn't exist: {0}".\ @@ -1296,9 +1229,6 @@ class QubesTemplateVm(QubesVm): def get_xml_attrs(self): attrs = super(QubesTemplateVm, self).get_xml_attrs() - attrs["appvms_conf_file"] = self.appvms_conf_file - attrs["netvms_conf_file"] = self.netvms_conf_file - attrs["standalonevms_conf_file"] = self.standalonevms_conf_file attrs["clean_volatile_img"] = self.clean_volatile_img attrs["rootcow_img"] = self.rootcow_img return attrs @@ -1357,6 +1287,11 @@ class QubesNetVm(QubesVm): assert lo >= 2 and lo <= 254, "Wrong IP address for VM" return self.netprefix + "{0}".format(lo) + def get_config_params(self, source_template=None): + args = super(QubesNetVm, self).get_config_params(source_template) + args['kernelopts'] = ' swiotlb=force pci=nomsi' + return args + def create_xenstore_entries(self, xid): if dry_run: return @@ -2078,11 +2013,6 @@ class QubesVmCollection(dict): try: kwargs = self.parse_xml_element(element) - # Add TemplateVM specific fields - attr_list = ("appvms_conf_file", "netvms_conf_file", "standalonevms_conf_file") - - for attribute in attr_list: - kwargs[attribute] = element.get(attribute) vm = QubesTemplateVm(**kwargs)