HVM part 1
This commit is contained in:
parent
e0210130da
commit
5eaf03c4a2
4
Makefile
4
Makefile
@ -80,8 +80,8 @@ endif
|
||||
cp qubes-rpc/qubes-notify-tools $(DESTDIR)/usr/libexec/qubes/
|
||||
|
||||
mkdir -p "$(DESTDIR)$(FILESDIR)"
|
||||
cp vm-config/$(BACKEND_VMM)-vm-template.xml "$(DESTDIR)$(FILESDIR)/vm-template.xml"
|
||||
cp vm-config/$(BACKEND_VMM)-vm-template-hvm.xml "$(DESTDIR)$(FILESDIR)/vm-template-hvm.xml"
|
||||
cp -r templates "$(DESTDIR)$(FILESDIR)/templates"
|
||||
rm -f "$(DESTDIR)$(FILESDIR)/templates/README"
|
||||
|
||||
mkdir -p $(DESTDIR)$(DATADIR)
|
||||
mkdir -p $(DESTDIR)$(DATADIR)/vm-templates
|
||||
|
@ -53,6 +53,7 @@ import __builtin__
|
||||
|
||||
import docutils.core
|
||||
import docutils.io
|
||||
import jinja2
|
||||
import lxml.etree
|
||||
import pkg_resources
|
||||
|
||||
@ -1199,6 +1200,11 @@ class Qubes(PropertyHolder):
|
||||
|
||||
self.__load_timestamp = None
|
||||
|
||||
#: jinja2 environment for libvirt XML templates
|
||||
self.env = jinja2.Environment(
|
||||
loader=jinja2.FileSystemLoader('/usr/share/qubes/templates'),
|
||||
undefined=jinja2.StrictUndefined)
|
||||
|
||||
if load:
|
||||
self.load()
|
||||
|
||||
|
115
qubes/devices.py
Normal file
115
qubes/devices.py
Normal file
@ -0,0 +1,115 @@
|
||||
#!/usr/bin/python2 -O
|
||||
# vim: fileencoding=utf-8
|
||||
|
||||
#
|
||||
# The Qubes OS Project, https://www.qubes-os.org/
|
||||
#
|
||||
# Copyright (C) 2010-2016 Joanna Rutkowska <joanna@invisiblethingslab.com>
|
||||
# Copyright (C) 2015-2016 Wojtek Porczyk <woju@invisiblethingslab.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import re
|
||||
|
||||
class DeviceCollection(object):
|
||||
'''Bag for devices.
|
||||
|
||||
Used as default value for :py:meth:`DeviceManager.__missing__` factory.
|
||||
|
||||
:param vm: VM for which we manage devices
|
||||
:param class_: device class
|
||||
'''
|
||||
|
||||
def __init__(self, vm, class_):
|
||||
self._vm = vm
|
||||
self._class = class_
|
||||
self._set = set()
|
||||
|
||||
|
||||
def attach(self, device):
|
||||
'''Attach (add) device to domain.
|
||||
|
||||
:param str device: device identifier (format is class-dependent)
|
||||
'''
|
||||
|
||||
if device in self:
|
||||
raise KeyError(
|
||||
'device {!r} of class {} already attached to {!r}'.format(
|
||||
device, self._class, self._vm))
|
||||
self._vm.fire_event_pre('device-pre-attach:{}'.format(self._class),
|
||||
device)
|
||||
self._set.add(device)
|
||||
self._vm.fire_event('device-attach:{}'.format(self._class), device)
|
||||
|
||||
|
||||
def detach(self, device):
|
||||
'''Detach (remove) device from domain.
|
||||
|
||||
:param str device: device identifier (format is class-dependent)
|
||||
'''
|
||||
|
||||
if device not in self:
|
||||
raise KeyError(
|
||||
'device {!r} of class {} not attached to {!r}'.format(
|
||||
device, self._class, self._vm))
|
||||
self._vm.fire_event_pre('device-pre-detach:{}'.format(self._class),
|
||||
device)
|
||||
self._set.remove(device)
|
||||
self._vm.fire_event('device-detach:{}'.format(self._class), device)
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._set)
|
||||
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._set
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return len(self._set)
|
||||
|
||||
|
||||
class DeviceManager(dict):
|
||||
'''Device manager that hold all devices by their classess.
|
||||
|
||||
:param vm: VM for which we manage devices
|
||||
'''
|
||||
|
||||
def __init__(self, vm):
|
||||
super(DeviceManager, self).__init__()
|
||||
self._vm = vm
|
||||
|
||||
def __missing__(self, key):
|
||||
self[key] = DeviceCollection(self._vm, key)
|
||||
return self[key]
|
||||
|
||||
|
||||
class RegexDevice(str):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RegexDevice, self).__init__(*args, **kwargs)
|
||||
|
||||
dev_match = self.regex.match(self)
|
||||
if not dev_match:
|
||||
raise ValueError('Invalid device identifier: {!r}'.format(self))
|
||||
|
||||
for group in self.regex.groupindex:
|
||||
setattr(self, group, dev_match.group(group))
|
||||
|
||||
|
||||
class PCIDevice(RegexDevice):
|
||||
regex = re.compile(
|
||||
r'^(?P<bus>[0-9a-f]+):(?P<device>[0-9a-f]+)\.(?P<function>[0-9a-f]+)$')
|
@ -291,7 +291,6 @@ class StatusColumn(Column):
|
||||
import qubes.vm.adminvm
|
||||
import qubes.vm.appvm
|
||||
import qubes.vm.dispvm
|
||||
import qubes.vm.hvm
|
||||
import qubes.vm.qubesvm
|
||||
import qubes.vm.templatevm
|
||||
|
||||
@ -310,7 +309,7 @@ class StatusColumn(Column):
|
||||
ret = 'd'
|
||||
|
||||
if ret is not None:
|
||||
if isinstance(vm, qubes.vm.hvm.HVM):
|
||||
if getattr(vm, 'hvm', False):
|
||||
return ret.upper()
|
||||
else:
|
||||
return ret
|
||||
|
@ -43,6 +43,7 @@ import lxml.etree
|
||||
|
||||
import qubes
|
||||
import qubes.log
|
||||
import qubes.devices
|
||||
import qubes.events
|
||||
import qubes.tools.qvm_ls
|
||||
|
||||
@ -145,80 +146,6 @@ class BaseVMMeta(qubes.events.EmitterMeta):
|
||||
qubes.tools.qvm_ls.process_class(cls)
|
||||
|
||||
|
||||
class DeviceCollection(object):
|
||||
'''Bag for devices.
|
||||
|
||||
Used as default value for :py:meth:`DeviceManager.__missing__` factory.
|
||||
|
||||
:param vm: VM for which we manage devices
|
||||
:param class_: device class
|
||||
'''
|
||||
|
||||
def __init__(self, vm, class_):
|
||||
self._vm = vm
|
||||
self._class = class_
|
||||
self._set = set()
|
||||
|
||||
|
||||
def attach(self, device):
|
||||
'''Attach (add) device to domain.
|
||||
|
||||
:param str device: device identifier (format is class-dependent)
|
||||
'''
|
||||
|
||||
if device in self:
|
||||
raise KeyError(
|
||||
'device {!r} of class {} already attached to {!r}'.format(
|
||||
device, self._class, self._vm))
|
||||
self._vm.fire_event_pre('device-pre-attached:{}'.format(self._class),
|
||||
device)
|
||||
self._set.add(device)
|
||||
self._vm.fire_event('device-attached:{}'.format(self._class), device)
|
||||
|
||||
|
||||
def detach(self, device):
|
||||
'''Detach (remove) device from domain.
|
||||
|
||||
:param str device: device identifier (format is class-dependent)
|
||||
'''
|
||||
|
||||
if device not in self:
|
||||
raise KeyError(
|
||||
'device {!r} of class {} not attached to {!r}'.format(
|
||||
device, self._class, self._vm))
|
||||
self._vm.fire_event_pre('device-pre-detached:{}'.format(self._class),
|
||||
device)
|
||||
self._set.remove(device)
|
||||
self._vm.fire_event('device-detached:{}'.format(self._class), device)
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._set)
|
||||
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._set
|
||||
|
||||
|
||||
def __len__(self):
|
||||
return len(self._set)
|
||||
|
||||
|
||||
class DeviceManager(dict):
|
||||
'''Device manager that hold all devices by their classess.
|
||||
|
||||
:param vm: VM for which we manage devices
|
||||
'''
|
||||
|
||||
def __init__(self, vm):
|
||||
super(DeviceManager, self).__init__()
|
||||
self._vm = vm
|
||||
|
||||
def __missing__(self, key):
|
||||
self[key] = DeviceCollection(self._vm, key)
|
||||
return self[key]
|
||||
|
||||
|
||||
class BaseVM(qubes.PropertyHolder):
|
||||
'''Base class for all VMs
|
||||
|
||||
@ -251,7 +178,7 @@ class BaseVM(qubes.PropertyHolder):
|
||||
|
||||
#: :py:class:`DeviceManager` object keeping devices that are attached to
|
||||
#: this domain
|
||||
self.devices = DeviceManager(self) if devices is None else devices
|
||||
self.devices = devices or qubes.devices.DeviceManager(self)
|
||||
|
||||
#: user-specified tags
|
||||
self.tags = tags or {}
|
||||
@ -480,13 +407,8 @@ class BaseVM(qubes.PropertyHolder):
|
||||
conf_template = f_conf_template.read()
|
||||
f_conf_template.close()
|
||||
|
||||
template_params = self.get_config_params()
|
||||
if prepare_dvm:
|
||||
template_params['name'] = '%NAME%'
|
||||
template_params['privatedev'] = ''
|
||||
template_params['netdev'] = re.sub(r"address='[0-9.]*'",
|
||||
"address='%IP%'", template_params['netdev'])
|
||||
domain_config = conf_template.format(**template_params)
|
||||
domain_config = self.app.env.get_template('libvirt/xen.xml').render(
|
||||
vm=self, prepare_dvm=prepare_dvm)
|
||||
|
||||
# FIXME: This is only for debugging purposes
|
||||
old_umask = os.umask(002)
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/python2 -O
|
||||
# vim: fileencoding=utf-8
|
||||
|
||||
import qubes.vm.qubesvm
|
||||
|
||||
class HVM(qubes.vm.qubesvm.QubesVM):
|
||||
'''HVM'''
|
||||
def __init__(self, D):
|
||||
super(HVM, self).__init__(D)
|
@ -166,6 +166,12 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
|
||||
ls_width=36,
|
||||
doc='UUID from libvirt.')
|
||||
|
||||
hvm = qubes.property('hvm',
|
||||
type=bool, setter=qubes.property.bool,
|
||||
default=False,
|
||||
doc='''Use full virtualisation (HVM) for this qube,
|
||||
instead of paravirtualisation (PV)''')
|
||||
|
||||
# XXX this should be part of qubes.xml
|
||||
firewall_conf = qubes.property('firewall_conf', type=str,
|
||||
default='firewall.xml')
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/python2 -O
|
||||
# vim: fileencoding=utf-8
|
||||
|
||||
import qubes.vm.hvm
|
||||
|
||||
class TemplateHVM(qubes.vm.hvm.HVM):
|
||||
'''Template for HVM'''
|
||||
def __init__(self, D):
|
||||
super(TemplateHVM, self).__init__(D)
|
@ -202,6 +202,7 @@ fi
|
||||
%dir %{python_sitelib}/qubes
|
||||
%{python_sitelib}/qubes/__init__.py*
|
||||
%{python_sitelib}/qubes/config.py*
|
||||
%{python_sitelib}/qubes/devices.py*
|
||||
%{python_sitelib}/qubes/dochelpers.py*
|
||||
%{python_sitelib}/qubes/events.py*
|
||||
%{python_sitelib}/qubes/exc.py*
|
||||
@ -214,9 +215,7 @@ fi
|
||||
%{python_sitelib}/qubes/vm/adminvm.py*
|
||||
%{python_sitelib}/qubes/vm/appvm.py*
|
||||
%{python_sitelib}/qubes/vm/dispvm.py*
|
||||
%{python_sitelib}/qubes/vm/hvm.py*
|
||||
%{python_sitelib}/qubes/vm/qubesvm.py*
|
||||
%{python_sitelib}/qubes/vm/templatehvm.py*
|
||||
%{python_sitelib}/qubes/vm/templatevm.py*
|
||||
|
||||
%dir %{python_sitelib}/qubes/vm/mix
|
||||
@ -314,8 +313,7 @@ fi
|
||||
%attr(2770,root,qubes) %dir /var/lib/qubes/backup
|
||||
%attr(2770,root,qubes) %dir /var/lib/qubes/dvmdata
|
||||
%attr(2770,root,qubes) %dir /var/lib/qubes/vm-kernels
|
||||
/usr/share/qubes/vm-template.xml
|
||||
/usr/share/qubes/vm-template-hvm.xml
|
||||
/usr/share/qubes/templates/libvirt/xen.xml
|
||||
/usr/lib/tmpfiles.d/qubes.conf
|
||||
/usr/lib/qubes/qubes-prepare-saved-domain.sh
|
||||
/usr/lib/qubes/qubes-update-dispvm-savefile-with-progress.sh
|
||||
|
4
templates/README
Normal file
4
templates/README
Normal file
@ -0,0 +1,4 @@
|
||||
Here were files with config for WNI, available in repo's history.
|
||||
|
||||
vm-config/wni-vm-template-hvm.xml
|
||||
vm-config/wni-vm-template.xml
|
121
templates/libvirt/xen.xml
Normal file
121
templates/libvirt/xen.xml
Normal file
@ -0,0 +1,121 @@
|
||||
<domain type="xen">
|
||||
<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>
|
||||
<os>
|
||||
{% if vm.hvm %}
|
||||
<type arch="x86_64" machine="xenfv">hvm</type>
|
||||
<loader>hvmloader</loader>
|
||||
<boot dev="cdrom" />
|
||||
<boot dev="hd" />
|
||||
<!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
|
||||
{% else %}
|
||||
<type arch="x86_64" machine="xenpv">linux</type>
|
||||
<kernel>{{ vm.storage.kernels_dir }}/vmlinuz</kernel>
|
||||
<initrd>{{ vm.storage.kernels_dir }}/initramfs</initrd>
|
||||
<cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH 3 {{ vm.kernelopts }}</cmdline>
|
||||
{% endif %}
|
||||
</os>
|
||||
|
||||
{% if vm.hvm %}
|
||||
<features>
|
||||
<pae/>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<viridian/>
|
||||
</features>
|
||||
|
||||
{# TODO
|
||||
<clock offset="variable"
|
||||
adjustment='{timeoffset}' basis='{time_basis}'/>
|
||||
#}
|
||||
{% else %}
|
||||
<clock offset='utc' adjustment='reset'>
|
||||
<timer name="tsc" mode="native"/>
|
||||
</clock>
|
||||
{% endif %}
|
||||
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>destroy</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
{#
|
||||
{% for device in vm.storage %}
|
||||
<disk type="block" device="{{ device.type }}">
|
||||
<driver name="phy" />
|
||||
<source dev="{{ device.path }}" />
|
||||
<target dev="{{ device.vdev }}" />
|
||||
|
||||
{% if not device.rw %}
|
||||
<readonly />
|
||||
{% endif %}
|
||||
|
||||
{% if device.domain %}
|
||||
<domain name="{{ domain }}" />
|
||||
{% endif %}
|
||||
|
||||
{% if device.script %}
|
||||
<script path="{{ device.script }}"></script>
|
||||
{% endif %}
|
||||
</disk>
|
||||
{% endfor %}
|
||||
#}
|
||||
|
||||
{{ vm.storage.root_dev_config() }}
|
||||
{% if not prepare_dvm %}{{ vm.storage.private_dev_config() }}{% endif %}
|
||||
{{ vm.storage.other_dev_config() }}
|
||||
|
||||
{% if not vm.hvm %}
|
||||
{{ vm.storage.volatile_dev_config() }}
|
||||
{% endif %}
|
||||
|
||||
{% if vm.netvm %}
|
||||
<interface type="ethernet">
|
||||
<mac address="{{ vm.mac }}" />
|
||||
<ip address="
|
||||
{%- if prepare_dvm -%}
|
||||
%IP%
|
||||
{%- else -%}
|
||||
{{ vm.ip }}
|
||||
{%- endif %}" />
|
||||
<backenddomain name="{{ vm.netvm.name }}" />
|
||||
<script path="vif-route-qubes"></script>
|
||||
</interface>
|
||||
{% endif %}
|
||||
|
||||
{% for device in vm.devices.pci %}
|
||||
<hostdev type="pci" managed="yes">
|
||||
<source>
|
||||
<address
|
||||
bus="0x{{ device.bus }}"
|
||||
slot="0x{{ device.device }}"
|
||||
function="0x{{ device.function }}" />
|
||||
</source>
|
||||
</hostdev>
|
||||
{% endfor %}
|
||||
|
||||
{% if vm.hvm %}
|
||||
<emulator
|
||||
type="stubdom"
|
||||
{% if vm.netvm %}
|
||||
cmdline="-net lwip,client_ip={{ vm.ip -}}
|
||||
,server_ip={{ vm.secondary_dns -}}
|
||||
,dns={{ vm.netvm.gateway -}}
|
||||
,gw={{ self.netvm.gateway -}}
|
||||
,netmask={{ vm.netmask }}"
|
||||
{% endif %}
|
||||
/>
|
||||
<input type="tablet" bus="usb"/>
|
||||
<video type="vga"/>
|
||||
{% else %}
|
||||
<console type="pty">
|
||||
<target type="xen" port="0"/>
|
||||
</console>
|
||||
{% endif %}
|
||||
|
||||
</devices>
|
||||
</domain>
|
||||
|
||||
<!-- vim: set ft=jinja ts=4 sts=4 sw=4 et tw=80 : -->
|
@ -1,9 +0,0 @@
|
||||
<domain type='test'>
|
||||
<name>{name}</name>
|
||||
<uuid>{uuid}</uuid>
|
||||
<memory unit='MiB'>{maxmem}</memory>
|
||||
<os>
|
||||
<type>hvm</type>
|
||||
</os>
|
||||
</domain>
|
||||
|
@ -1,9 +0,0 @@
|
||||
<domain type='test'>
|
||||
<name>{name}</name>
|
||||
<uuid>{uuid}</uuid>
|
||||
<memory unit='MiB'>{maxmem}</memory>
|
||||
<os>
|
||||
<type>pv</type>
|
||||
</os>
|
||||
</domain>
|
||||
|
@ -1,38 +0,0 @@
|
||||
<domain type='xen'>
|
||||
<name>{name}</name>
|
||||
<uuid>{uuid}</uuid>
|
||||
<memory unit='MiB'>{maxmem}</memory>
|
||||
<currentMemory unit='MiB'>{mem}</currentMemory>
|
||||
<vcpu placement='static'>{vcpus}</vcpu>
|
||||
<os>
|
||||
<type arch='x86_64' machine='xenfv'>hvm</type>
|
||||
<loader>hvmloader</loader>
|
||||
<boot dev='cdrom'/>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<features>
|
||||
<pae/>
|
||||
<acpi/>
|
||||
<apic/>
|
||||
<viridian/>
|
||||
</features>
|
||||
<clock offset='variable' adjustment='{timeoffset}' basis='{time_basis}'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>destroy</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
{no_network_begin}<emulator type='stubdom'/>{no_network_end}
|
||||
<!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
|
||||
{network_begin}<emulator type='stubdom' cmdline='-net lwip,client_ip={ip},server_ip={dns2},dns={dns1},gw={gateway},netmask={netmask}'/>{network_end}
|
||||
{rootdev}
|
||||
{privatedev}
|
||||
{otherdevs}
|
||||
{netdev}
|
||||
{pcidevs}
|
||||
<input type='tablet' bus='usb'/>
|
||||
<video type='vga'>
|
||||
<model type='xen' vram='16384'/>
|
||||
</video>
|
||||
</devices>
|
||||
</domain>
|
||||
|
@ -1,31 +0,0 @@
|
||||
<domain type='xen'>
|
||||
<name>{name}</name>
|
||||
<uuid>{uuid}</uuid>
|
||||
<memory unit='MiB'>{maxmem}</memory>
|
||||
<currentMemory unit='MiB'>{mem}</currentMemory>
|
||||
<vcpu placement='static'>{vcpus}</vcpu>
|
||||
<os>
|
||||
<type arch='x86_64' machine='xenpv'>linux</type>
|
||||
<kernel>{kerneldir}/vmlinuz</kernel>
|
||||
<initrd>{kerneldir}/initramfs</initrd>
|
||||
<cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH 3 {kernelopts}</cmdline>
|
||||
</os>
|
||||
<clock offset='utc' adjustment='reset'>
|
||||
<timer name="tsc" mode="native"/>
|
||||
</clock>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>destroy</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
{rootdev}
|
||||
{privatedev}
|
||||
{volatiledev}
|
||||
{otherdevs}
|
||||
{netdev}
|
||||
{pcidevs}
|
||||
<console type='pty'>
|
||||
<target type='xen' port='0'/>
|
||||
</console>
|
||||
</devices>
|
||||
</domain>
|
||||
|
Loading…
Reference in New Issue
Block a user