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::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
libvirt
|
||||||
autoxml
|
autoxml
|
||||||
manpages/index
|
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
|
#: jinja2 environment for libvirt XML templates
|
||||||
self.env = jinja2.Environment(
|
self.env = jinja2.Environment(
|
||||||
loader=jinja2.FileSystemLoader('/usr/share/qubes/templates'),
|
loader=jinja2.FileSystemLoader([
|
||||||
|
'/etc/qubes/templates',
|
||||||
|
'/usr/share/qubes/templates',
|
||||||
|
]),
|
||||||
undefined=jinja2.StrictUndefined)
|
undefined=jinja2.StrictUndefined)
|
||||||
|
|
||||||
if load:
|
if load:
|
||||||
|
@ -269,8 +269,12 @@ class BaseVM(qubes.PropertyHolder):
|
|||||||
:param bool prepare_dvm: If we are in the process of preparing \
|
:param bool prepare_dvm: If we are in the process of preparing \
|
||||||
DisposableVM
|
DisposableVM
|
||||||
'''
|
'''
|
||||||
domain_config = self.app.env.get_template('libvirt/xen.xml').render(
|
domain_config = self.app.env.select_template([
|
||||||
vm=self, prepare_dvm=prepare_dvm)
|
'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
|
return domain_config
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,25 +1,30 @@
|
|||||||
<domain type="xen">
|
<domain type="xen">
|
||||||
<name>{% if prepare_dvm %}%NAME%{% else %}{{ vm.name }}{% endif %}</name>
|
{% block basic %}
|
||||||
|
<name>{% if prepare_dvm %}%NAME%{% else %}{{ vm.name }}{% endif %}</name>
|
||||||
<uuid>{{ vm.uuid }}</uuid>
|
<uuid>{{ vm.uuid }}</uuid>
|
||||||
<memory unit="MiB">{{ vm.maxmem }}</memory>
|
<memory unit="MiB">{{ vm.maxmem }}</memory>
|
||||||
<currentMemory unit="MiB">{{ vm.memory }}</currentMemory>
|
<currentMemory unit="MiB">{{ vm.memory }}</currentMemory>
|
||||||
<vcpu placement="static">{{ vm.vcpus }}</vcpu>
|
<vcpu placement="static">{{ vm.vcpus }}</vcpu>
|
||||||
|
{% endblock %}
|
||||||
<os>
|
<os>
|
||||||
|
{% block os %}
|
||||||
{% if vm.hvm %}
|
{% if vm.hvm %}
|
||||||
<type arch="x86_64" machine="xenfv">hvm</type>
|
<type arch="x86_64" machine="xenfv">hvm</type>
|
||||||
<loader>hvmloader</loader>
|
<loader>hvmloader</loader>
|
||||||
<boot dev="cdrom" />
|
<boot dev="cdrom" />
|
||||||
<boot dev="hd" />
|
<boot dev="hd" />
|
||||||
<!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
|
<!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
|
||||||
{% else %}
|
{% else %}
|
||||||
<type arch="x86_64" machine="xenpv">linux</type>
|
<type arch="x86_64" machine="xenpv">linux</type>
|
||||||
<kernel>{{ vm.storage.kernels_dir }}/vmlinuz</kernel>
|
<kernel>{{ vm.storage.kernels_dir }}/vmlinuz</kernel>
|
||||||
<initrd>{{ vm.storage.kernels_dir }}/initramfs</initrd>
|
<initrd>{{ vm.storage.kernels_dir }}/initramfs</initrd>
|
||||||
<cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH 3 {{ vm.kernelopts }}</cmdline>
|
<cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH 3 {{ vm.kernelopts }}</cmdline>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
</os>
|
</os>
|
||||||
|
|
||||||
<features>
|
<features>
|
||||||
|
{% block features %}
|
||||||
{% if vm.hvm %}
|
{% if vm.hvm %}
|
||||||
<pae/>
|
<pae/>
|
||||||
<acpi/>
|
<acpi/>
|
||||||
@ -33,8 +38,10 @@
|
|||||||
<e820_host state="on"/>
|
<e820_host state="on"/>
|
||||||
</xen>
|
</xen>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
</features>
|
</features>
|
||||||
|
|
||||||
|
{% block clock %}
|
||||||
{% if vm.hvm %}
|
{% if vm.hvm %}
|
||||||
{% set timezone = vm.features.check_with_template('timezone', 'localtime').lower() %}
|
{% set timezone = vm.features.check_with_template('timezone', 'localtime').lower() %}
|
||||||
{% if timezone == 'localtime' %}
|
{% if timezone == 'localtime' %}
|
||||||
@ -49,11 +56,16 @@
|
|||||||
<timer name="tsc" mode="native"/>
|
<timer name="tsc" mode="native"/>
|
||||||
</clock>
|
</clock>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block on %}
|
||||||
<on_poweroff>destroy</on_poweroff>
|
<on_poweroff>destroy</on_poweroff>
|
||||||
<on_reboot>destroy</on_reboot>
|
<on_reboot>destroy</on_reboot>
|
||||||
<on_crash>destroy</on_crash>
|
<on_crash>destroy</on_crash>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
<devices>
|
<devices>
|
||||||
|
{% block devices %}
|
||||||
{% set i = 0 %}
|
{% set i = 0 %}
|
||||||
{# TODO Allow more volumes out of the box #}
|
{# TODO Allow more volumes out of the box #}
|
||||||
{% set dd = ['e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
|
{% set dd = ['e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
|
||||||
@ -116,7 +128,7 @@
|
|||||||
<target type="xen" port="0"/>
|
<target type="xen" port="0"/>
|
||||||
</console>
|
</console>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
</devices>
|
</devices>
|
||||||
</domain>
|
</domain>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user