Add possibility to override libvirt config
This is the equivalent of "custom config" from R3.x. fixes QubesOS/qubes-issues#1798
This commit is contained in:
		
							parent
							
								
									cedd822735
								
							
						
					
					
						commit
						9dc37c1ee7
					
				| @ -26,6 +26,7 @@ manpages and API documentation. For primary user documentation, see | ||||
| .. toctree:: | ||||
|    :maxdepth: 1 | ||||
| 
 | ||||
|    libvirt | ||||
|    autoxml | ||||
|    manpages/index | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										114
									
								
								doc/libvirt.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								doc/libvirt.rst
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | ||||
| Custom libvirt config | ||||
| ===================== | ||||
| 
 | ||||
| Starting from Qubes OS R4.0, libvirt domain config is generated using jinja | ||||
| templates. Those templates can be overridden by the user in a couple of ways. | ||||
| A basic knowledge of jinja template language and libvirt xml spec is needed. | ||||
| 
 | ||||
| .. seealso:: | ||||
| 
 | ||||
|    https://libvirt.org/formatdomain.html | ||||
|       Format of the domain XML in libvirt. | ||||
| 
 | ||||
|    http://jinja.pocoo.org/docs/dev/templates/ | ||||
|       Template format documentation. | ||||
| 
 | ||||
| File paths | ||||
| ---------- | ||||
| 
 | ||||
| In order of increasing precedence: the main template, from which the config is | ||||
| generated is :file:`/usr/share/templates/libvirt/xen.xml`). | ||||
| The distributor may put a file at | ||||
| :file:`/usr/share/qubes/template/xen-dist.xml`) to override this file.  | ||||
| User may put a file at either | ||||
| :file:`/etc/qubes/templates/libvirt/xen-user.xml` or | ||||
| :file:`/etc/qubes/templates/libvirt/by-name/<name>.xml`, where ``<name>`` is | ||||
| full name of the domain. Wildcards are not supported but symlinks are. | ||||
| 
 | ||||
| Jinja has a concept of template names, which basically is the path below some | ||||
| load point, which in Qubes' case is :file:`/etc/qubes/templates` and | ||||
| :file:`/usr/share/qubes/templates`. Thus names of those templates are | ||||
| respectively ``'libvirt/xen.xml'``, ``'libvirt/xen-dist.xml'``, | ||||
| ``'libvirt/xen-user.xml'`` and ``'libvirt/by-name/<name>.xml'``. | ||||
| This will be important later. | ||||
| 
 | ||||
| .. note:: | ||||
| 
 | ||||
|    Those who know jinja python API will know that the abovementioned locations | ||||
|    aren't the only possibilities. Yes, it's a lie, but a justified one. | ||||
| 
 | ||||
| What to put in the template | ||||
| --------------------------- | ||||
| 
 | ||||
| In principle the user may put anything in the template and there is no attempt | ||||
| to constrain the user from doing stupid things. One obvious thing is to copy the | ||||
| original config file and make changes. | ||||
| 
 | ||||
| .. code-block:: jinja | ||||
| 
 | ||||
|    <domain type="xen"> | ||||
|        <name>{{ vm.name }}</name> | ||||
|        ... | ||||
| 
 | ||||
| The better way is to inherit from the original template and override any number | ||||
| of blocks. This is the point when we need the name of the original template. | ||||
| 
 | ||||
| .. code-block:: jinja | ||||
| 
 | ||||
|    {% extends 'libvirt/xen.xml' %} | ||||
|    {% block devices %} | ||||
|        {{ super() }} | ||||
|        <serial type='pty'> | ||||
|            <target port='0'/> | ||||
|        </serial> | ||||
|    {% endblock %} | ||||
| 
 | ||||
| ``{% extends %}`` specifies which template we inherit from. Then you may put any | ||||
| block by putting new content inside ``{% block %}{% endblock %}``. | ||||
| ``{{ super() }}`` is substituted with original content of the block as specified | ||||
| in the parent template. Untouched blocks remain as they were. | ||||
| 
 | ||||
| The example above adds serial device. | ||||
| 
 | ||||
| Template API | ||||
| ------------ | ||||
| 
 | ||||
| .. warning:: | ||||
| 
 | ||||
|    This API is provisional and subject to change at the minor releases until | ||||
|    further notice. No backwards compatibility is promised. | ||||
| 
 | ||||
| Globals | ||||
| ``````` | ||||
| vm | ||||
|    the domain object (instance of subclass of | ||||
|    :py:class:`qubes.vm.qubesvm.QubesVM`) | ||||
| 
 | ||||
| Filters | ||||
| ``````` | ||||
| 
 | ||||
| No custom filters at the moment. | ||||
| 
 | ||||
| Blocks in the default template | ||||
| `````````````````````````````` | ||||
| basic | ||||
|    Contains ``<name>``, ``<uuid>``, ``<memory>``, ``<currentMemory>`` and | ||||
|    ``<vcpu>`` nodes. | ||||
| 
 | ||||
| os | ||||
|    Contents of ``<os>`` node. | ||||
| 
 | ||||
| features | ||||
|    Contents of ``<features>`` node. | ||||
| 
 | ||||
| clock | ||||
|    Contains the ``<clock>`` node. | ||||
| 
 | ||||
| on | ||||
|    Contains ``<on_*>`` nodes. | ||||
| 
 | ||||
| devices | ||||
|    Contents of ``<devices>`` node. | ||||
| 
 | ||||
| 
 | ||||
| .. vim: ts=3 sts=3 sw=3 et | ||||
| @ -625,7 +625,10 @@ class Qubes(qubes.PropertyHolder): | ||||
| 
 | ||||
|         #: jinja2 environment for libvirt XML templates | ||||
|         self.env = jinja2.Environment( | ||||
|             loader=jinja2.FileSystemLoader('/usr/share/qubes/templates'), | ||||
|             loader=jinja2.FileSystemLoader([ | ||||
|                 '/etc/qubes/templates', | ||||
|                 '/usr/share/qubes/templates', | ||||
|             ]), | ||||
|             undefined=jinja2.StrictUndefined) | ||||
| 
 | ||||
|         if load: | ||||
|  | ||||
| @ -269,8 +269,12 @@ class BaseVM(qubes.PropertyHolder): | ||||
|         :param bool prepare_dvm: If we are in the process of preparing \ | ||||
|             DisposableVM | ||||
|         ''' | ||||
|         domain_config = self.app.env.get_template('libvirt/xen.xml').render( | ||||
|             vm=self, prepare_dvm=prepare_dvm) | ||||
|         domain_config = self.app.env.select_template([ | ||||
|                 'libvirt/xen/by-name/{}.xml'.format(self.name), | ||||
|                 'libvirt/xen-user.xml', | ||||
|                 'libvirt/xen-dist.xml', | ||||
|                 'libvirt/xen.xml', | ||||
|             ]).render(vm=self, prepare_dvm=prepare_dvm) | ||||
|         return domain_config | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,10 +1,13 @@ | ||||
| <domain type="xen"> | ||||
|     {% block basic %} | ||||
|         <name>{% if prepare_dvm %}%NAME%{% else %}{{ vm.name }}{% endif %}</name> | ||||
|         <uuid>{{ vm.uuid }}</uuid> | ||||
|         <memory unit="MiB">{{ vm.maxmem }}</memory> | ||||
|         <currentMemory unit="MiB">{{ vm.memory }}</currentMemory> | ||||
|         <vcpu placement="static">{{ vm.vcpus }}</vcpu> | ||||
|     {% endblock %} | ||||
|     <os> | ||||
|         {% block os %} | ||||
|             {% if vm.hvm %} | ||||
|                 <type arch="x86_64" machine="xenfv">hvm</type> | ||||
|                 <loader>hvmloader</loader> | ||||
| @ -17,9 +20,11 @@ | ||||
|                 <initrd>{{ vm.storage.kernels_dir }}/initramfs</initrd> | ||||
|                 <cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH 3 {{ vm.kernelopts }}</cmdline> | ||||
|             {% endif %} | ||||
|         {% endblock %} | ||||
|     </os> | ||||
| 
 | ||||
|     <features> | ||||
|         {% block features %} | ||||
|             {% if vm.hvm %} | ||||
|                 <pae/> | ||||
|                 <acpi/> | ||||
| @ -33,8 +38,10 @@ | ||||
|                     <e820_host state="on"/> | ||||
|                 </xen> | ||||
|             {% endif %} | ||||
|         {% endblock %} | ||||
|     </features> | ||||
| 
 | ||||
|     {% block clock %} | ||||
|         {% if vm.hvm %} | ||||
|             {% set timezone = vm.features.check_with_template('timezone', 'localtime').lower() %} | ||||
|             {% if timezone == 'localtime' %} | ||||
| @ -49,11 +56,16 @@ | ||||
|                 <timer name="tsc" mode="native"/> | ||||
|             </clock> | ||||
|         {% endif %} | ||||
|     {% endblock %} | ||||
| 
 | ||||
|     {% block on %} | ||||
|         <on_poweroff>destroy</on_poweroff> | ||||
|         <on_reboot>destroy</on_reboot> | ||||
|         <on_crash>destroy</on_crash> | ||||
|     {% endblock %} | ||||
| 
 | ||||
|     <devices> | ||||
|         {% block devices %} | ||||
|             {% set i = 0 %} | ||||
|             {# TODO Allow more volumes out of the box #} | ||||
|             {% set dd = ['e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', | ||||
| @ -116,7 +128,7 @@ | ||||
|                     <target type="xen" port="0"/> | ||||
|                 </console> | ||||
|             {% endif %} | ||||
| 
 | ||||
|         {% endblock %} | ||||
|     </devices> | ||||
| </domain> | ||||
|   | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Wojtek Porczyk
						Wojtek Porczyk