qubes: fix Qubes instantiation
This commit is contained in:
parent
8e16dd2b28
commit
d937d39c9e
@ -16,7 +16,9 @@ __version__ = 'R3'
|
|||||||
import ast
|
import ast
|
||||||
import atexit
|
import atexit
|
||||||
import collections
|
import collections
|
||||||
|
import errno
|
||||||
import grp
|
import grp
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
@ -102,7 +104,7 @@ class VMMConnection(object):
|
|||||||
self._xs = xen.lowlevel.xs.xs()
|
self._xs = xen.lowlevel.xs.xs()
|
||||||
if 'xen.lowlevel.cs' in sys.modules:
|
if 'xen.lowlevel.cs' in sys.modules:
|
||||||
self._xc = xen.lowlevel.xc.xc()
|
self._xc = xen.lowlevel.xc.xc()
|
||||||
self._libvirt_conn = libvirt.open(defaults['libvirt_uri'])
|
self._libvirt_conn = libvirt.open(qubes.config.defaults['libvirt_uri'])
|
||||||
if self._libvirt_conn is None:
|
if self._libvirt_conn is None:
|
||||||
raise QubesException("Failed connect to libvirt driver")
|
raise QubesException("Failed connect to libvirt driver")
|
||||||
libvirt.registerErrorHandler(self._libvirt_error_handler, None)
|
libvirt.registerErrorHandler(self._libvirt_error_handler, None)
|
||||||
@ -150,7 +152,7 @@ class QubesHost(object):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self._app = app
|
self.app = app
|
||||||
self._no_cpus = None
|
self._no_cpus = None
|
||||||
|
|
||||||
|
|
||||||
@ -159,7 +161,7 @@ class QubesHost(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
(model, memory, cpus, mhz, nodes, socket, cores, threads) = \
|
(model, memory, cpus, mhz, nodes, socket, cores, threads) = \
|
||||||
self._app.vmm.libvirt_conn.getInfo()
|
self.app.vmm.libvirt_conn.getInfo()
|
||||||
self._total_mem = long(memory) * 1024
|
self._total_mem = long(memory) * 1024
|
||||||
self._no_cpus = cpus
|
self._no_cpus = cpus
|
||||||
|
|
||||||
@ -214,7 +216,7 @@ class QubesHost(object):
|
|||||||
previous_time = time.time()
|
previous_time = time.time()
|
||||||
previous = {}
|
previous = {}
|
||||||
try:
|
try:
|
||||||
info = self._app.vmm.xc.domain_getinfo(0, qubes_max_qid)
|
info = self.app.vmm.xc.domain_getinfo(0, qubes_max_qid)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
'This function requires Xen hypervisor')
|
'This function requires Xen hypervisor')
|
||||||
@ -761,9 +763,12 @@ class PropertyHolder(qubes.events.Emitter):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, xml, *args, **kwargs):
|
def __init__(self, xml, *args, **kwargs):
|
||||||
super(PropertyHolder, self).__init__(*args, **kwargs)
|
super(PropertyHolder, self).__init__(*args)
|
||||||
self.xml = xml
|
self.xml = xml
|
||||||
|
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
setattr(self, key, value)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_props_list(cls, load_stage=None):
|
def get_props_list(cls, load_stage=None):
|
||||||
@ -1051,11 +1056,15 @@ class Qubes(PropertyHolder):
|
|||||||
|
|
||||||
|
|
||||||
def __init__(self, store='/var/lib/qubes/qubes.xml'):
|
def __init__(self, store='/var/lib/qubes/qubes.xml'):
|
||||||
|
super(Qubes, self).__init__(xml=None)
|
||||||
|
|
||||||
|
self.log = logging.getLogger('app')
|
||||||
|
|
||||||
self._extensions = set(ext(self)
|
self._extensions = set(ext(self)
|
||||||
for ext in qubes.ext.Extension.register.values())
|
for ext in qubes.ext.Extension.register.values())
|
||||||
|
|
||||||
#: collection of all VMs managed by this Qubes instance
|
#: collection of all VMs managed by this Qubes instance
|
||||||
self.domains = VMCollection()
|
self.domains = VMCollection(self)
|
||||||
|
|
||||||
#: collection of all available labels for VMs
|
#: collection of all available labels for VMs
|
||||||
self.labels = {}
|
self.labels = {}
|
||||||
@ -1067,28 +1076,46 @@ class Qubes(PropertyHolder):
|
|||||||
self.host = QubesHost(self)
|
self.host = QubesHost(self)
|
||||||
|
|
||||||
self._store = store
|
self._store = store
|
||||||
|
self.load()
|
||||||
try:
|
|
||||||
self.load()
|
|
||||||
except IOError:
|
|
||||||
self._init()
|
|
||||||
|
|
||||||
super(Qubes, self).__init__(
|
|
||||||
xml=lxml.etree.parse(self.qubes_store_file))
|
|
||||||
|
|
||||||
|
|
||||||
def _open_store(self):
|
def _open_store(self):
|
||||||
|
'''Open qubes.xml
|
||||||
|
|
||||||
|
This method takes care of creation of the store when it does not exist.
|
||||||
|
|
||||||
|
:raises OSError: on failure
|
||||||
|
:raises lxml.etree.XMLSyntaxError: on syntax error in qubes.xml
|
||||||
|
'''
|
||||||
if hasattr(self, '_storefd'):
|
if hasattr(self, '_storefd'):
|
||||||
return
|
return
|
||||||
|
|
||||||
self._storefd = open(self._store, 'r+')
|
try:
|
||||||
|
fd = os.open(self._store,
|
||||||
|
os.O_RDWR | os.O_CREAT | os.O_EXCL | 0o660)
|
||||||
|
parsexml = False
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno != errno.EEXIST:
|
||||||
|
raise
|
||||||
|
|
||||||
|
# file does exist
|
||||||
|
fd = os.open(self._store, os.O_RDWR)
|
||||||
|
parsexml = True
|
||||||
|
|
||||||
|
self._storefd = os.fdopen(fd, 'r+b')
|
||||||
|
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
fcntl.lockf(self.qubes_store_file, fcntl.LOCK_EX)
|
fcntl.lockf(self._storefd, fcntl.LOCK_EX)
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt':
|
||||||
overlapped = pywintypes.OVERLAPPED()
|
win32file.LockFileEx(
|
||||||
win32file.LockFileEx(win32file._get_osfhandle(self.qubes_store_file.fileno()),
|
win32file._get_osfhandle(self._storefd.fileno()),
|
||||||
win32con.LOCKFILE_EXCLUSIVE_LOCK, 0, -0x10000, overlapped)
|
win32con.LOCKFILE_EXCLUSIVE_LOCK,
|
||||||
|
0, -0x10000,
|
||||||
|
pywintypes.OVERLAPPED())
|
||||||
|
|
||||||
|
if parsexml:
|
||||||
|
self.xml = lxml.etree.parse(self._storefd)
|
||||||
|
# else: it will remain None, as set by PropertyHolder
|
||||||
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
@ -1098,6 +1125,10 @@ class Qubes(PropertyHolder):
|
|||||||
'''
|
'''
|
||||||
self._open_store()
|
self._open_store()
|
||||||
|
|
||||||
|
if self.xml is None:
|
||||||
|
self._init()
|
||||||
|
return
|
||||||
|
|
||||||
# stage 1: load labels
|
# stage 1: load labels
|
||||||
for node in self._xml.xpath('./labels/label'):
|
for node in self._xml.xpath('./labels/label'):
|
||||||
label = Label.fromxml(node)
|
label = Label.fromxml(node)
|
||||||
@ -1110,7 +1141,8 @@ class Qubes(PropertyHolder):
|
|||||||
self.domains.add(vm)
|
self.domains.add(vm)
|
||||||
|
|
||||||
if not 0 in self.domains:
|
if not 0 in self.domains:
|
||||||
self.domains.add(qubes.vm.adminvm.AdminVM(self))
|
self.domains.add(qubes.vm.adminvm.AdminVM(
|
||||||
|
self, None, qid=0, name='dom0'))
|
||||||
|
|
||||||
# stage 3: load global properties
|
# stage 3: load global properties
|
||||||
self.load_properties(self.xml, load_stage=3)
|
self.load_properties(self.xml, load_stage=3)
|
||||||
@ -1153,12 +1185,16 @@ class Qubes(PropertyHolder):
|
|||||||
8: Label(8, '0x000000', 'black'),
|
8: Label(8, '0x000000', 'black'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.domains.add(qubes.vm.adminvm.AdminVM(
|
||||||
|
self, None, qid=0, name='dom0'))
|
||||||
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
# intentionally do not call explicit unlock to not unlock the file
|
# intentionally do not call explicit unlock to not unlock the file
|
||||||
# before all buffers are flushed
|
# before all buffers are flushed
|
||||||
self._storefd.close()
|
if hasattr(self, '_storefd'):
|
||||||
del self._storefd
|
self._storefd.close()
|
||||||
|
del self._storefd
|
||||||
|
|
||||||
|
|
||||||
def __xml__(self):
|
def __xml__(self):
|
||||||
|
@ -120,6 +120,10 @@ class DeviceCollection(object):
|
|||||||
return item in self._set
|
return item in self._set
|
||||||
|
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._set)
|
||||||
|
|
||||||
|
|
||||||
class DeviceManager(dict):
|
class DeviceManager(dict):
|
||||||
'''Device manager that hold all devices by their classess.
|
'''Device manager that hold all devices by their classess.
|
||||||
|
|
||||||
|
@ -54,9 +54,9 @@ except ImportError:
|
|||||||
|
|
||||||
|
|
||||||
def _setter_qid(self, prop, value):
|
def _setter_qid(self, prop, value):
|
||||||
if not 0 <= value <= qubes.MAX_QID:
|
if not 0 <= value <= qubes.config.max_qid:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'{} value must be between 0 and qubes.MAX_QID'.format(
|
'{} value must be between 0 and qubes.config.max_qid'.format(
|
||||||
prop.__name__))
|
prop.__name__))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@ -182,7 +182,8 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
# XXX not applicable to HVM?
|
# XXX not applicable to HVM?
|
||||||
kernelopts = qubes.property('kernelopts', type=str, load_stage=4,
|
kernelopts = qubes.property('kernelopts', type=str, load_stage=4,
|
||||||
default=(lambda self: defaults['kernelopts_pcidevs'] \
|
default=(lambda self: defaults['kernelopts_pcidevs'] \
|
||||||
if len(self.devices['pci']) > 0 else defaults['kernelopts']),
|
if len(self.devices['pci']) > 0 \
|
||||||
|
else qubes.config.defaults['kernelopts']),
|
||||||
doc='Kernel command line passed to domain.')
|
doc='Kernel command line passed to domain.')
|
||||||
|
|
||||||
mac = qubes.property('mac', type=str,
|
mac = qubes.property('mac', type=str,
|
||||||
@ -398,25 +399,17 @@ class QubesVM(qubes.vm.BaseVM):
|
|||||||
# constructor
|
# constructor
|
||||||
#
|
#
|
||||||
|
|
||||||
def __init__(self, app, xml):
|
def __init__(self, app, xml, **kwargs):
|
||||||
super(QubesVM, self).__init__(app, xml)
|
super(QubesVM, self).__init__(app, xml, **kwargs)
|
||||||
|
|
||||||
#Init private attrs
|
#Init private attrs
|
||||||
|
|
||||||
self._libvirt_domain = None
|
self._libvirt_domain = None
|
||||||
self._qdb_connection = None
|
self._qdb_connection = None
|
||||||
|
|
||||||
assert self.__qid < qubes_max_qid, "VM id out of bounds!"
|
assert self.qid < qubes.config.max_qid, "VM id out of bounds!"
|
||||||
assert self.name is not None
|
assert self.name is not None
|
||||||
|
|
||||||
if not self.verify_name(self.name):
|
|
||||||
msg = ("'%s' is invalid VM name (invalid characters, over 31 chars long, "
|
|
||||||
"or one of 'none', 'true', 'false')") % self.name
|
|
||||||
if xml is not None:
|
|
||||||
print >>sys.stderr, "WARNING: %s" % msg
|
|
||||||
else:
|
|
||||||
raise QubesException(msg)
|
|
||||||
|
|
||||||
# Not in generic way to not create QubesHost() to frequently
|
# Not in generic way to not create QubesHost() to frequently
|
||||||
# XXX this doesn't apply, host is instantiated once
|
# XXX this doesn't apply, host is instantiated once
|
||||||
if self.maxmem is None and not self.app.vmm.offline_mode:
|
if self.maxmem is None and not self.app.vmm.offline_mode:
|
||||||
|
Loading…
Reference in New Issue
Block a user