Merge remote-tracking branch 'woju/master'
This commit is contained in:
commit
b858488719
@ -23,6 +23,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
import lxml.etree
|
import lxml.etree
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
@ -243,7 +244,6 @@ class QubesVm(object):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
||||||
self._collection = None
|
self._collection = None
|
||||||
if 'collection' in kwargs:
|
if 'collection' in kwargs:
|
||||||
self._collection = kwargs['collection']
|
self._collection = kwargs['collection']
|
||||||
@ -343,6 +343,10 @@ class QubesVm(object):
|
|||||||
else:
|
else:
|
||||||
assert self.root_img is not None, "Missing root_img for standalone VM!"
|
assert self.root_img is not None, "Missing root_img for standalone VM!"
|
||||||
|
|
||||||
|
self.log = logging.getLogger('qubes.vm.{}'.format(self.qid))
|
||||||
|
self.log.debug('instantiated name={!r} class={}'.format(
|
||||||
|
self.name, self.__class__.__name__))
|
||||||
|
|
||||||
# fire hooks
|
# fire hooks
|
||||||
for hook in self.hooks_init:
|
for hook in self.hooks_init:
|
||||||
hook(self)
|
hook(self)
|
||||||
@ -406,6 +410,7 @@ class QubesVm(object):
|
|||||||
hook(self, new_netvm)
|
hook(self, new_netvm)
|
||||||
|
|
||||||
def _set_netvm(self, new_netvm):
|
def _set_netvm(self, new_netvm):
|
||||||
|
self.log.debug('netvm = {!r}'.format(new_netvm))
|
||||||
if self.is_running() and new_netvm is not None and not new_netvm.is_running():
|
if self.is_running() and new_netvm is not None and not new_netvm.is_running():
|
||||||
raise QubesException("Cannot dynamically attach to stopped NetVM")
|
raise QubesException("Cannot dynamically attach to stopped NetVM")
|
||||||
if self.netvm is not None:
|
if self.netvm is not None:
|
||||||
@ -544,6 +549,7 @@ class QubesVm(object):
|
|||||||
hook(self, new_name)
|
hook(self, new_name)
|
||||||
|
|
||||||
def set_name(self, name):
|
def set_name(self, name):
|
||||||
|
self.log.debug('name = {!r}'.format(name))
|
||||||
if self.is_running():
|
if self.is_running():
|
||||||
raise QubesException("Cannot change name of running VM!")
|
raise QubesException("Cannot change name of running VM!")
|
||||||
|
|
||||||
@ -695,6 +701,7 @@ class QubesVm(object):
|
|||||||
self._update_libvirt_domain()
|
self._update_libvirt_domain()
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return self._libvirt_domain
|
return self._libvirt_domain
|
||||||
|
|
||||||
def get_uuid(self):
|
def get_uuid(self):
|
||||||
@ -1117,6 +1124,8 @@ class QubesVm(object):
|
|||||||
return domain_config
|
return domain_config
|
||||||
|
|
||||||
def create_on_disk(self, verbose=False, source_template = None):
|
def create_on_disk(self, verbose=False, source_template = None):
|
||||||
|
self.log.debug('create_on_disk(source_template={!r})'.format(
|
||||||
|
source_template))
|
||||||
if source_template is None:
|
if source_template is None:
|
||||||
source_template = self.template
|
source_template = self.template
|
||||||
assert source_template is not None
|
assert source_template is not None
|
||||||
@ -1220,6 +1229,7 @@ class QubesVm(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def remove_from_disk(self):
|
def remove_from_disk(self):
|
||||||
|
self.log.debug('remove_from_disk()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1368,6 +1378,7 @@ class QubesVm(object):
|
|||||||
return conf
|
return conf
|
||||||
|
|
||||||
def pci_add(self, pci):
|
def pci_add(self, pci):
|
||||||
|
self.log.debug('pci_add(pci={!r})'.format(pci))
|
||||||
if not os.path.exists('/sys/bus/pci/devices/0000:%s' % pci):
|
if not os.path.exists('/sys/bus/pci/devices/0000:%s' % pci):
|
||||||
raise QubesException("Invalid PCI device: %s" % pci)
|
raise QubesException("Invalid PCI device: %s" % pci)
|
||||||
if self.pcidevs.count(pci):
|
if self.pcidevs.count(pci):
|
||||||
@ -1383,6 +1394,7 @@ class QubesVm(object):
|
|||||||
"(%s), changes will be seen after VM restart" % str(e)
|
"(%s), changes will be seen after VM restart" % str(e)
|
||||||
|
|
||||||
def pci_remove(self, pci):
|
def pci_remove(self, pci):
|
||||||
|
self.log.debug('pci_remove(pci={!r})'.format(pci))
|
||||||
if not self.pcidevs.count(pci):
|
if not self.pcidevs.count(pci):
|
||||||
# not attached
|
# not attached
|
||||||
return
|
return
|
||||||
@ -1415,6 +1427,10 @@ class QubesVm(object):
|
|||||||
When ignore_stderr=True, stderr is connected to /dev/null.
|
When ignore_stderr=True, stderr is connected to /dev/null.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.log.debug(
|
||||||
|
'run(command={!r}, user={!r}, passio={!r}, wait={!r})'.format(
|
||||||
|
command, user, passio, wait))
|
||||||
|
|
||||||
if user is None:
|
if user is None:
|
||||||
user = self.default_user
|
user = self.default_user
|
||||||
null = None
|
null = None
|
||||||
@ -1492,6 +1508,7 @@ class QubesVm(object):
|
|||||||
passio_popen=passio_popen, user=user, wait=True)
|
passio_popen=passio_popen, user=user, wait=True)
|
||||||
|
|
||||||
def attach_network(self, verbose = False, wait = True, netvm = None):
|
def attach_network(self, verbose = False, wait = True, netvm = None):
|
||||||
|
self.log.debug('attach_network(netvm={!r})'.format(netvm))
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1514,6 +1531,7 @@ class QubesVm(object):
|
|||||||
self._format_net_dev(self.ip, self.mac, self.netvm.name))
|
self._format_net_dev(self.ip, self.mac, self.netvm.name))
|
||||||
|
|
||||||
def detach_network(self, verbose = False, netvm = None):
|
def detach_network(self, verbose = False, netvm = None):
|
||||||
|
self.log.debug('detach_network(netvm={!r})'.format(netvm))
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1530,6 +1548,7 @@ class QubesVm(object):
|
|||||||
self.mac, self.netvm.name))
|
self.mac, self.netvm.name))
|
||||||
|
|
||||||
def wait_for_session(self, notify_function = None):
|
def wait_for_session(self, notify_function = None):
|
||||||
|
self.log.debug('wait_for_session()')
|
||||||
#self.run('echo $$ >> /tmp/qubes-session-waiter; [ ! -f /tmp/qubes-session-env ] && exec sleep 365d', ignore_stderr=True, gui=False, wait=True)
|
#self.run('echo $$ >> /tmp/qubes-session-waiter; [ ! -f /tmp/qubes-session-env ] && exec sleep 365d', ignore_stderr=True, gui=False, wait=True)
|
||||||
|
|
||||||
# Note : User root is redefined to SYSTEM in the Windows agent code
|
# Note : User root is redefined to SYSTEM in the Windows agent code
|
||||||
@ -1538,6 +1557,9 @@ class QubesVm(object):
|
|||||||
|
|
||||||
def start_guid(self, verbose = True, notify_function = None,
|
def start_guid(self, verbose = True, notify_function = None,
|
||||||
extra_guid_args=None, before_qrexec=False):
|
extra_guid_args=None, before_qrexec=False):
|
||||||
|
self.log.debug(
|
||||||
|
'start_guid(extra_guid_args={!r}, before_qrexec={!r})'.format(
|
||||||
|
extra_guid_args, before_qrexec))
|
||||||
if verbose:
|
if verbose:
|
||||||
print >> sys.stderr, "--> Starting Qubes GUId..."
|
print >> sys.stderr, "--> Starting Qubes GUId..."
|
||||||
|
|
||||||
@ -1571,6 +1593,7 @@ class QubesVm(object):
|
|||||||
self.wait_for_session(notify_function)
|
self.wait_for_session(notify_function)
|
||||||
|
|
||||||
def start_qrexec_daemon(self, verbose = False, notify_function = None):
|
def start_qrexec_daemon(self, verbose = False, notify_function = None):
|
||||||
|
self.log.debug('start_qrexec_daemon()')
|
||||||
if verbose:
|
if verbose:
|
||||||
print >> sys.stderr, "--> Starting the qrexec daemon..."
|
print >> sys.stderr, "--> Starting the qrexec daemon..."
|
||||||
qrexec_args = [str(self.xid), self.name, self.default_user]
|
qrexec_args = [str(self.xid), self.name, self.default_user]
|
||||||
@ -1584,6 +1607,7 @@ class QubesVm(object):
|
|||||||
raise OSError ("Cannot execute qrexec-daemon!")
|
raise OSError ("Cannot execute qrexec-daemon!")
|
||||||
|
|
||||||
def start_qubesdb(self):
|
def start_qubesdb(self):
|
||||||
|
self.log.debug('start_qubesdb()')
|
||||||
retcode = subprocess.call ([
|
retcode = subprocess.call ([
|
||||||
system_path["qubesdb_daemon_path"],
|
system_path["qubesdb_daemon_path"],
|
||||||
str(self.xid),
|
str(self.xid),
|
||||||
@ -1594,6 +1618,9 @@ class QubesVm(object):
|
|||||||
|
|
||||||
def start(self, verbose = False, preparing_dvm = False, start_guid = True,
|
def start(self, verbose = False, preparing_dvm = False, start_guid = True,
|
||||||
notify_function = None, mem_required = None):
|
notify_function = None, mem_required = None):
|
||||||
|
self.log.debug('start('
|
||||||
|
'preparing_dvm={!r}, start_guid={!r}, mem_required={!r})'.format(
|
||||||
|
preparing_dvm, start_guid, mem_required))
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1647,6 +1674,7 @@ class QubesVm(object):
|
|||||||
self.start_qubesdb()
|
self.start_qubesdb()
|
||||||
|
|
||||||
xid = self.xid
|
xid = self.xid
|
||||||
|
self.log.debug('xid={}'.format(xid))
|
||||||
|
|
||||||
if preparing_dvm:
|
if preparing_dvm:
|
||||||
self.services['qubes-dvm'] = True
|
self.services['qubes-dvm'] = True
|
||||||
@ -1709,6 +1737,7 @@ class QubesVm(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def shutdown(self, force=False, xid = None):
|
def shutdown(self, force=False, xid = None):
|
||||||
|
self.log.debug('shutdown()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1718,6 +1747,7 @@ class QubesVm(object):
|
|||||||
self.libvirt_domain.shutdown()
|
self.libvirt_domain.shutdown()
|
||||||
|
|
||||||
def force_shutdown(self, xid = None):
|
def force_shutdown(self, xid = None):
|
||||||
|
self.log.debug('force_shutdown()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1727,6 +1757,7 @@ class QubesVm(object):
|
|||||||
self.libvirt_domain.destroy()
|
self.libvirt_domain.destroy()
|
||||||
|
|
||||||
def suspend(self):
|
def suspend(self):
|
||||||
|
self.log.debug('suspend()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1741,6 +1772,7 @@ class QubesVm(object):
|
|||||||
self.pause()
|
self.pause()
|
||||||
|
|
||||||
def resume(self):
|
def resume(self):
|
||||||
|
self.log.debug('resume()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1750,6 +1782,7 @@ class QubesVm(object):
|
|||||||
self.unpause()
|
self.unpause()
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
|
self.log.debug('pause()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1759,6 +1792,7 @@ class QubesVm(object):
|
|||||||
self.libvirt_domain.suspend()
|
self.libvirt_domain.suspend()
|
||||||
|
|
||||||
def unpause(self):
|
def unpause(self):
|
||||||
|
self.log.debug('unpause()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ class QubesTemplateVm(QubesVm):
|
|||||||
self.commit_changes(verbose=verbose)
|
self.commit_changes(verbose=verbose)
|
||||||
|
|
||||||
def commit_changes (self, verbose = False):
|
def commit_changes (self, verbose = False):
|
||||||
|
self.log.debug('commit_changes()')
|
||||||
|
|
||||||
if not vmm.offline_mode:
|
if not vmm.offline_mode:
|
||||||
assert not self.is_running(), "Attempt to commit changes on running Template VM!"
|
assert not self.is_running(), "Attempt to commit changes on running Template VM!"
|
||||||
|
@ -73,6 +73,9 @@ class QubesNetVm(QubesVm):
|
|||||||
|
|
||||||
self.__external_ip_allowed_xids = set()
|
self.__external_ip_allowed_xids = set()
|
||||||
|
|
||||||
|
self.log.debug('network={} netmask={} gateway={} secondary_dns={}'.format(
|
||||||
|
self.network, self.netmask, self.gateway, self.secondary_dns))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
return "NetVM"
|
return "NetVM"
|
||||||
|
@ -118,6 +118,7 @@ class QubesDisposableVm(QubesVm):
|
|||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def start(self, verbose = False, **kwargs):
|
def start(self, verbose = False, **kwargs):
|
||||||
|
self.log.debug('start()')
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -195,6 +195,8 @@ class QubesHVm(QubesVm):
|
|||||||
self._drive = drv_type + ":" + value
|
self._drive = drv_type + ":" + value
|
||||||
|
|
||||||
def create_on_disk(self, verbose, source_template = None):
|
def create_on_disk(self, verbose, source_template = None):
|
||||||
|
self.log.debug('create_on_disk(source_template={!r})'.format(
|
||||||
|
source_template))
|
||||||
if dry_run:
|
if dry_run:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -23,16 +23,19 @@
|
|||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import sys
|
import atexit
|
||||||
|
import grp
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import lxml.etree
|
import sys
|
||||||
import xml.parsers.expat
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import warnings
|
import warnings
|
||||||
import tempfile
|
import xml.parsers.expat
|
||||||
import grp
|
|
||||||
import atexit
|
import lxml.etree
|
||||||
|
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
import fcntl
|
import fcntl
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt':
|
||||||
@ -295,9 +298,17 @@ class QubesVmCollection(dict):
|
|||||||
self.clockvm_qid = None
|
self.clockvm_qid = None
|
||||||
self.qubes_store_file = None
|
self.qubes_store_file = None
|
||||||
|
|
||||||
|
self.log = logging.getLogger('qubes.qvmc.{:x}'.format(id(self)))
|
||||||
|
self.log.debug('instantiated store_filename={!r}'.format(
|
||||||
|
self.qubes_store_filename))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<{} {!r}>'.format(self.__class__.__name__, list(sorted(self.keys())))
|
return '<{} {!r}>'.format(self.__class__.__name__, list(sorted(self.keys())))
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.log.debug('clear()')
|
||||||
|
super(QubesVmCollection, self).clear()
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
for qid in self.keys():
|
for qid in self.keys():
|
||||||
yield self[qid]
|
yield self[qid]
|
||||||
@ -313,12 +324,15 @@ class QubesVmCollection(dict):
|
|||||||
keys = __iter__
|
keys = __iter__
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
|
self.log.debug('[{!r}] = {!r}'.format(key, value))
|
||||||
if key not in self:
|
if key not in self:
|
||||||
return super(QubesVmCollection, self).__setitem__(key, value)
|
return super(QubesVmCollection, self).__setitem__(key, value)
|
||||||
else:
|
else:
|
||||||
assert False, "Attempt to add VM with qid that already exists in the collection!"
|
assert False, "Attempt to add VM with qid that already exists in the collection!"
|
||||||
|
|
||||||
def add_new_vm(self, vm_type, **kwargs):
|
def add_new_vm(self, vm_type, **kwargs):
|
||||||
|
self.log.debug('add_new_vm(vm_type={}, **kwargs={!r})'.format(
|
||||||
|
vm_type, kwargs))
|
||||||
if vm_type not in QubesVmClasses.keys():
|
if vm_type not in QubesVmClasses.keys():
|
||||||
raise ValueError("Unknown VM type: %s" % vm_type)
|
raise ValueError("Unknown VM type: %s" % vm_type)
|
||||||
|
|
||||||
@ -428,6 +442,7 @@ class QubesVmCollection(dict):
|
|||||||
netvm = self.get_default_fw_netvm())
|
netvm = self.get_default_fw_netvm())
|
||||||
|
|
||||||
def set_default_template(self, vm):
|
def set_default_template(self, vm):
|
||||||
|
self.log.debug('set_default_template({!r})'.format(vm))
|
||||||
if vm is None:
|
if vm is None:
|
||||||
self.default_template_qid = None
|
self.default_template_qid = None
|
||||||
else:
|
else:
|
||||||
@ -441,6 +456,7 @@ class QubesVmCollection(dict):
|
|||||||
return self[self.default_template_qid]
|
return self[self.default_template_qid]
|
||||||
|
|
||||||
def set_default_netvm(self, vm):
|
def set_default_netvm(self, vm):
|
||||||
|
self.log.debug('set_default_netvm({!r})'.format(vm))
|
||||||
if vm is None:
|
if vm is None:
|
||||||
self.default_netvm_qid = None
|
self.default_netvm_qid = None
|
||||||
else:
|
else:
|
||||||
@ -454,6 +470,7 @@ class QubesVmCollection(dict):
|
|||||||
return self[self.default_netvm_qid]
|
return self[self.default_netvm_qid]
|
||||||
|
|
||||||
def set_default_kernel(self, kernel):
|
def set_default_kernel(self, kernel):
|
||||||
|
self.log.debug('set_default_kernel({!r})'.format(kernel))
|
||||||
assert os.path.exists(
|
assert os.path.exists(
|
||||||
os.path.join(system_path["qubes_kernels_base_dir"], kernel)), \
|
os.path.join(system_path["qubes_kernels_base_dir"], kernel)), \
|
||||||
"Kerel {0} not installed!".format(kernel)
|
"Kerel {0} not installed!".format(kernel)
|
||||||
@ -463,6 +480,7 @@ class QubesVmCollection(dict):
|
|||||||
return self.default_kernel
|
return self.default_kernel
|
||||||
|
|
||||||
def set_default_fw_netvm(self, vm):
|
def set_default_fw_netvm(self, vm):
|
||||||
|
self.log.debug('set_default_fw_netvm({!r})'.format(vm))
|
||||||
if vm is None:
|
if vm is None:
|
||||||
self.default_fw_netvm_qid = None
|
self.default_fw_netvm_qid = None
|
||||||
else:
|
else:
|
||||||
@ -476,6 +494,7 @@ class QubesVmCollection(dict):
|
|||||||
return self[self.default_fw_netvm_qid]
|
return self[self.default_fw_netvm_qid]
|
||||||
|
|
||||||
def set_updatevm_vm(self, vm):
|
def set_updatevm_vm(self, vm):
|
||||||
|
self.log.debug('set_updatevm_vm({!r})'.format(vm))
|
||||||
if vm is None:
|
if vm is None:
|
||||||
self.updatevm_qid = None
|
self.updatevm_qid = None
|
||||||
else:
|
else:
|
||||||
@ -488,6 +507,7 @@ class QubesVmCollection(dict):
|
|||||||
return self[self.updatevm_qid]
|
return self[self.updatevm_qid]
|
||||||
|
|
||||||
def set_clockvm_vm(self, vm):
|
def set_clockvm_vm(self, vm):
|
||||||
|
self.log.debug('set_clockvm({!r})'.format(vm))
|
||||||
if vm is None:
|
if vm is None:
|
||||||
self.clockvm_qid = None
|
self.clockvm_qid = None
|
||||||
else:
|
else:
|
||||||
@ -576,6 +596,7 @@ class QubesVmCollection(dict):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def create_empty_storage(self):
|
def create_empty_storage(self):
|
||||||
|
self.log.debug('create_empty_storage()')
|
||||||
self.qubes_store_file = open (self.qubes_store_filename, 'w')
|
self.qubes_store_file = open (self.qubes_store_filename, 'w')
|
||||||
self.clear()
|
self.clear()
|
||||||
self.save()
|
self.save()
|
||||||
@ -584,6 +605,7 @@ class QubesVmCollection(dict):
|
|||||||
# save() would rename the file over qubes.xml, _then_ release lock,
|
# save() would rename the file over qubes.xml, _then_ release lock,
|
||||||
# so we need to ensure that the file for which we've got the lock is
|
# so we need to ensure that the file for which we've got the lock is
|
||||||
# still the right file
|
# still the right file
|
||||||
|
self.log.debug('lock_db_for_reading()')
|
||||||
while True:
|
while True:
|
||||||
self.qubes_store_file = open (self.qubes_store_filename, 'r')
|
self.qubes_store_file = open (self.qubes_store_filename, 'r')
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
@ -601,6 +623,7 @@ class QubesVmCollection(dict):
|
|||||||
# save() would rename the file over qubes.xml, _then_ release lock,
|
# save() would rename the file over qubes.xml, _then_ release lock,
|
||||||
# so we need to ensure that the file for which we've got the lock is
|
# so we need to ensure that the file for which we've got the lock is
|
||||||
# still the right file
|
# still the right file
|
||||||
|
self.log.debug('lock_db_for_writing()')
|
||||||
while True:
|
while True:
|
||||||
self.qubes_store_file = open (self.qubes_store_filename, 'r+')
|
self.qubes_store_file = open (self.qubes_store_filename, 'r+')
|
||||||
if os.name == 'posix':
|
if os.name == 'posix':
|
||||||
@ -617,9 +640,11 @@ class QubesVmCollection(dict):
|
|||||||
def unlock_db(self):
|
def unlock_db(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.log.debug('unlock_db()')
|
||||||
self.qubes_store_file.close()
|
self.qubes_store_file.close()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
|
self.log.debug('save()')
|
||||||
root = lxml.etree.Element(
|
root = lxml.etree.Element(
|
||||||
"QubesVmCollection",
|
"QubesVmCollection",
|
||||||
|
|
||||||
@ -738,7 +763,27 @@ class QubesVmCollection(dict):
|
|||||||
self.default_kernel = element.get("default_kernel")
|
self.default_kernel = element.get("default_kernel")
|
||||||
|
|
||||||
|
|
||||||
|
def _check_global(self, attr, default):
|
||||||
|
qid = getattr(self, attr)
|
||||||
|
if qid is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self[qid]
|
||||||
|
except KeyError:
|
||||||
|
setattr(self, attr, default)
|
||||||
|
|
||||||
|
|
||||||
|
def check_globals(self):
|
||||||
|
'''Ensure that all referenced qids are present in the collection'''
|
||||||
|
self._check_global('default_template_qid', None)
|
||||||
|
self._check_global('default_fw_netvm_qid', None)
|
||||||
|
self._check_global('default_netvm_qid', self.default_fw_netvm_qid)
|
||||||
|
self._check_global('updatevm_qid', self.default_netvm_qid)
|
||||||
|
self._check_global('clockvm_qid', self.default_netvm_qid)
|
||||||
|
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
|
self.log.debug('load()')
|
||||||
self.clear()
|
self.clear()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -779,6 +824,8 @@ class QubesVmCollection(dict):
|
|||||||
os.path.basename(sys.argv[0]), vm_class_name, err))
|
os.path.basename(sys.argv[0]), vm_class_name, err))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
self.check_globals()
|
||||||
|
|
||||||
# if there was no clockvm entry in qubes.xml, try to determine default:
|
# if there was no clockvm entry in qubes.xml, try to determine default:
|
||||||
# root of default NetVM chain
|
# root of default NetVM chain
|
||||||
if tree.getroot().get("clockvm") is None:
|
if tree.getroot().get("clockvm") is None:
|
||||||
@ -803,6 +850,8 @@ class QubesVmCollection(dict):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def pop(self, qid):
|
def pop(self, qid):
|
||||||
|
self.log.debug('pop({})'.format(qid))
|
||||||
|
|
||||||
if self.default_netvm_qid == qid:
|
if self.default_netvm_qid == qid:
|
||||||
self.default_netvm_qid = None
|
self.default_netvm_qid = None
|
||||||
if self.default_fw_netvm_qid == qid:
|
if self.default_fw_netvm_qid == qid:
|
||||||
|
118
tests/run.py
118
tests/run.py
@ -22,6 +22,7 @@
|
|||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import argparse
|
||||||
import curses
|
import curses
|
||||||
import importlib
|
import importlib
|
||||||
import logging
|
import logging
|
||||||
@ -101,7 +102,7 @@ class QubesTestResult(unittest.TestResult):
|
|||||||
fullname[-1] = '{color[bold]}{}{color[normal]}'.format(
|
fullname[-1] = '{color[bold]}{}{color[normal]}'.format(
|
||||||
fullname[-1], color=self.color)
|
fullname[-1], color=self.color)
|
||||||
teststr[i] = '_'.join(fullname)
|
teststr[i] = '_'.join(fullname)
|
||||||
teststr = '.'.join(teststr)
|
teststr = '/'.join(teststr)
|
||||||
|
|
||||||
doc_first_line = test.shortDescription()
|
doc_first_line = test.shortDescription()
|
||||||
if self.descriptions and doc_first_line:
|
if self.descriptions and doc_first_line:
|
||||||
@ -145,7 +146,7 @@ class QubesTestResult(unittest.TestResult):
|
|||||||
|
|
||||||
def addFailure(self, test, err): # pylint: disable=invalid-name
|
def addFailure(self, test, err): # pylint: disable=invalid-name
|
||||||
super(QubesTestResult, self).addFailure(test, err)
|
super(QubesTestResult, self).addFailure(test, err)
|
||||||
test.log.error('FAIL ({err[0]!s}: {err[1]!r})'.format(err=err))
|
test.log.error('FAIL ({err[0].__name__}: {err[1]!r})'.format(err=err))
|
||||||
if self.showAll:
|
if self.showAll:
|
||||||
self.stream.writeln('{color[red]}FAIL{color[normal]}'.format(
|
self.stream.writeln('{color[red]}FAIL{color[normal]}'.format(
|
||||||
color=self.color))
|
color=self.color))
|
||||||
@ -210,33 +211,108 @@ class QubesTestResult(unittest.TestResult):
|
|||||||
self.stream.writeln('%s' % err)
|
self.stream.writeln('%s' % err)
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
epilog='''When running only specific tests, write their names like in log,
|
||||||
|
in format: MODULE+"/"+CLASS+"/"+FUNCTION. MODULE should omit initial
|
||||||
|
"qubes.tests.". Example: basic/TC_00_Basic/test_000_create''')
|
||||||
|
|
||||||
|
parser.add_argument('--failfast', '-f',
|
||||||
|
action='store_true', dest='failfast',
|
||||||
|
help='stop on the first fail, error or unexpected success')
|
||||||
|
parser.add_argument('--no-failfast',
|
||||||
|
action='store_false', dest='failfast',
|
||||||
|
help='disable --failfast')
|
||||||
|
|
||||||
|
parser.add_argument('--verbose', '-v',
|
||||||
|
action='count',
|
||||||
|
help='increase console verbosity level')
|
||||||
|
parser.add_argument('--quiet', '-q',
|
||||||
|
action='count',
|
||||||
|
help='decrease console verbosity level')
|
||||||
|
|
||||||
|
parser.add_argument('--loglevel', '-L', metavar='LEVEL',
|
||||||
|
action='store', choices=tuple(k
|
||||||
|
for k in sorted(logging._levelNames.keys(),
|
||||||
|
key=lambda x: logging._levelNames[x])
|
||||||
|
if isinstance(k, basestring)),
|
||||||
|
help='logging level for file and syslog forwarding '
|
||||||
|
'(one of: %(choices)s; default: %(default)s)')
|
||||||
|
|
||||||
|
parser.add_argument('--logfile', '-o', metavar='FILE',
|
||||||
|
action='store',
|
||||||
|
help='if set, test run will be also logged to file')
|
||||||
|
|
||||||
|
parser.add_argument('--syslog',
|
||||||
|
action='store_true', dest='syslog',
|
||||||
|
help='reenable logging to syslog')
|
||||||
|
parser.add_argument('--no-syslog',
|
||||||
|
action='store_false', dest='syslog',
|
||||||
|
help='disable logging to syslog')
|
||||||
|
|
||||||
|
parser.add_argument('--kmsg', '--very-brave-or-very-stupid',
|
||||||
|
action='store_true', dest='kmsg',
|
||||||
|
help='log most important things to kernel ring-buffer')
|
||||||
|
parser.add_argument('--no-kmsg', '--i-am-smarter-than-kay-sievers',
|
||||||
|
action='store_false', dest='kmsg',
|
||||||
|
help='do not abuse kernel ring-buffer')
|
||||||
|
|
||||||
|
parser.add_argument('names', metavar='TESTNAME',
|
||||||
|
action='store', nargs='*',
|
||||||
|
help='list of tests to run named like in description '
|
||||||
|
'(default: run all tests)')
|
||||||
|
|
||||||
|
parser.set_defaults(
|
||||||
|
failfast=False,
|
||||||
|
loglevel='DEBUG',
|
||||||
|
logfile=None,
|
||||||
|
syslog=True,
|
||||||
|
kmsg=False,
|
||||||
|
verbose=2,
|
||||||
|
quiet=0)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
ha_file = logging.FileHandler(
|
args = parser.parse_args()
|
||||||
os.path.join(os.environ['HOME'], 'qubes-tests.log'))
|
|
||||||
ha_file.setFormatter(
|
|
||||||
logging.Formatter('%(asctime)s %(name)s[%(process)d]: %(message)s'))
|
|
||||||
logging.root.addHandler(ha_file)
|
|
||||||
|
|
||||||
ha_syslog = logging.handlers.SysLogHandler('/dev/log')
|
logging.root.setLevel(args.loglevel)
|
||||||
ha_syslog.setFormatter(
|
|
||||||
logging.Formatter('%(name)s[%(process)d]: %(message)s'))
|
|
||||||
|
|
||||||
try:
|
if args.logfile is not None:
|
||||||
subprocess.check_call(('sudo', 'chmod', '666', '/dev/kmsg'))
|
ha_file = logging.FileHandler(
|
||||||
except subprocess.CalledProcessError:
|
os.path.join(os.environ['HOME'], args.logfile))
|
||||||
pass
|
ha_file.setFormatter(
|
||||||
else:
|
logging.Formatter('%(asctime)s %(name)s[%(process)d]: %(message)s'))
|
||||||
ha_kmsg = logging.FileHandler('/dev/kmsg', 'w')
|
logging.root.addHandler(ha_file)
|
||||||
ha_kmsg.setFormatter(
|
|
||||||
|
if args.syslog:
|
||||||
|
ha_syslog = logging.handlers.SysLogHandler('/dev/log')
|
||||||
|
ha_syslog.setFormatter(
|
||||||
logging.Formatter('%(name)s[%(process)d]: %(message)s'))
|
logging.Formatter('%(name)s[%(process)d]: %(message)s'))
|
||||||
ha_kmsg.setLevel(logging.CRITICAL)
|
logging.root.addHandler(ha_syslog)
|
||||||
logging.root.addHandler(ha_kmsg)
|
|
||||||
|
if args.kmsg:
|
||||||
|
try:
|
||||||
|
subprocess.check_call(('sudo', 'chmod', '666', '/dev/kmsg'))
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
parser.error('could not chmod /dev/kmsg')
|
||||||
|
else:
|
||||||
|
ha_kmsg = logging.FileHandler('/dev/kmsg', 'w')
|
||||||
|
ha_kmsg.setFormatter(
|
||||||
|
logging.Formatter('%(name)s[%(process)d]: %(message)s'))
|
||||||
|
ha_kmsg.setLevel(logging.CRITICAL)
|
||||||
|
logging.root.addHandler(ha_kmsg)
|
||||||
|
|
||||||
suite = unittest.TestSuite()
|
suite = unittest.TestSuite()
|
||||||
loader = unittest.TestLoader()
|
loader = unittest.TestLoader()
|
||||||
suite.addTests(loader.loadTestsFromName('qubes.tests'))
|
|
||||||
|
|
||||||
runner = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
|
if args.names:
|
||||||
|
suite.addTests(loader.loadTestsFromNames(
|
||||||
|
('qubes.tests.' + name.replace('/', '.') for name in args.names)))
|
||||||
|
else:
|
||||||
|
suite.addTests(loader.loadTestsFromName('qubes.tests'))
|
||||||
|
|
||||||
|
runner = unittest.TextTestRunner(stream=sys.stdout,
|
||||||
|
verbosity=(args.verbose-args.quiet),
|
||||||
|
failfast=args.failfast)
|
||||||
unittest.signals.installHandler()
|
unittest.signals.installHandler()
|
||||||
runner.resultclass = QubesTestResult
|
runner.resultclass = QubesTestResult
|
||||||
return runner.run(suite).wasSuccessful()
|
return runner.run(suite).wasSuccessful()
|
||||||
|
Loading…
Reference in New Issue
Block a user