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
This commit is contained in:
parent
62111845ea
commit
6dd0870ca6
28
dom0/misc/vm-template.conf
Normal file
28
dom0/misc/vm-template.conf
Normal file
@ -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'
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user