core3: fixes from Marek

This is adapted from commit 90a50dca406e3d40c88ea338566e0460589df7a3.
This commit is contained in:
Wojtek Porczyk 2015-09-17 12:08:03 +02:00
parent e9b998400d
commit 80d664441d
8 changed files with 134 additions and 49 deletions

View File

@ -640,7 +640,7 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name
if self._setter is not None: if self._setter is not None:
value = self._setter(instance, self, value) value = self._setter(instance, self, value)
if self._type is not None: if self._type is not None: # XXX what about QubesVM and other types?
value = self._type(value) value = self._type(value)
if has_oldvalue: if has_oldvalue:
@ -705,7 +705,7 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name
# #
class DontSave(Exception): class DontSave(Exception):
'''This exception may be raised from saver to sing that property should '''This exception may be raised from saver to sign that property should
not be saved. not be saved.
''' '''
pass pass
@ -1023,23 +1023,28 @@ class VMProperty(property):
raise TypeError( raise TypeError(
"'vmclass' should specify a subclass of qubes.vm.BaseVM") "'vmclass' should specify a subclass of qubes.vm.BaseVM")
super(VMProperty, self).__init__(name, **kwargs) super(VMProperty, self).__init__(name,
saver=(lambda self, prop, value: value.name if value else 'None'),
**kwargs)
self.vmclass = vmclass self.vmclass = vmclass
self.allow_none = allow_none self.allow_none = allow_none
def __set__(self, instance, value): def __set__(self, instance, value):
if value is None: if value is None:
if self.allow_none: if self.allow_none:
super(VMProperty, self).__set__(self, instance, value) super(VMProperty, self).__set__(instance, value)
return return
else: else:
raise ValueError( raise ValueError(
'Property {!r} does not allow setting to {!r}'.format( 'Property {!r} does not allow setting to {!r}'.format(
self.__name__, value)) self.__name__, value))
app = instance if isinstance(instance, Qubes) else instance.app
# XXX this may throw LookupError; that's good until introduction # XXX this may throw LookupError; that's good until introduction
# of QubesNoSuchVMException or whatever # of QubesNoSuchVMException or whatever
vm = instance.app.domains[value] vm = app.domains[value]
if not isinstance(vm, self.vmclass): if not isinstance(vm, self.vmclass):
raise TypeError('wrong VM class: domains[{!r}] if of type {!s} ' raise TypeError('wrong VM class: domains[{!r}] if of type {!s} '
@ -1047,7 +1052,7 @@ class VMProperty(property):
vm.__class__.__name__, vm.__class__.__name__,
self.vmclass.__name__)) self.vmclass.__name__))
super(VMProperty, self).__set__(self, instance, vm) super(VMProperty, self).__set__(instance, vm)
import qubes.vm.qubesvm import qubes.vm.qubesvm
@ -1100,11 +1105,11 @@ class Qubes(PropertyHolder):
''' '''
default_netvm = VMProperty('default_netvm', load_stage=3, default_netvm = VMProperty('default_netvm', load_stage=3,
default=None, default=None, allow_none=True,
doc='''Default NetVM for AppVMs. Initial state is `None`, which means doc='''Default NetVM for AppVMs. Initial state is `None`, which means
that AppVMs are not connected to the Internet.''') that AppVMs are not connected to the Internet.''')
default_fw_netvm = VMProperty('default_fw_netvm', load_stage=3, default_fw_netvm = VMProperty('default_fw_netvm', load_stage=3,
default=None, default=None, allow_none=True,
doc='''Default NetVM for ProxyVMs. Initial state is `None`, which means doc='''Default NetVM for ProxyVMs. Initial state is `None`, which means
that ProxyVMs (including FirewallVM) are not connected to the that ProxyVMs (including FirewallVM) are not connected to the
Internet.''') Internet.''')
@ -1112,9 +1117,11 @@ class Qubes(PropertyHolder):
vmclass=qubes.vm.templatevm.TemplateVM, vmclass=qubes.vm.templatevm.TemplateVM,
doc='Default template for new AppVMs') doc='Default template for new AppVMs')
updatevm = VMProperty('updatevm', load_stage=3, updatevm = VMProperty('updatevm', load_stage=3,
allow_none=True,
doc='''Which VM to use as `yum` proxy for updating AdminVM and doc='''Which VM to use as `yum` proxy for updating AdminVM and
TemplateVMs''') TemplateVMs''')
clockvm = VMProperty('clockvm', load_stage=3, clockvm = VMProperty('clockvm', load_stage=3,
allow_none=True,
doc='Which VM to use as NTP proxy for updating AdminVM') doc='Which VM to use as NTP proxy for updating AdminVM')
default_kernel = property('default_kernel', load_stage=3, default_kernel = property('default_kernel', load_stage=3,
doc='Which kernel to use when not overriden in VM') doc='Which kernel to use when not overriden in VM')
@ -1209,7 +1216,7 @@ class Qubes(PropertyHolder):
# Disable ntpd in ClockVM - to not conflict with ntpdate (both are # Disable ntpd in ClockVM - to not conflict with ntpdate (both are
# using 123/udp port) # using 123/udp port)
if hasattr(self, 'clockvm'): if hasattr(self, 'clockvm') and self.clockvm is not None:
if 'ntpd' in self.clockvm.services: if 'ntpd' in self.clockvm.services:
if self.clockvm.services['ntpd']: if self.clockvm.services['ntpd']:
self.log.warning("VM set as clockvm ({!r}) has enabled " self.log.warning("VM set as clockvm ({!r}) has enabled "
@ -1367,6 +1374,8 @@ class Qubes(PropertyHolder):
@qubes.events.handler('property-pre-set:clockvm') @qubes.events.handler('property-pre-set:clockvm')
def on_property_pre_set_clockvm(self, event, name, newvalue, oldvalue=None): def on_property_pre_set_clockvm(self, event, name, newvalue, oldvalue=None):
# pylint: disable=unused-argument,no-self-use # pylint: disable=unused-argument,no-self-use
if newvalue is None:
return
if 'ntpd' in newvalue.services: if 'ntpd' in newvalue.services:
if newvalue.services['ntpd']: if newvalue.services['ntpd']:
raise QubesException('Cannot set {!r} as {!r} property since ' raise QubesException('Cannot set {!r} as {!r} property since '

View File

@ -102,7 +102,8 @@ class Emitter(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Emitter, self).__init__(*args, **kwargs) super(Emitter, self).__init__(*args, **kwargs)
self.events_enabled = False if not hasattr(self, 'events_enabled'):
self.events_enabled = False
@classmethod @classmethod

5
qubes/qdb.py Normal file
View File

@ -0,0 +1,5 @@
# This is mock file, not installed. It is needed. because pylint needs to
# import all the modules, and qubes.qbd is one of them.
def QubesDB(dummy):
return None

View File

@ -353,7 +353,7 @@ class BaseVM(qubes.PropertyHolder):
args['name'] = self.name args['name'] = self.name
if hasattr(self, 'kernels_dir'): if hasattr(self, 'kernels_dir'):
args['kerneldir'] = self.kernels_dir args['kerneldir'] = self.kernels_dir
args['uuidnode'] = '<uuid>{!r}</uuid>'.format(self.uuid) \ args['uuidnode'] = '<uuid>{!s}</uuid>'.format(self.uuid) \
if hasattr(self, 'uuid') else '' if hasattr(self, 'uuid') else ''
args['vmdir'] = self.dir_path args['vmdir'] = self.dir_path
args['pcidevs'] = ''.join(lxml.etree.tostring(self.lvxml_pci_dev(dev)) args['pcidevs'] = ''.join(lxml.etree.tostring(self.lvxml_pci_dev(dev))
@ -398,6 +398,8 @@ class BaseVM(qubes.PropertyHolder):
"Debug mode: adding 'earlyprintk=xen' to kernel opts") "Debug mode: adding 'earlyprintk=xen' to kernel opts")
args['kernelopts'] += ' earlyprintk=xen' args['kernelopts'] += ' earlyprintk=xen'
return args
def create_config_file(self, file_path=None, prepare_dvm=False): def create_config_file(self, file_path=None, prepare_dvm=False):
'''Create libvirt's XML domain config file '''Create libvirt's XML domain config file

View File

@ -1,6 +1,7 @@
#!/usr/bin/python2 -O #!/usr/bin/python2 -O
# vim: fileencoding=utf-8 # vim: fileencoding=utf-8
import qubes.events
import qubes.vm.qubesvm import qubes.vm.qubesvm
class AppVM(qubes.vm.qubesvm.QubesVM): class AppVM(qubes.vm.qubesvm.QubesVM):
@ -11,9 +12,11 @@ class AppVM(qubes.vm.qubesvm.QubesVM):
ls_width=31, ls_width=31,
doc='Template, on which this AppVM is based.') doc='Template, on which this AppVM is based.')
def __init__(self, D): def __init__(self, *args, **kwargs):
super(AppVM, self).__init__(D) super(AppVM, self).__init__(*args, **kwargs)
@qubes.events.handler('domain-loaded')
def on_domain_loaded(self, event):
# Some additional checks for template based VM # Some additional checks for template based VM
assert self.template assert self.template
self.template.appvms.add(self) #self.template.appvms.add(self) # XXX

View File

@ -3,7 +3,32 @@
import qubes.vm.qubesvm import qubes.vm.qubesvm
class NetVM(qubes.vm.qubesvm.QubesVM): class NetVM(qubes.vm.appvm.AppVM):
'''Network interface VM''' '''Network interface VM'''
def __init__(self, D):
super(NetVM, self).__init__(D) netvm = qubes.property('netvm', setter=qubes.property.forbidden)
def __init__(self, *args, **kwargs):
super(NetVM, self).__init__(*args, **kwargs)
def get_ip_for_vm(self, vm):
return '10.137.{}.{}'.format(self.qid, vm.qid + 2)
@property
def gateway(self):
return '10.137.{}.1'.format(self.qid)
@property
def secondary_dns(self):
return '10.137.{}.254'.format(self.qid)
# @property
# def netmask(self):
# return '255.255.255.0'
#
# @property
# def provides_network(self):
# return True
netmask = '255.255.255.0'
provides_network = True

View File

@ -24,6 +24,8 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# #
from __future__ import absolute_import
import datetime import datetime
import lxml.etree import lxml.etree
import os import os
@ -34,11 +36,13 @@ import subprocess
import sys import sys
import time import time
import uuid import uuid
import warnings
import libvirt import libvirt
import qubes import qubes
import qubes.config import qubes.config
#import qubes.qdb import qubes.qdb
#import qubes.qmemman #import qubes.qmemman
#import qubes.qmemman_algo #import qubes.qmemman_algo
import qubes.storage import qubes.storage
@ -90,19 +94,29 @@ def _setter_name(self, prop, value):
def _setter_kernel(self, prop, value): def _setter_kernel(self, prop, value):
# pylint: disable=unused-argument # pylint: disable=unused-argument
if not os.path.exists(os.path.join( dirname = os.path.join(
qubes.config.system_path['qubes_kernels_base_dir'], value)): qubes.config.system_path['qubes_base_dir'],
qubes.config.system_path['qubes_kernels_base_dir'],
value)
if not os.path.exists(dirname):
raise qubes.QubesException('Kernel {!r} not installed'.format(value)) raise qubes.QubesException('Kernel {!r} not installed'.format(value))
for filename in ('vmlinuz', 'modules.img'): for filename in ('vmlinuz', 'modules.img'):
if not os.path.exists(os.path.join( if not os.path.exists(os.path.join(dirname, filename)):
qubes.config.system_path['qubes_kernels_base_dir'],
value, filename)):
raise qubes.QubesException( raise qubes.QubesException(
'Kernel {!r} not properly installed: missing {!r} file'.format( 'Kernel {!r} not properly installed: missing {!r} file'.format(
value, filename)) value, filename))
return value return value
def _setter_label(self, prop, value):
if isinstance(value, qubes.Label):
return value
if value.startswith('label-'):
return self.app.labels[int(value.split('-', 1)[1])]
return self.app.get_label(value)
def _default_conf_file(self, name=None): def _default_conf_file(self, name=None):
return (name or self.name) + '.conf' return (name or self.name) + '.conf'
@ -115,7 +129,8 @@ class QubesVM(qubes.vm.BaseVM):
# #
label = qubes.property('label', label = qubes.property('label',
setter=(lambda self, prop, value: self.app.get_label(value)), setter=_setter_label,
saver=(lambda self, prop, value: 'label-{}'.format(value.index)),
ls_width=14, ls_width=14,
doc='''Colourful label assigned to VM. This is where the colour of the doc='''Colourful label assigned to VM. This is where the colour of the
padlock is set.''') padlock is set.''')
@ -129,9 +144,9 @@ class QubesVM(qubes.vm.BaseVM):
`None`, machine is disconnected. When absent, domain uses default `None`, machine is disconnected. When absent, domain uses default
NetVM.''') NetVM.''')
provides_network = qubes.property('provides_network', # provides_network = qubes.property('provides_network',
type=bool, setter=qubes.property.bool, # type=bool, setter=qubes.property.bool,
doc='`True` if it is NetVM or ProxyVM, false otherwise.') # doc='`True` if it is NetVM or ProxyVM, false otherwise.')
qid = qubes.property('qid', type=int, qid = qubes.property('qid', type=int,
setter=_setter_qid, setter=_setter_qid,
@ -180,8 +195,9 @@ class QubesVM(qubes.vm.BaseVM):
doc='''Internal VM (not shown in qubes-manager, don't create appmenus doc='''Internal VM (not shown in qubes-manager, don't create appmenus
entries.''') entries.''')
# XXX what is that # FIXME self.app.host could not exist - only self.app.vm required by API
vcpus = qubes.property('vcpus', default=None, vcpus = qubes.property('vcpus',
default=(lambda self: self.app.host.no_cpus),
ls_width=2, ls_width=2,
doc='FIXME') doc='FIXME')
@ -215,7 +231,8 @@ class QubesVM(qubes.vm.BaseVM):
# XXX shouldn't this go to standalone VM and TemplateVM, and leave here # XXX shouldn't this go to standalone VM and TemplateVM, and leave here
# only plain property? # only plain property?
default_user = qubes.property('default_user', type=str, default_user = qubes.property('default_user', type=str,
default=(lambda self: self.template.default_user), default=(lambda self: self.template.default_user
if hasattr(self, 'template') else 'user'),
ls_width=12, ls_width=12,
doc='FIXME') doc='FIXME')
@ -353,7 +370,7 @@ class QubesVM(qubes.vm.BaseVM):
If :py:attr:`self.kernel` is :py:obj:`None`, the this points inside If :py:attr:`self.kernel` is :py:obj:`None`, the this points inside
:py:attr:`self.dir_path` :py:attr:`self.dir_path`
''' '''
return os.path.join( return os.path.join(qubes.config.system_path['qubes_base_dir'],
qubes.config.system_path['qubes_kernels_base_dir'], self.kernel) \ qubes.config.system_path['qubes_kernels_base_dir'], self.kernel) \
if self.kernel is not None \ if self.kernel is not None \
else os.path.join(self.dir_path, else os.path.join(self.dir_path,
@ -379,17 +396,25 @@ class QubesVM(qubes.vm.BaseVM):
# XXX I don't know what to do with these; probably should be isinstance(...) # XXX I don't know what to do with these; probably should be isinstance(...)
# def is_template(self): def is_template(self):
# return False warnings.warn('vm.is_template() is deprecated, use isinstance()',
# DeprecationWarning)
# def is_appvm(self): return isinstance(self, qubes.vm.templatevm.TemplateVM)
# return False
# def is_appvm(self):
# def is_proxyvm(self): warnings.warn('vm.is_appvm() is deprecated, use isinstance()',
# return False DeprecationWarning)
# return isinstance(self, qubes.vm.appvm.AppVM)
# def is_disposablevm(self):
# return False def is_proxyvm(self):
warnings.warn('vm.is_proxyvm() is deprecated, use isinstance()',
DeprecationWarning)
return isinstance(self, qubes.vm.proxyvm.ProxyVM)
def is_disposablevm(self):
warnings.warn('vm.is_disposable() is deprecated, use isinstance()',
DeprecationWarning)
return isinstance(self, qubes.vm.dispvm.DispVM)
# network-related # network-related
@ -399,7 +424,7 @@ class QubesVM(qubes.vm.BaseVM):
def ip(self): def ip(self):
'''IP address of this domain.''' '''IP address of this domain.'''
if self.netvm is not None: if self.netvm is not None:
return self.netvm.get_ip_for_vm(self.qid) return self.netvm.get_ip_for_vm(self)
else: else:
return None return None
@ -441,6 +466,13 @@ class QubesVM(qubes.vm.BaseVM):
return None return None
return "vif{0}.+".format(self.xid) return "vif{0}.+".format(self.xid)
@property
def provides_network(self):
''':py:obj:`True` if it is :py:class:`qubes.vm.netvm.NetVM` or
:py:class:`qubes.vm.proxyvm.ProxyVM`, :py:obj:`False` otherwise'''
return isinstance(self,
(qubes.vm.netvm.NetVM, qubes.vm.proxyvm.ProxyVM))
# #
# constructor # constructor
# #
@ -472,8 +504,8 @@ class QubesVM(qubes.vm.BaseVM):
self.maxmem = self.memory * 10 self.maxmem = self.memory * 10
# By default allow use all VCPUs # By default allow use all VCPUs
if not hasattr(self, 'vcpus') and not self.app.vmm.offline_mode: # if not hasattr(self, 'vcpus') and not self.app.vmm.offline_mode:
self.vcpus = self.app.host.no_cpus # self.vcpus = self.app.host.no_cpus
if len(self.devices['pci']) > 0: if len(self.devices['pci']) > 0:
# Force meminfo-writer disabled when VM have PCI devices # Force meminfo-writer disabled when VM have PCI devices
@ -486,10 +518,11 @@ class QubesVM(qubes.vm.BaseVM):
# Initialize VM image storage class # Initialize VM image storage class
self.storage = qubes.storage.get_storage(self) self.storage = qubes.storage.get_storage(self)
if self.kernels_dir is not None: # it is None for AdminVM # XXX should be moved to defaults in storage class
self.storage.modules_img = os.path.join(self.kernels_dir, # if self.kernels_dir is not None: # it is None for AdminVM
'modules.img') # self.storage.modules_img = os.path.join(self.kernels_dir,
self.storage.modules_img_rw = self.kernel is None # 'modules.img')
# self.storage.modules_img_rw = self.kernel is None
# fire hooks # fire hooks
self.fire_event('domain-init') self.fire_event('domain-init')

View File

@ -1,6 +1,8 @@
#!/usr/bin/python2 -O #!/usr/bin/python2 -O
# vim: fileencoding=utf-8 # vim: fileencoding=utf-8
import os.path
import qubes import qubes
import qubes.vm.qubesvm import qubes.vm.qubesvm
@ -38,3 +40,8 @@ class TemplateVM(qubes.vm.qubesvm.QubesVM):
self.log.info( self.log.info(
'Commiting template update; COW: {}'.format(self.rootcow_img)) 'Commiting template update; COW: {}'.format(self.rootcow_img))
self.storage.commit_template_changes() self.storage.commit_template_changes()
@property
def rootcow_img(self):
return os.path.join(self.dir_path, qubes.config.vm_files['rootcow_img'])