diff --git a/linux/aux-tools/Makefile b/linux/aux-tools/Makefile index d919c84f7..9dc7b2b11 100644 --- a/linux/aux-tools/Makefile +++ b/linux/aux-tools/Makefile @@ -6,3 +6,4 @@ install: cp cleanup-dispvms $(DESTDIR)/usr/lib/qubes cp startup-misc.sh $(DESTDIR)/usr/lib/qubes cp fix-dir-perms.sh $(DESTDIR)/usr/lib/qubes/ + cp hypervisor.sh $(DESTDIR)/usr/lib/qubes/ diff --git a/linux/aux-tools/hypervisor.sh b/linux/aux-tools/hypervisor.sh new file mode 100755 index 000000000..b81c13d03 --- /dev/null +++ b/linux/aux-tools/hypervisor.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# Return hypervisor name or match result if 'name' provided +hypervisor () { + local name="$1" + local hypervisor + + if [[ $(cat /sys/hypervisor/type 2>/dev/null) == 'xen' ]]; then + hypervisor="xen" + + elif [ -e /sys/devices/virtual/misc/kvm ]; then + hypervisor="kvm" + fi + + if [ ! -z $hypervisor ]; then + if [ -z "$name" ]; then + echo "$hypervisor" + return 0 + fi + if [ "$name" == "$hypervisor" ]; then + return 0 + fi + fi + return 1 +} + + +(return 0 2>/dev/null) && sourced=1 || sourced=0 +if (( ! sourced )); then + hypervisor "$1" +fi + diff --git a/linux/aux-tools/startup-misc.sh b/linux/aux-tools/startup-misc.sh index de438a64c..e93a78adb 100755 --- a/linux/aux-tools/startup-misc.sh +++ b/linux/aux-tools/startup-misc.sh @@ -1,14 +1,21 @@ -#!/bin/sh +#!/usr/bin/sh # Misc dom0 startup setup +#### KVM: +. /usr/lib/qubes/hypervisor.sh +######## -/usr/lib/qubes/fix-dir-perms.sh -DOM0_MAXMEM=$(/usr/sbin/xl list 0 | tail -1 | awk '{ print $3 }') -xenstore-write /local/domain/0/memory/static-max $[ $DOM0_MAXMEM * 1024 ] +#### KVM: +if hypervisor xen; then + /usr/lib/qubes/fix-dir-perms.sh + DOM0_MAXMEM=$(/usr/sbin/xl list 0 | tail -1 | awk '{ print $3 }') + xenstore-write /local/domain/0/memory/static-max $[ $DOM0_MAXMEM * 1024 ] -xl sched-credit -d 0 -w 2000 -cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml + xl sched-credit -d 0 -w 2000 +fi +######## +cp /var/lib/qubes/qubes.xml /var/lib/qubes/backup/qubes-$(date +%F-%T).xml /usr/lib/qubes/cleanup-dispvms # Hide mounted devices from qubes-block list (at first udev run, only / is mounted) diff --git a/linux/systemd/qubes-core.service b/linux/systemd/qubes-core.service index 34ce40fde..8104e82a3 100644 --- a/linux/systemd/qubes-core.service +++ b/linux/systemd/qubes-core.service @@ -1,6 +1,6 @@ [Unit] Description=Qubes Dom0 startup setup -After=qubes-db-dom0.service libvirtd.service xenconsoled.service qubesd.service qubes-qmemman.service +After=qubes-db-dom0.service libvirtd.service xenconsoled.service qubesd.service # Cover legacy init.d script [Service] @@ -17,5 +17,4 @@ ExecStop=-/usr/bin/killall qubesdb-daemon [Install] WantedBy=multi-user.target -Also=qubes-meminfo-writer-dom0.service qubes-qmemman.service Alias=qubes_core.service diff --git a/qubes/api/internal.py b/qubes/api/internal.py index b54b547a8..32bbf6821 100644 --- a/qubes/api/internal.py +++ b/qubes/api/internal.py @@ -75,7 +75,7 @@ async def vm_volume_import(self, untrusted_payload): When the script finish importing, it will trigger internal.vm.volume.ImportEnd (with either b'ok' or b'fail' as a - payload) and response from that call will be actually send to the + payload) and response from that call will be actually sent to the caller. """ self.enforce(self.arg in self.dest.volumes.keys()) @@ -121,7 +121,7 @@ async def vm_volume_import(self, untrusted_payload): async def vm_volume_import_end(self, untrusted_payload): ''' This is second half of admin.vm.volume.Import handling. It is called - when actual import is finished. Response from this method is sent do + when actual import is finished. Response from this method is sent to the client (as a response for admin.vm.volume.Import call). The payload is either 'ok', or 'fail\n'. diff --git a/qubes/app.py b/qubes/app.py index ccfd56fa4..13850ee3a 100644 --- a/qubes/app.py +++ b/qubes/app.py @@ -194,10 +194,23 @@ def init_vmm_connection(self): raise qubes.exc.QubesException( 'VMM operations disabled in offline mode') + #### KVM: + ##if 'xen.lowlevel.xs' in sys.modules: + ## self._xs = xen.lowlevel.xs.xs() + ##if 'xen.lowlevel.xc' in sys.modules: + ## self._xc = xen.lowlevel.xc.xc() if 'xen.lowlevel.xs' in sys.modules: - self._xs = xen.lowlevel.xs.xs() + try: + self._xs = xen.lowlevel.xs.xs() + except xen.lowlevel.xs.Error: + pass if 'xen.lowlevel.xc' in sys.modules: - self._xc = xen.lowlevel.xc.xc() + try: + self._xc = xen.lowlevel.xc.xc() + except xen.lowlevel.xc.Error: + pass + ######## + self._libvirt_conn = VirConnectWrapper( qubes.config.defaults['libvirt_uri'], reconnect_cb=self._libvirt_reconnect_cb) @@ -213,7 +226,7 @@ def libvirt_conn(self): def xs(self): """Connection to Xen Store - This property in available only when running on Xen. + This property is available only when running on Xen. """ # XXX what about the case when we run under KVM, @@ -229,7 +242,7 @@ def xs(self): def xc(self): """Connection to Xen - This property in available only when running on Xen. + This property is available only when running on Xen. """ # XXX what about the case when we run under KVM, @@ -279,9 +292,12 @@ def _fetch(self): self.app.log.debug('QubesHost: no_cpus={} memory_total={}'.format( self.no_cpus, self.memory_total)) - with suppress(NotImplementedError): - self.app.log.debug('QubesHost: xen_free_memory={}'.format( - self.get_free_xen_memory())) + #### KVM: + #### XXX: TEMP: Commented out + ##with suppress(NotImplementedError): + ## self.app.log.debug('QubesHost: xen_free_memory={}'.format( + ## self.get_free_xen_memory())) + ######## @property def memory_total(self): @@ -323,26 +339,33 @@ def cpu_family_model(self): self._cpu_model = model return self._cpu_family, self._cpu_model - def get_free_xen_memory(self): - """Get free memory from Xen's physinfo. - - :raises NotImplementedError: when not under Xen - """ - try: - self._physinfo = self.app.vmm.xc.physinfo() - except AttributeError: - raise NotImplementedError('This function requires Xen hypervisor') - return int(self._physinfo['free_memory']) + #### KVM: + #### XXX: TEMP: Commented out + ## def get_free_xen_memory(self): + ## """Get free memory from Xen's physinfo. + ## + ## :raises NotImplementedError: when not under Xen + ## """ + ## try: + ## self._physinfo = self.app.vmm.xc.physinfo() + ## except AttributeError: + ## raise NotImplementedError('This function requires Xen hypervisor') + ## return int(self._physinfo['free_memory']) + ######## def is_iommu_supported(self): """Check if IOMMU is supported on this platform""" - if self._physinfo is None: - try: - self._physinfo = self.app.vmm.xc.physinfo() - except AttributeError: - raise NotImplementedError( - 'This function requires Xen hypervisor') - return 'hvm_directio' in self._physinfo['virt_caps'] + #### KVM: + #### XXX: TEMP: Commented out + ## if self._physinfo is None: + ## try: + ## self._physinfo = self.app.vmm.xc.physinfo() + ## except AttributeError: + ## raise NotImplementedError( + ## 'This function requires Xen hypervisor') + ## return 'hvm_directio' in self._physinfo['virt_caps'] + return True + ######## def get_vm_stats(self, previous_time=None, previous=None, only_vm=None): """Measure cpu usage for all domains at once. @@ -381,15 +404,19 @@ def get_vm_stats(self, previous_time=None, previous=None, only_vm=None): current_time = time.time() current = {} try: - if only_vm: - xid = only_vm.xid - if xid < 0: - raise qubes.exc.QubesVMNotRunningError(only_vm) - info = self.app.vmm.xc.domain_getinfo(xid, 1) - if info[0]['domid'] != xid: - raise qubes.exc.QubesVMNotRunningError(only_vm) - else: - info = self.app.vmm.xc.domain_getinfo(0, 1024) + #### KVM: + #### XXX: TEMP: Commented out + ##if only_vm: + ## xid = only_vm.xid + ## if xid < 0: + ## raise qubes.exc.QubesVMNotRunningError(only_vm) + ## info = self.app.vmm.xc.domain_getinfo(xid, 1) + ## if info[0]['domid'] != xid: + ## raise qubes.exc.QubesVMNotRunningError(only_vm) + ##else: + ## ##info = self.app.vmm.xc.domain_getinfo(0, 1024) + info = [] + ######## except AttributeError: raise NotImplementedError( 'This function requires Xen hypervisor') diff --git a/qubes/config.py b/qubes/config.py index a8f6c9de7..0eab53fb9 100644 --- a/qubes/config.py +++ b/qubes/config.py @@ -27,6 +27,10 @@ '''Constants which can be configured in one place''' import os.path +#### KVM: +from .hypervisor import hypervisor_name +######## + qubes_base_dir = "/var/lib/qubes" system_path = { @@ -49,7 +53,10 @@ } defaults = { - 'libvirt_uri': 'xen:///', + #### KVM: + ##'libvirt_uri': 'xen:///', + 'libvirt_uri': 'xen:///' if hypervisor_name() == 'xen' else 'qemu:///system', + ######## 'memory': 400, 'hvm_memory': 400, 'kernelopts': "", diff --git a/qubes/hypervisor.py b/qubes/hypervisor.py new file mode 100644 index 000000000..fcf8fdad1 --- /dev/null +++ b/qubes/hypervisor.py @@ -0,0 +1,42 @@ +# +# The Qubes OS Project, https://www.qubes-os.org/ +# +# Copyright (C) 2020 Jason Mehring +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see . +# + +'''Hypervisor utilities.''' + +import pathlib + + +def hypervisor_name(): + '''Return hypervisor name.''' + hypervisor = pathlib.Path('/sys/hypervisor/type') + if hypervisor.exists(): + return hypervisor.read_text().strip().lower() + if pathlib.Path('/sys/devices/virtual/misc/kvm').exists(): + return 'kvm' + return None + + +def is_xen(): + '''Check if hypervisor is xen.''' + return hypervisor_name() == 'xen' + + +def is_kvm(): + '''Check if hypervisor is xen.''' + return hypervisor_name() == 'xen' diff --git a/qubes/tools/qubesd.py b/qubes/tools/qubesd.py index 88196bb75..0cb2b747a 100644 --- a/qubes/tools/qubesd.py +++ b/qubes/tools/qubesd.py @@ -14,6 +14,7 @@ import qubes.api.misc import qubes.log import qubes.utils +import qubes.tools import qubes.vm.qubesvm # Wait for the system entropy pool to fill, so we can use “/dev/urandom” with diff --git a/qubes/vm/__init__.py b/qubes/vm/__init__.py index 4e32706da..be39168fa 100644 --- a/qubes/vm/__init__.py +++ b/qubes/vm/__init__.py @@ -36,6 +36,10 @@ import qubes.features import qubes.log +#### KVM: +from qubes.hypervisor import hypervisor_name +######## + VM_ENTRY_POINT = 'qubes.vm' def validate_name(holder, prop, value): @@ -368,12 +372,21 @@ def create_config_file(self): '''Create libvirt's XML domain config file ''' + #### KVM: + ##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) + hypervisor = hypervisor_name() 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', + f'libvirt/{hypervisor}/by-name/{self.name}.xml', + f'libvirt/{hypervisor}-user.xml', + f'libvirt/{hypervisor}-dist.xml', + f'libvirt/{hypervisor}.xml', ]).render(vm=self) + ######## return domain_config def watch_qdb_path(self, path): diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index ef85f1570..76bee1455 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -43,12 +43,22 @@ import qubes.vm.mix.net qmemman_present = False -try: - import qubes.qmemman.client # pylint: disable=wrong-import-position +#### KVM: +##try: +## import qubes.qmemman.client # pylint: disable=wrong-import-position +## +## qmemman_present = True +##except ImportError: +## pass +from qubes.hypervisor import is_xen +if is_xen(): + try: + import qubes.qmemman.client # pylint: disable=wrong-import-position - qmemman_present = True -except ImportError: - pass + qmemman_present = True + except ImportError: + pass +######## # overhead of per-qube/per-vcpu Xen structures, # taken from OpenStack nova/virt/xenapi/driver.py diff --git a/rpm_spec/core-dom0.spec.in b/rpm_spec/core-dom0.spec.in index b4473b8e5..7274d5781 100644 --- a/rpm_spec/core-dom0.spec.in +++ b/rpm_spec/core-dom0.spec.in @@ -55,7 +55,10 @@ BuildRequires: python3-lxml BuildRequires: libvirt-python3 BuildRequires: python3-dbus BuildRequires: python3-PyYAML + +%if "%{?backend_vmm}" == "xen" BuildRequires: python3-xen +%endif Requires(post): systemd-units Requires(preun): systemd-units @@ -69,9 +72,12 @@ Requires: python3-lxml Requires: python3-qubesdb Requires: python3-setuptools Requires: python3-PyYAML -Requires: python3-xen Requires: libvirt-python3 +%if "%{?backend_vmm}" == "xen" +Requires: python3-xen +%endif + Requires: pciutils # udev rules for encrypted volatile volumes Requires: qubes-core-dom0-linux >= 4.1.13 @@ -80,13 +86,16 @@ Requires: qubes-core-qrexec-dom0 >= 4.1.8 Requires: qubes-db-dom0 # TODO: R: qubes-gui-dom0 >= 2.1.11 Conflicts: qubes-gui-dom0 < 1.1.13 -%if "x%{?backend_vmm}" == "xxen" +%if "%{?backend_vmm}" == "xen" Requires: xen-runtime Requires: xen-hvm Requires: xen-hvm-stubdom-linux >= 1.0.13 Requires: xen-hvm-stubdom-linux-full >= 1.0.13 Requires: libvirt-daemon-xen >= 3.3.0-7 %endif +%if "%{?backend_vmm}" == "kvm" +Requires: libvirt-daemon-kvm >= 3.3.0-7 +%endif Requires: cronie Requires: scrypt # for qubes-hcl-report @@ -138,12 +147,18 @@ mkdir -p $RPM_BUILD_ROOT/etc/qubes/backup %post %systemd_post qubes-core.service +## Xen only +%if "%{?backend_vmm}" == "xen" %systemd_post qubes-qmemman.service +%endif +######## %systemd_post qubesd.service +%if "%{?backend_vmm}" == "xen" sed '/^autoballoon=/d;/^lockfile=/d' -i /etc/xen/xl.conf echo 'autoballoon=0' >> /etc/xen/xl.conf echo 'lockfile="/var/run/qubes/xl-lock"' >> /etc/xen/xl.conf +%endif if [ -e /etc/sysconfig/prelink ]; then sed 's/^PRELINKING\s*=.*/PRELINKING=no/' -i /etc/sysconfig/prelink @@ -168,12 +183,18 @@ if ! grep -q ^qubes: /etc/group ; then groupadd qubes fi +%if "%{?backend_vmm}" == "xen" %triggerin -- xen-runtime /usr/lib/qubes/fix-dir-perms.sh +%endif %preun %systemd_preun qubes-core.service +## Xen only +%if "%{?backend_vmm}" == "xen" %systemd_preun qubes-qmemman.service +%endif +######## %systemd_preun qubesd.service if [ "$1" = 0 ] ; then @@ -184,7 +205,11 @@ fi %postun %systemd_postun qubes-core.service +## Xen only +%if "%{?backend_vmm}" == "xen" %systemd_postun_with_restart qubes-qmemman.service +%endif +######## %systemd_postun_with_restart qubesd.service if [ "$1" = 0 ] ; then @@ -338,12 +363,20 @@ done %files %defattr(-,root,root,-) +## Xen only +%if "%{?backend_vmm}" == "xen" %config(noreplace) %attr(0664,root,qubes) %{_sysconfdir}/qubes/qmemman.conf +%endif +######## %config(noreplace) /etc/logrotate.d/qubes %attr(770,root,qubes) %dir /etc/qubes/backup /usr/bin/qvm-* /usr/bin/qubes-* +## Xen only - XXX: TEMP: Package since it installed. Need to prevent install +#%%if "%{?backend_vmm}" == "xen" /usr/bin/qmemmand +#%%endif +######## /usr/bin/qubesd* %{_mandir}/man1/qubes*.1* @@ -366,6 +399,9 @@ done %{python3_sitelib}/qubes/features.py %{python3_sitelib}/qubes/firewall.py %{python3_sitelib}/qubes/log.py +#### KVM: Added for KVM +%{python3_sitelib}/qubes/hypervisor.py +######## %{python3_sitelib}/qubes/rngdoc.py %{python3_sitelib}/qubes/tarwriter.py %{python3_sitelib}/qubes/utils.py @@ -411,7 +447,9 @@ done %dir %{python3_sitelib}/qubes/tools/__pycache__ %{python3_sitelib}/qubes/tools/__pycache__/* %{python3_sitelib}/qubes/tools/__init__.py +## XXX: %{python3_sitelib}/qubes/tools/qmemmand.py +######## %{python3_sitelib}/qubes/tools/qubes_create.py %{python3_sitelib}/qubes/tools/qubesd.py %{python3_sitelib}/qubes/tools/qubesd_query.py @@ -510,19 +548,24 @@ done %{python3_sitelib}/qubes/tests/integ/tools/__init__.py %{python3_sitelib}/qubes/tests/integ/tools/qubes_create.py +## XXX: %dir %{python3_sitelib}/qubes/qmemman %dir %{python3_sitelib}/qubes/qmemman/__pycache__ %{python3_sitelib}/qubes/qmemman/__pycache__/* %{python3_sitelib}/qubes/qmemman/__init__.py %{python3_sitelib}/qubes/qmemman/algo.py %{python3_sitelib}/qubes/qmemman/client.py +######## /usr/lib/qubes/cleanup-dispvms /usr/lib/qubes/fix-dir-perms.sh /usr/lib/qubes/startup-misc.sh +/usr/lib/qubes/hypervisor.sh %{_unitdir}/lvm2-pvscan@.service.d/30_qubes.conf %{_unitdir}/qubes-core.service +## XXX: %{_unitdir}/qubes-qmemman.service +######## %{_unitdir}/qubes-vm@.service %{_unitdir}/qubesd.service %attr(2770,root,qubes) %dir /var/lib/qubes @@ -530,6 +573,9 @@ done %attr(2770,root,qubes) %dir /var/lib/qubes/appvms %attr(2770,root,qubes) %dir /var/lib/qubes/backup %attr(2770,root,qubes) %dir /var/lib/qubes/vm-kernels +%if "%{?backend_vmm}" == "kvm" +/usr/share/qubes/templates/libvirt/kvm.xml +%endif /usr/share/qubes/templates/libvirt/xen.xml /usr/share/qubes/templates/libvirt/devices/block.xml /usr/share/qubes/templates/libvirt/devices/pci.xml diff --git a/templates/libvirt/kvm.xml b/templates/libvirt/kvm.xml new file mode 100644 index 000000000..a3273af7f --- /dev/null +++ b/templates/libvirt/kvm.xml @@ -0,0 +1,569 @@ + + +{# machine: q35 | i440 #} +{% set machine = 'i440' %} + + + {% block basic %} + {{ vm.name }} + {{ vm.uuid }} + {# PLACEHOLDER + + + + + + #} + {% if ((vm.virt_mode == 'hvm' and vm.devices['pci'].persistent() | list) + or vm.maxmem == 0) -%} + {{ vm.memory }} + {% else -%} + {{ vm.maxmem }} + {% endif -%} + {{ vm.memory }} + {{ vm.vcpus }} + {% endblock %} + + {% block cpu %} + + {% endblock %} + + + {% block os %} + + {% if machine == 'i440' %} + hvm + {% else %} + hvm + {% endif %} + + + /usr/share/edk2/ovmf/OVMF_CODE.fd + /var/lib/libvirt/qemu/nvram/fedora-32_VARS.fd + + + + {# PLACEHOLDER + {% if vm.kernel %} + {% if vm.features.check_with_template('no-default-kernelopts', False) -%} + {{ vm.kernelopts }} + {% else -%} + {{ vm.kernelopts_common }}{{ vm.kernelopts }} + {% endif -%} + {% endif %} + #} + {% endblock %} + + + + {% block features %} + + + + {% endblock %} + + + {% block clock %} + {% set timezone = vm.features.check_with_template('timezone', 'localtime').lower() %} + {% if timezone == 'localtime' %} + + {% elif timezone.isdigit() %} + + {% else %} + + {% endif %} + + + + + {% endblock %} + + {% block on %} + destroy + destroy + destroy + {% endblock %} + + {# NOT IMPLEMENTED #} + {% block pm %} + + + + + {% endblock %} + + + + {#- NOT IMPLEMENTED -#} + {%- block device_controllers %} + + {% if machine == 'i440' %} + + + + +
+ + + + +
+ + + {% else %} + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + {% endif %} + + + + + + + + + + + + + + + + + + + + + + {%- endblock %} + + + + + + + + + + + {%- block devices %} + {#- + HACK: The letter counter is implemented in this way because + Jinja does not allow you to increment variables in a loop + anymore. As of Jinja 2.10, we will be able to replace this + with: + {% set counter = namespace(i=0) %} + {% set counter.i = counter.i + 1 %} + #} + {%- set counter = {'i': 0} %} + {# TODO Allow more volumes out of the box #} + {%- set dd = ['e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y'] + %} + + {#- + DISK.TYPE: + Valid values are 'file', 'block', 'dir', 'network', 'volume', or + 'nvme'. + + DRIVER: + xen supports a name of 'tap', 'tap2', 'phy', or 'file', with a type + of 'aio'. + + qemu only supports a name of 'qemu', but multiple types including + 'raw', 'bochs', 'qcow2', and 'qed'. + #} + + {%- for device in vm.block_devices %} + + + + + {%- if device.name == 'root' %} + + + + {%- elif device.name == 'private' %} + + + + {%- elif device.name == 'volatile' %} + + + + {%- elif device.name == 'kernel' %} + + + + {%- else %} + {# XXX: FIX: Only allows up to 8 devices total #} + + + {% if counter.update({'i': counter.i + 1}) %}{% endif %} + {%-endif %} + + {%- if not device.rw %} + + {%- endif %} + + {%- if device.domain %} + + {%- endif %} + + {%- endfor -%} + + {# start external devices from xvdi #} + {% set counter = {'i': 4} %} + {% for assignment in vm.devices.block.assignments(True) %} + {% set device = assignment.device %} + {% set options = assignment.options %} + {% include 'libvirt/devices/block.xml' %} + {% endfor %} + + {% if vm.netvm %} + {# TODO: #} + {# include 'libvirt/devices/net.xml' with context #} + + + + + + + + + + {% endif %} + + {% for assignment in vm.devices.pci.assignments(True) %} + {% set device = assignment.device %} + {% set options = assignment.options %} + {% include 'libvirt/devices/pci.xml' %} + {% endfor %} + + + + + + + + + + + {% if vm.virt_mode == 'hvm' %} + + {# TODO: + + #} + /usr/bin/qemu-system-x86_64 + + +
+ + + + + {% if vm.features.check_with_template('audio-model', False) %} + +
+ + {% endif %} + + {% if vm.features.check_with_template('video-model', 'vga') != 'none' %} + + + + + + {% if vm.features.check_with_template('linux-stubdom', True) %} + {# TODO only add qubes gui if gui-agent is not installed in HVM #} + + {% endif %} + #} + {% endif %} + {% endif %} + + + + + + + + + + + + + + + + /dev/urandom + + + + + + + + + + + + {% endblock %} + + + + + + + + + +