qubes: pylint fixes (mostly whitespace)
This commit is contained in:
parent
e3415a7b4e
commit
cdc3df66c8
@ -123,9 +123,11 @@ class VMMConnection(object):
|
||||
This property in available only when running on Xen.
|
||||
'''
|
||||
|
||||
# XXX what about the case when we run under KVM, but xen modules are importable?
|
||||
# XXX what about the case when we run under KVM,
|
||||
# but xen modules are importable?
|
||||
if 'xen.lowlevel.xs' not in sys.modules:
|
||||
raise AttributeError('xs object is available under Xen hypervisor only')
|
||||
raise AttributeError(
|
||||
'xs object is available under Xen hypervisor only')
|
||||
|
||||
self.init_vmm_connection()
|
||||
return self._xs
|
||||
@ -137,9 +139,11 @@ class VMMConnection(object):
|
||||
This property in available only when running on Xen.
|
||||
'''
|
||||
|
||||
# XXX what about the case when we run under KVM, but xen modules are importable?
|
||||
# XXX what about the case when we run under KVM,
|
||||
# but xen modules are importable?
|
||||
if 'xen.lowlevel.xc' not in sys.modules:
|
||||
raise AttributeError('xc object is available under Xen hypervisor only')
|
||||
raise AttributeError(
|
||||
'xc object is available under Xen hypervisor only')
|
||||
|
||||
self.init_vmm_connection()
|
||||
return self._xs
|
||||
@ -148,7 +152,8 @@ class VMMConnection(object):
|
||||
class QubesHost(object):
|
||||
'''Basic information about host machine
|
||||
|
||||
:param qubes.Qubes app: Qubes application context (must have :py:attr:`Qubes.vmm` attribute defined)
|
||||
:param qubes.Qubes app: Qubes application context (must have \
|
||||
:py:attr:`Qubes.vmm` attribute defined)
|
||||
'''
|
||||
|
||||
def __init__(self, app):
|
||||
@ -165,9 +170,11 @@ class QubesHost(object):
|
||||
self._total_mem = long(memory) * 1024
|
||||
self._no_cpus = cpus
|
||||
|
||||
self.app.log.debug('QubesHost: no_cpus={} memory_total={}'.format(self.no_cpus, self.memory_total))
|
||||
self.app.log.debug('QubesHost: no_cpus={} memory_total={}'.format(
|
||||
self.no_cpus, self.memory_total))
|
||||
try:
|
||||
self.app.log.debug('QubesHost: xen_free_memory={}'.format(self.get_free_xen_memory()))
|
||||
self.app.log.debug('QubesHost: xen_free_memory={}'.format(
|
||||
self.get_free_xen_memory()))
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
@ -275,11 +282,12 @@ class Label(object):
|
||||
#: label's name like "red" or "green"
|
||||
self.name = name
|
||||
|
||||
#: freedesktop icon name, suitable for use in :py:meth:`PyQt4.QtGui.QIcon.fromTheme`
|
||||
#: freedesktop icon name, suitable for use in
|
||||
#: :py:meth:`PyQt4.QtGui.QIcon.fromTheme`
|
||||
self.icon = 'appvm-' + name
|
||||
|
||||
#: freedesktop icon name, suitable for use in :py:meth:`PyQt4.QtGui.QIcon.fromTheme`
|
||||
#: on DispVMs
|
||||
#: freedesktop icon name, suitable for use in
|
||||
#: :py:meth:`PyQt4.QtGui.QIcon.fromTheme` on DispVMs
|
||||
self.icon_dispvm = 'dispvm-' + name
|
||||
|
||||
|
||||
@ -402,18 +410,18 @@ class VMCollection(object):
|
||||
# this violates duck typing, but is needed
|
||||
# for VMProperty to function correctly
|
||||
if not isinstance(value, qubes.vm.BaseVM):
|
||||
raise TypeError(
|
||||
'{} holds only BaseVM instances'.format(self.__class__.__name__))
|
||||
raise TypeError('{} holds only BaseVM instances'.format(
|
||||
self.__class__.__name__))
|
||||
|
||||
if not hasattr(value, 'qid'):
|
||||
value.qid = self.domains.get_new_unused_qid()
|
||||
|
||||
if value.qid in self:
|
||||
raise ValueError('This collection already holds VM that has qid={!r} (!r)'.format(
|
||||
value.qid, self[value.qid]))
|
||||
raise ValueError('This collection already holds VM that has '
|
||||
'qid={!r} ({!r})'.format(value.qid, self[value.qid]))
|
||||
if value.name in self:
|
||||
raise ValueError('This collection already holds VM that has name={!r} (!r)'.format(
|
||||
value.name, self[value.name]))
|
||||
raise ValueError('This collection already holds VM that has '
|
||||
'name={!r} ({!r})'.format(value.name, self[value.name]))
|
||||
|
||||
self._dict[value.qid] = value
|
||||
self.app.fire_event('domain-added', value)
|
||||
@ -425,7 +433,7 @@ class VMCollection(object):
|
||||
|
||||
if isinstance(key, basestring):
|
||||
for vm in self:
|
||||
if (vm.name == key):
|
||||
if vm.name == key:
|
||||
return vm
|
||||
raise KeyError(key)
|
||||
|
||||
@ -507,13 +515,19 @@ class property(object):
|
||||
or, when no default, py:class:`exceptions.AttributeError`.
|
||||
|
||||
:param str name: name of the property
|
||||
:param collections.Callable setter: if not :py:obj:`None`, this is used to initialise value; first parameter to the function is holder instance and the second is value; this is called before ``type``
|
||||
:param collections.Callable saver: function to coerce value to something readable by setter
|
||||
:param collections.Callable setter: if not :py:obj:`None`, this is used to \
|
||||
initialise value; first parameter to the function is holder instance \
|
||||
and the second is value; this is called before ``type``
|
||||
:param collections.Callable saver: function to coerce value to something \
|
||||
readable by setter
|
||||
:param type type: if not :py:obj:`None`, value is coerced to this type
|
||||
:param object default: default value; if callable, will be called with holder as first argument
|
||||
:param int load_stage: stage when property should be loaded (see :py:class:`Qubes` for description of stages)
|
||||
:param object default: default value; if callable, will be called with \
|
||||
holder as first argument
|
||||
:param int load_stage: stage when property should be loaded (see \
|
||||
:py:class:`Qubes` for description of stages)
|
||||
:param int order: order of evaluation (bigger order values are later)
|
||||
:param str doc: docstring; this should be one paragraph of plain RST, no sphinx-specific features
|
||||
:param str doc: docstring; this should be one paragraph of plain RST, no \
|
||||
sphinx-specific features
|
||||
|
||||
Setters and savers have following signatures:
|
||||
|
||||
@ -542,8 +556,9 @@ class property(object):
|
||||
# internal use only
|
||||
_NO_DEFAULT = object()
|
||||
|
||||
def __init__(self, name, setter=None, saver=None, type=None, default=_NO_DEFAULT,
|
||||
load_stage=2, order=0, save_via_ref=False, doc=None):
|
||||
def __init__(self, name, setter=None, saver=None, type=None,
|
||||
default=_NO_DEFAULT, load_stage=2, order=0, save_via_ref=False,
|
||||
doc=None):
|
||||
self.__name__ = name
|
||||
self._setter = setter
|
||||
self._saver = saver if saver is not None else (
|
||||
@ -563,8 +578,8 @@ class property(object):
|
||||
|
||||
# XXX this violates duck typing, shall we keep it?
|
||||
if not isinstance(instance, PropertyHolder):
|
||||
raise AttributeError(
|
||||
'qubes.property should be used on qubes.PropertyHolder instances only')
|
||||
raise AttributeError('qubes.property should be used on '
|
||||
'qubes.PropertyHolder instances only')
|
||||
|
||||
try:
|
||||
return getattr(instance, self._attr_name)
|
||||
@ -618,14 +633,16 @@ class property(object):
|
||||
has_oldvalue = False
|
||||
|
||||
if has_oldvalue:
|
||||
instance.fire_event_pre('property-pre-deleted:' + self.__name__, oldvalue)
|
||||
instance.fire_event_pre('property-pre-deleted:' + self.__name__,
|
||||
oldvalue)
|
||||
else:
|
||||
instance.fire_event_pre('property-pre-deleted:' + self.__name__)
|
||||
|
||||
delattr(instance, self._attr_name)
|
||||
|
||||
if has_oldvalue:
|
||||
instance.fire_event('property-deleted:' + self.__name__, oldvalue)
|
||||
instance.fire_event('property-deleted:' + self.__name__,
|
||||
oldvalue)
|
||||
else:
|
||||
instance.fire_event('property-deleted:' + self.__name__)
|
||||
|
||||
@ -647,7 +664,8 @@ class property(object):
|
||||
'''Return parsed documentation string, stripping RST markup.
|
||||
'''
|
||||
|
||||
if not self.__doc__: return ''
|
||||
if not self.__doc__:
|
||||
return ''
|
||||
|
||||
output, pub = docutils.core.publish_programmatically(
|
||||
source_class=docutils.io.StringInput,
|
||||
@ -692,8 +710,9 @@ class property(object):
|
||||
:throws AttributeError: always
|
||||
'''
|
||||
|
||||
raise AttributeError('setting {} property on {} instance is forbidden'.format(
|
||||
prop.__name__, self.__class__.__name__))
|
||||
raise AttributeError(
|
||||
'setting {} property on {} instance is forbidden'.format(
|
||||
prop.__name__, self.__class__.__name__))
|
||||
|
||||
|
||||
@staticmethod
|
||||
@ -725,7 +744,8 @@ class PropertyHolder(qubes.events.Emitter):
|
||||
Fired once after all properties are loaded from XML. Individual
|
||||
``property-set`` events are not fired.
|
||||
|
||||
.. event:: property-set:<propname> (subject, event, name, newvalue[, oldvalue])
|
||||
.. event:: property-set:<propname> \
|
||||
(subject, event, name, newvalue[, oldvalue])
|
||||
|
||||
Fired when property changes state. Signature is variable,
|
||||
*oldvalue* is present only if there was an old value.
|
||||
@ -734,7 +754,8 @@ class PropertyHolder(qubes.events.Emitter):
|
||||
:param newvalue: New value of the property
|
||||
:param oldvalue: Old value of the property
|
||||
|
||||
.. event:: property-pre-set:<propname> (subject, event, name, newvalue[, oldvalue])
|
||||
.. event:: property-pre-set:<propname> \
|
||||
(subject, event, name, newvalue[, oldvalue])
|
||||
|
||||
Fired before property changes state. Signature is variable,
|
||||
*oldvalue* is present only if there was an old value.
|
||||
@ -743,7 +764,8 @@ class PropertyHolder(qubes.events.Emitter):
|
||||
:param newvalue: New value of the property
|
||||
:param oldvalue: Old value of the property
|
||||
|
||||
.. event:: property-del:<propname> (subject, event, name[, oldvalue])
|
||||
.. event:: property-del:<propname> \
|
||||
(subject, event, name[, oldvalue])
|
||||
|
||||
Fired when property gets deleted (is set to default). Signature is
|
||||
variable, *oldvalue* is present only if there was an old value.
|
||||
@ -751,7 +773,8 @@ class PropertyHolder(qubes.events.Emitter):
|
||||
:param name: Property name
|
||||
:param oldvalue: Old value of the property
|
||||
|
||||
.. event:: property-pre-del:<propname> (subject, event, name[, oldvalue])
|
||||
.. event:: property-pre-del:<propname> \
|
||||
(subject, event, name[, oldvalue])
|
||||
|
||||
Fired before property gets deleted (is set to default). Signature
|
||||
is variable, *oldvalue* is present only if there was an old value.
|
||||
@ -866,7 +889,9 @@ class PropertyHolder(qubes.events.Emitter):
|
||||
def xml_properties(self, with_defaults=False):
|
||||
'''Iterator that yields XML nodes representing set properties.
|
||||
|
||||
:param bool with_defaults: If :py:obj:`True`, then it also includes properties which were not set explicite, but have default values filled.
|
||||
:param bool with_defaults: If :py:obj:`True`, then it also includes \
|
||||
properties which were not set explicite, but have default values \
|
||||
filled.
|
||||
'''
|
||||
|
||||
|
||||
@ -899,7 +924,8 @@ class PropertyHolder(qubes.events.Emitter):
|
||||
'''Clone properties from other object.
|
||||
|
||||
:param PropertyHolder src: source object
|
||||
:param list proplist: list of properties (:py:obj:`None` for all properties)
|
||||
:param list proplist: list of properties \
|
||||
(:py:obj:`None` for all properties)
|
||||
'''
|
||||
|
||||
if proplist is None:
|
||||
@ -922,8 +948,10 @@ class PropertyHolder(qubes.events.Emitter):
|
||||
|
||||
:param prop: property name or object
|
||||
:type prop: qubes.property or str
|
||||
:param bool allow_none: if :py:obj:`True`, don't complain if :py:obj:`None` is found
|
||||
:param bool hard: if :py:obj:`True`, raise :py:class:`AssertionError`; if :py:obj:`False`, log warning instead
|
||||
:param bool allow_none: if :py:obj:`True`, don't complain if \
|
||||
:py:obj:`None` is found
|
||||
:param bool hard: if :py:obj:`True`, raise :py:class:`AssertionError`; \
|
||||
if :py:obj:`False`, log warning instead
|
||||
'''
|
||||
|
||||
if isinstance(qubes.property, prop):
|
||||
@ -949,18 +977,23 @@ class VMProperty(property):
|
||||
|
||||
:param type vmclass: class that returned VM is supposed to be instance of
|
||||
|
||||
and all supported by :py:class:`property` with the exception of ``type`` and ``setter``
|
||||
and all supported by :py:class:`property` with the exception of ``type`` \
|
||||
and ``setter``
|
||||
'''
|
||||
|
||||
def __init__(self, name, vmclass=qubes.vm.BaseVM, allow_none=False, **kwargs):
|
||||
def __init__(self, name, vmclass=qubes.vm.BaseVM, allow_none=False,
|
||||
**kwargs):
|
||||
if 'type' in kwargs:
|
||||
raise TypeError("'type' keyword parameter is unsupported in {}".format(
|
||||
self.__class__.__name__))
|
||||
raise TypeError(
|
||||
"'type' keyword parameter is unsupported in {}".format(
|
||||
self.__class__.__name__))
|
||||
if 'setter' in kwargs:
|
||||
raise TypeError("'setter' keyword parameter is unsupported in {}".format(
|
||||
self.__class__.__name__))
|
||||
raise TypeError(
|
||||
"'setter' keyword parameter is unsupported in {}".format(
|
||||
self.__class__.__name__))
|
||||
if not issubclass(vmclass, qubes.vm.BaseVM):
|
||||
raise TypeError("'vmclass' should specify a subclass of qubes.vm.BaseVM")
|
||||
raise TypeError(
|
||||
"'vmclass' should specify a subclass of qubes.vm.BaseVM")
|
||||
|
||||
super(VMProperty, self).__init__(name, **kwargs)
|
||||
self.vmclass = vmclass
|
||||
@ -981,8 +1014,10 @@ class VMProperty(property):
|
||||
vm = instance.app.domains[value]
|
||||
|
||||
if not isinstance(vm, self.vmclass):
|
||||
raise TypeError('wrong VM class: domains[{!r}] if of type {!s} and not {!s}'.format(
|
||||
value, vm.__class__.__name__, self.vmclass.__name__))
|
||||
raise TypeError('wrong VM class: domains[{!r}] if of type {!s} '
|
||||
'and not {!s}'.format(value,
|
||||
vm.__class__.__name__,
|
||||
self.vmclass.__name__))
|
||||
|
||||
super(VMProperty, self).__set__(self, instance, vm)
|
||||
|
||||
@ -1036,10 +1071,12 @@ class Qubes(PropertyHolder):
|
||||
Methods and attributes:
|
||||
'''
|
||||
|
||||
default_netvm = VMProperty('default_netvm', load_stage=3, default=None,
|
||||
default_netvm = VMProperty('default_netvm', load_stage=3,
|
||||
default=None,
|
||||
doc='''Default NetVM for AppVMs. Initial state is `None`, which means
|
||||
that AppVMs are not connected to the Internet.''')
|
||||
default_fw_netvm = VMProperty('default_fw_netvm', load_stage=3, default=None,
|
||||
default_fw_netvm = VMProperty('default_fw_netvm', load_stage=3,
|
||||
default=None,
|
||||
doc='''Default NetVM for ProxyVMs. Initial state is `None`, which means
|
||||
that ProxyVMs (including FirewallVM) are not connected to the
|
||||
Internet.''')
|
||||
@ -1274,25 +1311,25 @@ class Qubes(PropertyHolder):
|
||||
def on_property_pre_set_clockvm(self, event, name, newvalue, oldvalue=None):
|
||||
if 'ntpd' in newvalue.services:
|
||||
if newvalue.services['ntpd']:
|
||||
raise QubesException(
|
||||
'Cannot set {!r} as {!r} property since it has ntpd enabled.'.format(
|
||||
newvalue, name))
|
||||
raise QubesException('Cannot set {!r} as {!r} property since '
|
||||
'it has ntpd enabled.'.format(newvalue, name))
|
||||
else:
|
||||
newvalue.services['ntpd'] = False
|
||||
|
||||
|
||||
@qubes.events.handler('property-pre-set:default_netvm')
|
||||
def on_property_pre_set_default_netvm(self, event, name, newvalue, oldvalue=None):
|
||||
def on_property_pre_set_default_netvm(self, event, name, newvalue,
|
||||
oldvalue=None):
|
||||
if newvalue is not None and oldvalue is not None \
|
||||
and oldvalue.is_running() and not newvalue.is_running() \
|
||||
and self.domains.get_vms_connected_to(oldvalue):
|
||||
raise QubesException(
|
||||
'Cannot change default_netvm to domain that is not running ({!r}).'.format(
|
||||
newvalue))
|
||||
raise QubesException('Cannot change default_netvm to domain that '
|
||||
'is not running ({!r}).'.format(newvalue))
|
||||
|
||||
|
||||
@qubes.events.handler('property-set:default_fw_netvm')
|
||||
def on_property_set_default_netvm(self, event, name, newvalue, oldvalue=None):
|
||||
def on_property_set_default_netvm(self, event, name, newvalue,
|
||||
oldvalue=None):
|
||||
for vm in self.domains:
|
||||
if not vm.provides_network and vm.property_is_default('netvm'):
|
||||
# fire property-del:netvm as it is responsible for resetting
|
||||
@ -1301,7 +1338,8 @@ class Qubes(PropertyHolder):
|
||||
|
||||
|
||||
@qubes.events.handler('property-set:default_netvm')
|
||||
def on_property_set_default_netvm(self, event, name, newvalue, oldvalue=None):
|
||||
def on_property_set_default_netvm(self, event, name, newvalue,
|
||||
oldvalue=None):
|
||||
for vm in self.domains:
|
||||
if vm.provides_network and vm.property_is_default('netvm'):
|
||||
# fire property-del:netvm as it is responsible for resetting
|
||||
|
@ -22,7 +22,7 @@
|
||||
#
|
||||
#
|
||||
|
||||
qubes_base_dir = "/var/lib/qubes"
|
||||
qubes_base_dir = "/var/lib/qubes"
|
||||
system_path = {
|
||||
'qubes_guid_path': '/usr/bin/qubes-guid',
|
||||
'qrexec_daemon_path': '/usr/lib/qubes/qrexec-daemon',
|
||||
|
@ -35,7 +35,8 @@ def fetch_ticket_info(uri):
|
||||
reader = csv.reader((line + '\n' for line in data.split('\r\n')),
|
||||
quoting=csv.QUOTE_MINIMAL, quotechar='"')
|
||||
|
||||
return dict(zip(*((cell.decode('utf-8') for cell in row) for row in list(reader)[:2])))
|
||||
return dict(zip(*((cell.decode('utf-8') for cell in row)
|
||||
for row in list(reader)[:2])))
|
||||
|
||||
|
||||
def ticket(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
@ -45,14 +46,16 @@ def ticket(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
:param str rawtext: The entire markup snippet, with role
|
||||
:param str text: The text marked with the role
|
||||
:param int lineno: The line number where rawtext appears in the input
|
||||
:param docutils.parsers.rst.states.Inliner inliner: The inliner instance that called this function
|
||||
:param docutils.parsers.rst.states.Inliner inliner: The inliner instance \
|
||||
that called this function
|
||||
:param options: Directive options for customisation
|
||||
:param content: The directive content for customisation
|
||||
'''
|
||||
|
||||
ticket = text.lstrip('#')
|
||||
if not ticket.isdigit():
|
||||
msg = inliner.reporter.error('Invalid ticket identificator: {!r}'.format(text), line=lineno)
|
||||
msg = inliner.reporter.error(
|
||||
'Invalid ticket identificator: {!r}'.format(text), line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
return [prb], [msg]
|
||||
|
||||
@ -61,7 +64,8 @@ def ticket(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
try:
|
||||
info = fetch_ticket_info(uri)
|
||||
except urllib2.HTTPError, e:
|
||||
msg = inliner.reporter.error('Error while fetching ticket info: {!s}'.format(e), line=lineno)
|
||||
msg = inliner.reporter.error(
|
||||
'Error while fetching ticket info: {!s}'.format(e), line=lineno)
|
||||
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||
return [prb], [msg]
|
||||
|
||||
@ -76,7 +80,8 @@ def ticket(name, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
return [node], []
|
||||
|
||||
|
||||
class versioncheck(docutils.nodes.warning): pass
|
||||
class versioncheck(docutils.nodes.warning):
|
||||
pass
|
||||
|
||||
def visit(self, node):
|
||||
self.visit_admonition(node, 'version')
|
||||
@ -145,7 +150,8 @@ def parse_event(env, sig, signode):
|
||||
|
||||
def setup(app):
|
||||
app.add_role('ticket', ticket)
|
||||
app.add_config_value('ticket_base_uri', 'https://wiki.qubes-os.org/ticket/', 'env')
|
||||
app.add_config_value('ticket_base_uri',
|
||||
'https://wiki.qubes-os.org/ticket/', 'env')
|
||||
app.add_node(versioncheck,
|
||||
html=(visit, depart),
|
||||
man=(visit, depart))
|
||||
|
@ -106,7 +106,8 @@ class Emitter(object):
|
||||
if not hasattr(cls, '__handlers__'):
|
||||
continue
|
||||
for handler in sorted(cls.__handlers__[event],
|
||||
key=(lambda handler: hasattr(handler, 'ha_bound')), reverse=True):
|
||||
key=(lambda handler: hasattr(handler, 'ha_bound')),
|
||||
reverse=True):
|
||||
handler(self, event, *args, **kwargs)
|
||||
|
||||
|
||||
@ -127,7 +128,8 @@ class Emitter(object):
|
||||
different events.
|
||||
'''
|
||||
|
||||
self._fire_event_in_order(reversed(self.__class__.__mro__), event, *args, **kwargs)
|
||||
self._fire_event_in_order(reversed(self.__class__.__mro__), event,
|
||||
*args, **kwargs)
|
||||
|
||||
|
||||
def fire_event_pre(self, event, *args, **kwargs):
|
||||
@ -146,4 +148,5 @@ class Emitter(object):
|
||||
different events.
|
||||
'''
|
||||
|
||||
self._fire_event_in_order(self.__class__.__mro__, event, *args, **kwargs)
|
||||
self._fire_event_in_order(self.__class__.__mro__, event,
|
||||
*args, **kwargs)
|
||||
|
@ -29,7 +29,8 @@ class ExtensionPlugin(qubes.plugins.Plugin):
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls._instance is None:
|
||||
cls._instance = super(ExtensionPlugin, cls).__call__(*args, **kwargs)
|
||||
cls._instance = super(ExtensionPlugin, cls).__call__(
|
||||
*args, **kwargs)
|
||||
return cls._instance
|
||||
|
||||
class Extension(object):
|
||||
@ -67,7 +68,8 @@ def handler(*events, **kwargs):
|
||||
|
||||
:param str event: event type
|
||||
:param type vm: VM to hook (leave as None to hook all VMs)
|
||||
:param bool system: when :py:obj:`True`, hook is system-wide (not attached to any VM)
|
||||
:param bool system: when :py:obj:`True`, hook is system-wide (not attached \
|
||||
to any VM)
|
||||
'''
|
||||
|
||||
def decorator(f):
|
||||
|
@ -12,7 +12,8 @@ import sys
|
||||
|
||||
FORMAT_CONSOLE = '%(message)s'
|
||||
FORMAT_LOG = '%(asctime)s %(message)s'
|
||||
FORMAT_DEBUG = '%(asctime)s [%(processName)s %(module)s.%(funcName)s:%(lineno)d] %(name)s: %(message)s'
|
||||
FORMAT_DEBUG = '%(asctime)s ' \
|
||||
'[%(processName)s %(module)s.%(funcName)s:%(lineno)d] %(name)s: %(message)s'
|
||||
LOGPATH = '/var/log/qubes'
|
||||
LOGFILE = os.path.join(LOGPATH, 'qubes.log')
|
||||
|
||||
|
@ -24,10 +24,12 @@ class Element(object):
|
||||
|
||||
|
||||
def get_description(self, xml=None, wrap=True):
|
||||
if xml is None: xml = self.xml
|
||||
if xml is None:
|
||||
xml = self.xml
|
||||
|
||||
xml = xml.xpath('./doc:description', namespaces=self.nsmap)
|
||||
if not xml: return ''
|
||||
if not xml:
|
||||
return ''
|
||||
xml = xml[0]
|
||||
|
||||
if wrap:
|
||||
@ -38,7 +40,8 @@ class Element(object):
|
||||
|
||||
|
||||
def get_data_type(self, xml=None):
|
||||
if xml is None: xml = self.xml
|
||||
if xml is None:
|
||||
xml = self.xml
|
||||
|
||||
value = xml.xpath('./rng:value', namespaces=self.nsmap)
|
||||
if value:
|
||||
@ -75,7 +78,8 @@ class Element(object):
|
||||
|
||||
|
||||
def resolve_ref(self, ref):
|
||||
refs = self.xml.xpath('//rng:define[name="{}"]/rng:element'.format(ref['name']))
|
||||
refs = self.xml.xpath(
|
||||
'//rng:define[name="{}"]/rng:element'.format(ref['name']))
|
||||
return refs[0] if refs else None
|
||||
|
||||
|
||||
@ -83,7 +87,8 @@ class Element(object):
|
||||
for xml in self.xml.xpath('''./rng:element | ./rng:ref |
|
||||
./rng:optional/rng:element | ./rng:optional/rng:ref |
|
||||
./rng:zeroOrMore/rng:element | ./rng:zeroOrMore/rng:ref |
|
||||
./rng:oneOrMore/rng:element | ./rng:oneOrMore/rng:ref''', namespaces=self.nsmap):
|
||||
./rng:oneOrMore/rng:element | ./rng:oneOrMore/rng:ref''',
|
||||
namespaces=self.nsmap):
|
||||
parent = xml.getparent()
|
||||
qname = lxml.etree.QName(parent)
|
||||
if parent == self.xml:
|
||||
@ -99,7 +104,8 @@ class Element(object):
|
||||
|
||||
if xml.tag == 'ref':
|
||||
xml = self.resolve_ref(xml)
|
||||
if xml is None: continue
|
||||
if xml is None:
|
||||
continue
|
||||
|
||||
yield (self.schema.elements[xml.get('name')], n)
|
||||
|
||||
@ -124,7 +130,8 @@ class Element(object):
|
||||
write_rst_table(stream, attrtable,
|
||||
('attribute', 'req.', 'type', 'value', 'description'))
|
||||
|
||||
childtable = [(':ref:`{0} <qubesxml-element-{0}>`'.format(child.xml.get('name')), n)
|
||||
childtable = [(':ref:`{0} <qubesxml-element-{0}>`'.format(
|
||||
child.xml.get('name')), n)
|
||||
for child, n in self.get_child_elements()]
|
||||
if childtable:
|
||||
stream.write(make_rst_section('Child elements', '^'))
|
||||
@ -155,8 +162,10 @@ def make_rst_section(heading, c):
|
||||
|
||||
def write_rst_table(stream, it, heads):
|
||||
stream.write('.. csv-table::\n')
|
||||
stream.write(' :header: {}\n'.format(', '.join('"{}"'.format(c) for c in heads)))
|
||||
stream.write(' :widths: {}\n\n'.format(', '.join('1' for c in heads)))
|
||||
stream.write(' :header: {}\n'.format(', '.join('"{}"'.format(c)
|
||||
for c in heads)))
|
||||
stream.write(' :widths: {}\n\n'.format(', '.join('1'
|
||||
for c in heads)))
|
||||
|
||||
for row in it:
|
||||
stream.write(' {}\n'.format(', '.join('"{}"'.format(i) for i in row)))
|
||||
@ -168,9 +177,14 @@ def main(filename, example):
|
||||
schema = Schema(lxml.etree.parse(open(filename, 'rb')))
|
||||
|
||||
sys.stdout.write(make_rst_section('Qubes XML specification', '='))
|
||||
sys.stdout.write('This is the documentation of qubes.xml autogenerated from RelaxNG source.\n\n')
|
||||
sys.stdout.write('Quick example, worth thousands lines of specification:\n\n')
|
||||
sys.stdout.write('.. literalinclude:: {}\n :language: xml\n\n'.format(example))
|
||||
sys.stdout.write('''
|
||||
This is the documentation of qubes.xml autogenerated from RelaxNG source.
|
||||
|
||||
Quick example, worth thousands lines of specification:
|
||||
.. literalinclude:: {}
|
||||
:language: xml
|
||||
|
||||
'''[1:].format(example))
|
||||
|
||||
for name in sorted(schema.elements):
|
||||
schema.elements[name].write_rst(sys.stdout)
|
||||
|
@ -47,7 +47,8 @@ class XenVMStorage(qubes.storage.VMStorage):
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _format_disk_dev(path, vdev, script=None, rw=True, type='disk', domain=None):
|
||||
def _format_disk_dev(path, vdev, script=None, rw=True, type='disk',
|
||||
domain=None):
|
||||
if path is None:
|
||||
return ''
|
||||
|
||||
@ -130,9 +131,9 @@ class XenVMStorage(qubes.storage.VMStorage):
|
||||
|
||||
def create_on_disk_root_img(self, source_template=None):
|
||||
if source_template is None:
|
||||
f_root = open (self.root_img, "a+b")
|
||||
f_root.truncate (self.root_img_size)
|
||||
f_root.close ()
|
||||
fd = open(self.root_img, 'a+b')
|
||||
fd.truncate(self.root_img_size)
|
||||
fd.close()
|
||||
|
||||
elif self.vm.updateable:
|
||||
# if not updateable, just use template's disk
|
||||
@ -142,9 +143,9 @@ class XenVMStorage(qubes.storage.VMStorage):
|
||||
|
||||
|
||||
def resize_private_img(self, size):
|
||||
f_private = open(self.private_img, "a+b")
|
||||
f_private.truncate(size)
|
||||
f_private.close()
|
||||
fd = open(self.private_img, 'a+b')
|
||||
fd.truncate(size)
|
||||
fd.close()
|
||||
|
||||
# find loop device if any
|
||||
p = subprocess.Popen(
|
||||
@ -166,7 +167,7 @@ class XenVMStorage(qubes.storage.VMStorage):
|
||||
|
||||
# TODO: move rootcow_img to this class; the same for vm.is_outdated()
|
||||
if os.path.exists(self.vm.rootcow_img):
|
||||
os.rename(self.vm.rootcow_img, self.vm.rootcow_img + '.old')
|
||||
os.rename(self.vm.rootcow_img, self.vm.rootcow_img + '.old')
|
||||
|
||||
old_umask = os.umask(002)
|
||||
f_cow = open(self.vm.rootcow_img, 'w')
|
||||
|
@ -14,7 +14,8 @@ import qubes.events
|
||||
#: :py:obj:`True` if running in dom0, :py:obj:`False` otherwise
|
||||
in_dom0 = False
|
||||
|
||||
#: :py:obj:`False` if outside of git repo, path to root of the directory otherwise
|
||||
#: :py:obj:`False` if outside of git repo,
|
||||
#: path to root of the directory otherwise
|
||||
in_git = False
|
||||
|
||||
try:
|
||||
@ -26,7 +27,8 @@ except libvirt.libvirtError:
|
||||
pass
|
||||
|
||||
try:
|
||||
in_git = subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).strip()
|
||||
in_git = subprocess.check_output(
|
||||
['git', 'rev-parse', '--show-toplevel']).strip()
|
||||
except subprocess.CalledProcessError:
|
||||
# git returned nonzero, we are outside git repo
|
||||
pass
|
||||
@ -120,8 +122,10 @@ class QubesTestCase(unittest.TestCase):
|
||||
:param emitter: emitter which is being checked
|
||||
:type emitter: :py:class:`TestEmitter`
|
||||
:param str event: event identifier
|
||||
:param list args: when given, all items must appear in args passed to event
|
||||
:param list kwargs: when given, all items must appear in kwargs passed to event
|
||||
:param list args: when given, all items must appear in args passed to \
|
||||
an event
|
||||
:param list kwargs: when given, all items must appear in kwargs passed \
|
||||
to an event
|
||||
'''
|
||||
|
||||
for ev, ev_args, ev_kwargs in emitter.fired_events:
|
||||
@ -143,8 +147,10 @@ class QubesTestCase(unittest.TestCase):
|
||||
:param emitter: emitter which is being checked
|
||||
:type emitter: :py:class:`TestEmitter`
|
||||
:param str event: event identifier
|
||||
:param list args: when given, all items must appear in args passed to event
|
||||
:param list kwargs: when given, all items must appear in kwargs passed to event
|
||||
:param list args: when given, all items must appear in args passed to \
|
||||
an event
|
||||
:param list kwargs: when given, all items must appear in kwargs passed \
|
||||
to an event
|
||||
'''
|
||||
|
||||
for ev, ev_args, ev_kwargs in emitter.fired_events:
|
||||
@ -166,7 +172,7 @@ class QubesTestCase(unittest.TestCase):
|
||||
Schema can be given in a couple of ways:
|
||||
|
||||
- As separate file. This is most common, and also the only way to
|
||||
handle file inclusion. Call with file name as second argument.
|
||||
handle file inclusion. Call with file name as second argument.
|
||||
|
||||
- As string containing actual schema. Put that string in *schema*
|
||||
keyword argument.
|
||||
|
@ -82,7 +82,8 @@ class TC_10_property(qubes.tests.QubesTestCase):
|
||||
|
||||
def test_023_get_default_func(self):
|
||||
class TestHolder(qubes.tests.TestEmitter, qubes.PropertyHolder):
|
||||
testprop1 = qubes.property('testprop1', default=(lambda self: 'defaultvalue'))
|
||||
testprop1 = qubes.property('testprop1',
|
||||
default=(lambda self: 'defaultvalue'))
|
||||
holder = TestHolder(None)
|
||||
|
||||
self.assertEqual(holder.testprop1, 'defaultvalue')
|
||||
@ -202,7 +203,8 @@ class TC_20_PropertyHolder(qubes.tests.QubesTestCase):
|
||||
expected_prop1.text = 'testvalue1'
|
||||
self.assertXMLEqual(elements_with_defaults[0], expected_prop1)
|
||||
|
||||
expected_prop2 = lxml.etree.Element('property', name='testprop2', ref='testref2')
|
||||
expected_prop2 = lxml.etree.Element('property',
|
||||
name='testprop2', ref='testref2')
|
||||
self.assertXMLEqual(elements_with_defaults[1], expected_prop2)
|
||||
|
||||
expected_prop3 = lxml.etree.Element('property', name='testprop3')
|
||||
@ -285,7 +287,8 @@ class TC_30_VMCollection(qubes.tests.QubesTestCase):
|
||||
self.vms.add(self.testvm1)
|
||||
self.vms.add(self.testvm2)
|
||||
|
||||
self.assertItemsEqual(self.vms.items(), [(1, self.testvm1), (2, self.testvm2)])
|
||||
self.assertItemsEqual(self.vms.items(),
|
||||
[(1, self.testvm1), (2, self.testvm2)])
|
||||
|
||||
def test_007_len(self):
|
||||
self.vms.add(self.testvm1)
|
||||
@ -324,8 +327,10 @@ class TC_30_VMCollection(qubes.tests.QubesTestCase):
|
||||
class TC_90_Qubes(qubes.tests.QubesTestCase):
|
||||
@qubes.tests.skipUnlessDom0
|
||||
def test_000_init_empty(self):
|
||||
try: os.unlink('/tmp/qubestest.xml')
|
||||
except: pass
|
||||
try:
|
||||
os.unlink('/tmp/qubestest.xml')
|
||||
except:
|
||||
pass
|
||||
app = qubes.Qubes('/tmp/qubestest.xml')
|
||||
|
||||
@qubes.tests.skipUnlessGit
|
||||
|
@ -143,8 +143,8 @@ class ANSITestResult(unittest.TestResult):
|
||||
super(ANSITestResult, self).addUnexpectedSuccess(test)
|
||||
if self.showAll:
|
||||
self.stream.writeln(
|
||||
'{color[yellow]}{color[bold]}unexpected success{color[normal]}'.format(
|
||||
color=self.color))
|
||||
'{color[yellow]}{color[bold]}unexpected success'
|
||||
'{color[normal]}'.format(color=self.color))
|
||||
elif self.dots:
|
||||
self.stream.write(
|
||||
'{color[yellow]}{color[bold]}u{color[normal]}'.format(
|
||||
@ -165,7 +165,7 @@ class ANSITestResult(unittest.TestResult):
|
||||
def printErrorList(self, flavour, errors):
|
||||
for test, err in errors:
|
||||
self.stream.writeln(self.separator1)
|
||||
self.stream.writeln('%s: %s' % (flavour,self.getDescription(test)))
|
||||
self.stream.writeln('%s: %s' % (flavour, self.getDescription(test)))
|
||||
self.stream.writeln(self.separator2)
|
||||
self.stream.writeln('%s' % err)
|
||||
|
||||
|
@ -76,5 +76,5 @@ class TC_00_setters(qubes.tests.QubesTestCase):
|
||||
|
||||
class TC_90_QubesVM(qubes.tests.QubesTestCase):
|
||||
@unittest.skip('test not implemented')
|
||||
def test_000_init(self):
|
||||
def test_000_init(self):
|
||||
pass
|
||||
|
@ -1,4 +1,28 @@
|
||||
#!/usr/bin/python2 -O
|
||||
# vim: fileencoding=utf-8
|
||||
|
||||
#
|
||||
# The Qubes OS Project, https://www.qubes-os.org/
|
||||
#
|
||||
# Copyright (C) 2010-2015 Joanna Rutkowska <joanna@invisiblethingslab.com>
|
||||
# Copyright (C) 2011-2015 Marek Marczykowski-Górecki
|
||||
# <marmarek@invisiblethingslab.com>
|
||||
# Copyright (C) 2014-2015 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.
|
||||
#
|
||||
|
||||
'''Qubes Virtual Machines
|
||||
|
||||
@ -92,7 +116,8 @@ class DeviceCollection(object):
|
||||
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._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)
|
||||
|
||||
@ -107,7 +132,8 @@ class DeviceCollection(object):
|
||||
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._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)
|
||||
|
||||
@ -161,7 +187,8 @@ class BaseVM(qubes.PropertyHolder):
|
||||
self.tags = tags
|
||||
|
||||
self.events_enabled = False
|
||||
all_names = set(prop.__name__ for prop in self.get_props_list(load_stage=2))
|
||||
all_names = set(prop.__name__
|
||||
for prop in self.get_props_list(load_stage=2))
|
||||
for key in list(kwargs.keys()):
|
||||
if not key in all_names:
|
||||
raise AttributeError(
|
||||
@ -184,8 +211,8 @@ class BaseVM(qubes.PropertyHolder):
|
||||
vm_cls = QubesVmClasses[vm_type]
|
||||
if 'template' in kwargs:
|
||||
if not vm_cls.is_template_compatible(kwargs['template']):
|
||||
raise QubesException("Template not compatible with selected "
|
||||
"VM type")
|
||||
raise QubesException(
|
||||
'Template not compatible with selected VM type')
|
||||
|
||||
vm = vm_cls(qid=qid, collection=self, **kwargs)
|
||||
if not self.verify_new_vm(vm):
|
||||
@ -219,11 +246,10 @@ class BaseVM(qubes.PropertyHolder):
|
||||
|
||||
:param qubes.Qubes app: :py:class:`qubes.Qubes` application instance
|
||||
:param lxml.etree._Element xml: XML node reference
|
||||
:param int load_stage: do not change the default (2) unless you know, what you are doing
|
||||
:param int load_stage: do not change the default (2) unless you know, \
|
||||
what you are doing
|
||||
'''
|
||||
|
||||
# sys.stderr.write('{}.fromxml(app={!r}, xml={!r}, load_stage={})\n'.format(
|
||||
# cls.__name__, app, xml, load_stage))
|
||||
if xml is None:
|
||||
return cls(app)
|
||||
|
||||
@ -233,7 +259,8 @@ class BaseVM(qubes.PropertyHolder):
|
||||
|
||||
# services
|
||||
for node in xml.xpath('./services/service'):
|
||||
services[node.text] = bool(ast.literal_eval(node.get('enabled', 'True')))
|
||||
services[node.text] = bool(
|
||||
ast.literal_eval(node.get('enabled', 'True')))
|
||||
|
||||
# devices (pci, usb, ...)
|
||||
for parent in xml.xpath('./devices'):
|
||||
@ -375,7 +402,8 @@ class BaseVM(qubes.PropertyHolder):
|
||||
args['vcpus'] = str(self.vcpus)
|
||||
args['mem'] = str(max(self.memory, self.maxmem))
|
||||
|
||||
if 'meminfo-writer' in self.services and not self.services['meminfo-writer']:
|
||||
if 'meminfo-writer' in self.services \
|
||||
and not self.services['meminfo-writer']:
|
||||
# If dynamic memory management disabled, set maxmem=mem
|
||||
args['maxmem'] = args['mem']
|
||||
|
||||
@ -386,9 +414,10 @@ class BaseVM(qubes.PropertyHolder):
|
||||
args['dns1'] = self.netvm.gateway
|
||||
args['dns2'] = self.secondary_dns
|
||||
args['netmask'] = self.netmask
|
||||
args['netdev'] = lxml.etree.tostring(self.lvxml_net_dev(self.ip, self.mac, self.netvm))
|
||||
args['disable_network1'] = '';
|
||||
args['disable_network2'] = '';
|
||||
args['netdev'] = lxml.etree.tostring(
|
||||
self.lvxml_net_dev(self.ip, self.mac, self.netvm))
|
||||
args['disable_network1'] = ''
|
||||
args['disable_network2'] = ''
|
||||
else:
|
||||
args['ip'] = ''
|
||||
args['mac'] = ''
|
||||
@ -397,15 +426,16 @@ class BaseVM(qubes.PropertyHolder):
|
||||
args['dns2'] = ''
|
||||
args['netmask'] = ''
|
||||
args['netdev'] = ''
|
||||
args['disable_network1'] = '<!--';
|
||||
args['disable_network2'] = '-->';
|
||||
args['disable_network1'] = '<!--'
|
||||
args['disable_network2'] = '-->'
|
||||
|
||||
args.update(self.storage.get_config_params())
|
||||
|
||||
if hasattr(self, 'kernelopts'):
|
||||
args['kernelopts'] = self.kernelopts
|
||||
if self.debug:
|
||||
self.log.info("Debug mode: adding 'earlyprintk=xen' to kernel opts")
|
||||
self.log.info(
|
||||
"Debug mode: adding 'earlyprintk=xen' to kernel opts")
|
||||
args['kernelopts'] += ' earlyprintk=xen'
|
||||
|
||||
|
||||
@ -415,8 +445,10 @@ class BaseVM(qubes.PropertyHolder):
|
||||
If :py:attr:`qubes.vm.qubesvm.QubesVM.uses_custom_config` is true, this
|
||||
does nothing.
|
||||
|
||||
:param str file_path: Path to file to create (default: :py:attr:`qubes.vm.qubesvm.QubesVM.conf_file`)
|
||||
:param bool prepare_dvm: If we are in the process of preparing DisposableVM
|
||||
:param str file_path: Path to file to create \
|
||||
(default: :py:attr:`qubes.vm.qubesvm.QubesVM.conf_file`)
|
||||
:param bool prepare_dvm: If we are in the process of preparing \
|
||||
DisposableVM
|
||||
'''
|
||||
|
||||
if file_path is None:
|
||||
@ -435,7 +467,8 @@ class BaseVM(qubes.PropertyHolder):
|
||||
if prepare_dvm:
|
||||
template_params['name'] = '%NAME%'
|
||||
template_params['privatedev'] = ''
|
||||
template_params['netdev'] = re.sub(r"address='[0-9.]*'", "address='%IP%'", template_params['netdev'])
|
||||
template_params['netdev'] = re.sub(r"address='[0-9.]*'",
|
||||
"address='%IP%'", template_params['netdev'])
|
||||
domain_config = conf_template.format(**template_params)
|
||||
|
||||
# FIXME: This is only for debugging purposes
|
||||
@ -470,11 +503,10 @@ class BaseVM(qubes.PropertyHolder):
|
||||
|
||||
root = lxml.etree.Element(
|
||||
"QubesFirewallRules",
|
||||
policy = "allow" if conf["allow"] else "deny",
|
||||
dns = "allow" if conf["allowDns"] else "deny",
|
||||
icmp = "allow" if conf["allowIcmp"] else "deny",
|
||||
yumProxy = "allow" if conf["allowYumProxy"] else "deny"
|
||||
)
|
||||
policy=("allow" if conf["allow"] else "deny"),
|
||||
dns=("allow" if conf["allowDns"] else "deny"),
|
||||
icmp=("allow" if conf["allowIcmp"] else "deny"),
|
||||
yumProxy=("allow" if conf["allowYumProxy"] else "deny"))
|
||||
|
||||
for rule in conf["rules"]:
|
||||
# For backward compatibility
|
||||
@ -514,7 +546,8 @@ class BaseVM(qubes.PropertyHolder):
|
||||
os.path.basename(sys.argv[0]), err)
|
||||
return False
|
||||
|
||||
# Automatically enable/disable 'yum-proxy-setup' service based on allowYumProxy
|
||||
# Automatically enable/disable 'yum-proxy-setup' service based on
|
||||
# allowYumProxy
|
||||
if conf['allowYumProxy']:
|
||||
self.services['yum-proxy-setup'] = True
|
||||
else:
|
||||
@ -528,10 +561,15 @@ class BaseVM(qubes.PropertyHolder):
|
||||
return True
|
||||
|
||||
def has_firewall(self):
|
||||
return os.path.exists (self.firewall_conf)
|
||||
return os.path.exists(self.firewall_conf)
|
||||
|
||||
def get_firewall_defaults(self):
|
||||
return { "rules": list(), "allow": True, "allowDns": True, "allowIcmp": True, "allowYumProxy": False }
|
||||
return {
|
||||
'rules': list(),
|
||||
'allow': True,
|
||||
'allowDns': True,
|
||||
'allowIcmp': True,
|
||||
'allowYumProxy': False}
|
||||
|
||||
def get_firewall_conf(self):
|
||||
conf = self.get_firewall_defaults()
|
||||
@ -582,10 +620,10 @@ class BaseVM(qubes.PropertyHolder):
|
||||
"%s")):
|
||||
continue
|
||||
else:
|
||||
del(rule["expire"])
|
||||
del rule["expire"]
|
||||
|
||||
del(rule["port"])
|
||||
del(rule["toport"])
|
||||
del rule["port"]
|
||||
del rule["toport"]
|
||||
|
||||
conf["rules"].append(rule)
|
||||
|
||||
|
@ -122,7 +122,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
`None`, machine is disconnected. When absent, domain uses default
|
||||
NetVM.''')
|
||||
|
||||
provides_network = qubes.property('provides_network', type=bool,
|
||||
provides_network = qubes.property('provides_network',
|
||||
type=bool, setter=qubes.property.bool,
|
||||
doc='`True` if it is NetVM or ProxyVM, false otherwise.')
|
||||
|
||||
qid = qubes.property('qid', type=int,
|
||||
@ -150,20 +151,22 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
firewall_conf = qubes.property('firewall_conf', type=str,
|
||||
default='firewall.xml')
|
||||
|
||||
installed_by_rpm = qubes.property('installed_by_rpm', type=bool, default=False,
|
||||
setter=qubes.property.bool,
|
||||
installed_by_rpm = qubes.property('installed_by_rpm',
|
||||
type=bool, setter=qubes.property.bool,
|
||||
default=False,
|
||||
doc='''If this domain's image was installed from package tracked by
|
||||
package manager.''')
|
||||
|
||||
memory = qubes.property('memory', type=int, default=qubes.config.defaults['memory'],
|
||||
memory = qubes.property('memory', type=int,
|
||||
default=qubes.config.defaults['memory'],
|
||||
doc='Memory currently available for this VM.')
|
||||
|
||||
maxmem = qubes.property('maxmem', type=int, default=None,
|
||||
doc='''Maximum amount of memory available for this VM (for the purpose
|
||||
of the memory balancer).''')
|
||||
|
||||
internal = qubes.property('internal', type=bool, default=False,
|
||||
setter=qubes.property.bool,
|
||||
internal = qubes.property('internal', default=False,
|
||||
type=bool, setter=qubes.property.bool,
|
||||
doc='''Internal VM (not shown in qubes-manager, don't create appmenus
|
||||
entries.''')
|
||||
|
||||
@ -213,18 +216,18 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
failed. Operating system inside VM should be able to boot in this
|
||||
time.''')
|
||||
|
||||
autostart = qubes.property('autostart', type=bool, default=False,
|
||||
setter=qubes.property.bool,
|
||||
doc='''Setting this to `True` means that VM should be autostarted on dom0
|
||||
boot.''')
|
||||
autostart = qubes.property('autostart', default=False,
|
||||
type=bool, setter=qubes.property.bool,
|
||||
doc='''Setting this to `True` means that VM should be autostarted on
|
||||
dom0 boot.''')
|
||||
|
||||
# XXX I don't understand backups
|
||||
include_in_backups = qubes.property('include_in_backups', type=bool, default=True,
|
||||
setter=qubes.property.bool,
|
||||
include_in_backups = qubes.property('include_in_backups', default=True,
|
||||
type=bool, setter=qubes.property.bool,
|
||||
doc='If this domain is to be included in default backup.')
|
||||
|
||||
backup_content = qubes.property('backup_content', type=bool, default=False,
|
||||
setter=qubes.property.bool,
|
||||
backup_content = qubes.property('backup_content', default=False,
|
||||
type=bool, setter=qubes.property.bool,
|
||||
doc='FIXME')
|
||||
|
||||
backup_size = qubes.property('backup_size', type=int, default=0,
|
||||
@ -235,7 +238,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
# format got changed from %s to str(datetime.datetime)
|
||||
backup_timestamp = qubes.property('backup_timestamp', default=None,
|
||||
setter=(lambda self, prop, value: datetime.datetime.fromtimestamp(value)),
|
||||
setter=(lambda self, prop, value:
|
||||
datetime.datetime.fromtimestamp(value)),
|
||||
saver=(lambda self, prop, value: value.strftime('%s')),
|
||||
doc='FIXME')
|
||||
|
||||
@ -279,12 +283,14 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
# XXX _update_libvirt_domain?
|
||||
try:
|
||||
if self.uuid is not None:
|
||||
self._libvirt_domain = vmm.libvirt_conn.lookupByUUID(self.uuid.bytes)
|
||||
self._libvirt_domain = vmm.libvirt_conn.lookupByUUID(
|
||||
self.uuid.bytes)
|
||||
else:
|
||||
self._libvirt_domain = vmm.libvirt_conn.lookupByName(self.name)
|
||||
self.uuid = uuid.UUID(bytes=self._libvirt_domain.UUID())
|
||||
except libvirt.libvirtError:
|
||||
if vmm.libvirt_conn.virConnGetLastError()[0] == libvirt.VIR_ERR_NO_DOMAIN:
|
||||
if vmm.libvirt_conn.virConnGetLastError()[0] == \
|
||||
libvirt.VIR_ERR_NO_DOMAIN:
|
||||
self._update_libvirt_domain()
|
||||
else:
|
||||
raise
|
||||
@ -303,7 +309,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
# XXX this should go to to AppVM?
|
||||
@property
|
||||
def private_img(self):
|
||||
'''Location of private image of the VM (that contains :file:`/rw` and :file:`/home`).'''
|
||||
'''Location of private image of the VM (that contains :file:`/rw` \
|
||||
and :file:`/home`).'''
|
||||
return self.storage.private_img
|
||||
|
||||
|
||||
@ -427,7 +434,7 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
# Always set if meminfo-writer should be active or not
|
||||
if 'meminfo-writer' not in self.services:
|
||||
self.services['meminfo-writer'] = not (len(self.devices['pci']) > 0)
|
||||
self.services['meminfo-writer'] = not len(self.devices['pci']) > 0
|
||||
|
||||
# Additionally force meminfo-writer disabled when VM have PCI devices
|
||||
if len(self.devices['pci']) > 0:
|
||||
@ -468,13 +475,15 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
def on_property_del_netvm(self, event, name, old_netvm):
|
||||
# we are changing to default netvm
|
||||
new_netvm = self.netvm
|
||||
if new_netvm == old_netvm: return
|
||||
if new_netvm == old_netvm:
|
||||
return
|
||||
self.fire_event('property-set:netvm', 'netvm', new_netvm, old_netvm)
|
||||
|
||||
|
||||
@qubes.events.handler('property-set:netvm')
|
||||
def on_property_set_netvm(self, event, name, new_netvm, old_netvm=None):
|
||||
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")
|
||||
|
||||
if self.netvm is not None:
|
||||
@ -490,11 +499,13 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
if not self._do_not_reset_firewall:
|
||||
# Set also firewall to block all traffic as discussed in #370
|
||||
if os.path.exists(self.firewall_conf):
|
||||
shutil.copy(self.firewall_conf, os.path.join(system_path["qubes_base_dir"],
|
||||
"backup", "%s-firewall-%s.xml" % (self.name,
|
||||
shutil.copy(self.firewall_conf,
|
||||
os.path.join(system_path["qubes_base_dir"],
|
||||
"backup",
|
||||
"%s-firewall-%s.xml" % (self.name,
|
||||
time.strftime('%Y-%m-%d-%H:%M:%S'))))
|
||||
self.write_firewall_conf({'allow': False, 'allowDns': False,
|
||||
'allowIcmp': False, 'allowYumProxy': False, 'rules': []})
|
||||
'allowIcmp': False, 'allowYumProxy': False, 'rules': []})
|
||||
else:
|
||||
new_netvm.connected_vms.add(self)
|
||||
|
||||
@ -554,13 +565,15 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
new_conf, old_conf)
|
||||
|
||||
if hasattr(self, 'kernels_dir') and self.kernels_dir is not None:
|
||||
self.kernels_dir = self.kernels_dir.replace(old_dirpath, new_dirpath)
|
||||
self.kernels_dir = self.kernels_dir.replace(
|
||||
old_dirpath, new_dirpath)
|
||||
|
||||
self._update_libvirt_domain()
|
||||
|
||||
|
||||
@qubes.events.handler('property-pre-set:autostart')
|
||||
def on_property_pre_set_autostart(self, event, prop, name, value, oldvalue=None):
|
||||
def on_property_pre_set_autostart(self, event, prop, name, value,
|
||||
oldvalue=None):
|
||||
if subprocess.call(['sudo', 'systemctl',
|
||||
('enable' if value else 'disable'),
|
||||
'qubes-vm@{}.service'.format(self.name)]):
|
||||
@ -576,8 +589,10 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
try:
|
||||
# TODO: libvirt-ise
|
||||
subprocess.check_call(['sudo', system_path["qubes_pciback_cmd"], pci])
|
||||
subprocess.check_call(['sudo', 'xl', 'pci-attach', str(self.xid), pci])
|
||||
subprocess.check_call(
|
||||
['sudo', system_path["qubes_pciback_cmd"], pci])
|
||||
subprocess.check_call(
|
||||
['sudo', 'xl', 'pci-attach', str(self.xid), pci])
|
||||
except Exception as e:
|
||||
print >>sys.stderr, "Failed to attach PCI device on the fly " \
|
||||
"(%s), changes will be seen after VM restart" % str(e)
|
||||
@ -592,15 +607,17 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
p = subprocess.Popen(['xl', 'pci-list', str(self.xid)],
|
||||
stdout=subprocess.PIPE)
|
||||
result = p.communicate()
|
||||
m = re.search(r"^(\d+.\d+)\s+0000:%s$" % pci, result[0], flags=re.MULTILINE)
|
||||
m = re.search(r"^(\d+.\d+)\s+0000:%s$" % pci, result[0],
|
||||
flags=re.MULTILINE)
|
||||
if not m:
|
||||
print >>sys.stderr, "Device %s already detached" % pci
|
||||
return
|
||||
vmdev = m.group(1)
|
||||
try:
|
||||
self.run_service("qubes.DetachPciDevice",
|
||||
user="root", input="00:%s" % vmdev)
|
||||
subprocess.check_call(['sudo', 'xl', 'pci-detach', str(self.xid), pci])
|
||||
user="root", input="00:%s" % vmdev)
|
||||
subprocess.check_call(
|
||||
['sudo', 'xl', 'pci-detach', str(self.xid), pci])
|
||||
except Exception as e:
|
||||
print >>sys.stderr, "Failed to detach PCI device on the fly " \
|
||||
"(%s), changes will be seen after VM restart" % str(e)
|
||||
@ -620,7 +637,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
:param int mem_required: FIXME
|
||||
'''
|
||||
|
||||
# Intentionally not used is_running(): eliminate also "Paused", "Crashed", "Halting"
|
||||
# Intentionally not used is_running(): eliminate also "Paused",
|
||||
# "Crashed", "Halting"
|
||||
if self.get_power_state() != "Halted":
|
||||
raise QubesException("VM is already running!")
|
||||
|
||||
@ -631,7 +649,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
if self.netvm is not None:
|
||||
if self.netvm.qid != 0:
|
||||
if not self.netvm.is_running():
|
||||
self.netvm.start(start_guid=start_guid, notify_function=notify_function)
|
||||
self.netvm.start(start_guid=start_guid,
|
||||
notify_function=notify_function)
|
||||
|
||||
self.storage.prepare_for_vm_startup()
|
||||
self._update_libvirt_domain()
|
||||
@ -643,19 +662,22 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
try:
|
||||
got_memory = qmemman_client.request_memory(mem_required)
|
||||
except IOError as e:
|
||||
raise IOError("ERROR: Failed to connect to qmemman: %s" % str(e))
|
||||
raise IOError('Failed to connect to qmemman: {!s}'.format(e))
|
||||
if not got_memory:
|
||||
qmemman_client.close()
|
||||
raise MemoryError("ERROR: insufficient memory to start VM '%s'" % self.name)
|
||||
raise MemoryError(
|
||||
'Insufficient memory to start VM {!r}'.format(self.name))
|
||||
|
||||
# Bind pci devices to pciback driver
|
||||
for pci in self.devices['pci']:
|
||||
nd = vmm.libvirt_conn.nodeDeviceLookupByName('pci_0000_' + pci.replace(':','_').replace('.','_'))
|
||||
nd = vmm.libvirt_conn.nodeDeviceLookupByName(
|
||||
'pci_0000_' + pci.replace(':', '_').replace('.', '_'))
|
||||
try:
|
||||
nd.dettach()
|
||||
except libvirt.libvirtError:
|
||||
if vmm.libvirt_conn.virConnGetLastError()[0] == libvirt.VIR_ERR_INTERNAL_ERROR:
|
||||
# allready detached
|
||||
if vmm.libvirt_conn.virConnGetLastError()[0] == \
|
||||
libvirt.VIR_ERR_INTERNAL_ERROR:
|
||||
# already detached
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
@ -675,7 +697,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
if vm.is_proxyvm() and vm.is_running():
|
||||
vm.write_iptables_xenstore_entry()
|
||||
|
||||
self.fire_event('domain-started', preparing_dvm=preparing_dvm, start_guid=start_guid)
|
||||
self.fire_event('domain-started',
|
||||
preparing_dvm=preparing_dvm, start_guid=start_guid)
|
||||
|
||||
|
||||
self.log.warning('Activating the {} VM'.format(self.name))
|
||||
@ -689,13 +712,15 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
if qmemman_present:
|
||||
qmemman_client.close()
|
||||
|
||||
if self._start_guid_first and start_guid and not preparing_dvm and os.path.exists('/var/run/shm.id'):
|
||||
if self._start_guid_first and start_guid and not preparing_dvm \
|
||||
and os.path.exists('/var/run/shm.id'):
|
||||
self.start_guid(notify_function=notify_function)
|
||||
|
||||
if not preparing_dvm:
|
||||
self.start_qrexec_daemon(notify_function=notify_function)
|
||||
|
||||
if start_guid and not preparing_dvm and os.path.exists('/var/run/shm.id'):
|
||||
if start_guid and not preparing_dvm \
|
||||
and os.path.exists('/var/run/shm.id'):
|
||||
self.start_guid(notify_function=notify_function)
|
||||
|
||||
|
||||
@ -740,7 +765,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
|
||||
def pause(self):
|
||||
'''Pause (suspend) domain. This currently delegates to :py:meth:`suspend`.'''
|
||||
'''Pause (suspend) domain. This currently delegates to \
|
||||
:py:meth:`suspend`.'''
|
||||
|
||||
if not self.is_running():
|
||||
raise QubesException("VM not running!")
|
||||
@ -775,16 +801,22 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
:param str command: the command to be run
|
||||
:param str user: user to run the command as
|
||||
:param bool autostart: if :py:obj:`True`, machine will be started if it is not running
|
||||
:param bool autostart: if :py:obj:`True`, machine will be started if \
|
||||
it is not running
|
||||
:param collections.Callable notify_function: FIXME, may go away
|
||||
:param bool passio: FIXME
|
||||
:param bool passio_popen: if :py:obj:`True`, :py:class:`subprocess.Popen` object has connected ``stdin`` and ``stdout``
|
||||
:param bool passio_stderr: if :py:obj:`True`, :py:class:`subprocess.Popen` has additionaly ``stderr`` connected
|
||||
:param bool ignore_stderr: if :py:obj:`True`, ``stderr`` is connected to :file:`/dev/null`
|
||||
:param bool passio_popen: if :py:obj:`True`, \
|
||||
:py:class:`subprocess.Popen` object has connected ``stdin`` and \
|
||||
``stdout``
|
||||
:param bool passio_stderr: if :py:obj:`True`, \
|
||||
:py:class:`subprocess.Popen` has additionaly ``stderr`` connected
|
||||
:param bool ignore_stderr: if :py:obj:`True`, ``stderr`` is connected \
|
||||
to :file:`/dev/null`
|
||||
:param str localcmd: local command to communicate with remote command
|
||||
:param bool wait: if :py:obj:`True`, wait for command completion
|
||||
:param bool gui: when autostarting, also start gui daemon
|
||||
:param bool filter_esc: filter escape sequences to protect terminal emulator
|
||||
:param bool filter_esc: filter escape sequences to protect terminal \
|
||||
emulator
|
||||
'''
|
||||
|
||||
if user is None:
|
||||
@ -796,15 +828,18 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
try:
|
||||
if notify_function is not None:
|
||||
notify_function("info", "Starting the '{0}' VM...".format(self.name))
|
||||
notify_function('info',
|
||||
'Starting the {!r} VM...'.format(self.name))
|
||||
self.start(start_guid=gui, notify_function=notify_function)
|
||||
|
||||
except (IOError, OSError, QubesException) as err:
|
||||
raise QubesException("Error while starting the '{0}' VM: {1}".format(self.name, err))
|
||||
except (IOError, OSError, QubesException) as e:
|
||||
raise QubesException(
|
||||
'Error while starting the {!r} VM: {!s}'.format(
|
||||
self.name, e))
|
||||
except (MemoryError) as err:
|
||||
raise QubesException("Not enough memory to start '{0}' VM! "
|
||||
"Close one or more running VMs and try "
|
||||
"again.".format(self.name))
|
||||
raise QubesException('Not enough memory to start {!r} VM! '
|
||||
'Close one or more running VMs and try again.'.format(
|
||||
self.name))
|
||||
|
||||
if self.is_paused():
|
||||
raise QubesException("VM is paused")
|
||||
@ -812,22 +847,26 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
raise QubesException(
|
||||
"Domain '{}': qrexec not connected.".format(self.name))
|
||||
|
||||
if gui and os.getenv("DISPLAY") is not None and not self.is_guid_running():
|
||||
self.start_guid(verbose = verbose, notify_function = notify_function)
|
||||
if gui and os.getenv("DISPLAY") is not None \
|
||||
and not self.is_guid_running():
|
||||
self.start_guid(verbose=verbose, notify_function=notify_function)
|
||||
|
||||
args = [system_path["qrexec_client_path"], "-d", str(self.name), "%s:%s" % (user, command)]
|
||||
args = [system_path["qrexec_client_path"],
|
||||
"-d", str(self.name),
|
||||
'{}:{}'.format(user, command)]
|
||||
if localcmd is not None:
|
||||
args += [ "-l", localcmd]
|
||||
args += ['-l', localcmd]
|
||||
if filter_esc:
|
||||
args += ["-t"]
|
||||
args += ['-t']
|
||||
if os.isatty(sys.stderr.fileno()):
|
||||
args += ["-T"]
|
||||
args += ['-T']
|
||||
|
||||
# TODO: QSB#13
|
||||
if passio:
|
||||
if os.name == 'nt':
|
||||
# wait for qrexec-client to exit, otherwise client is not properly attached to console
|
||||
# if qvm-run is executed from cmd.exe
|
||||
# wait for qrexec-client to exit, otherwise client is not
|
||||
# properly attached to console if qvm-run is executed from
|
||||
# cmd.exe
|
||||
ret = subprocess.call(args)
|
||||
exit(ret)
|
||||
os.execv(system_path["qrexec_client_path"], args)
|
||||
@ -839,7 +878,7 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
call_kwargs['stderr'] = null
|
||||
|
||||
if passio_popen:
|
||||
popen_kwargs={'stdout': subprocess.PIPE}
|
||||
popen_kwargs = {'stdout': subprocess.PIPE}
|
||||
popen_kwargs['stdin'] = subprocess.PIPE
|
||||
if passio_stderr:
|
||||
popen_kwargs['stderr'] = subprocess.PIPE
|
||||
@ -910,13 +949,14 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
guid_cmd += ['-q']
|
||||
|
||||
retcode = subprocess.call(guid_cmd)
|
||||
if (retcode != 0) :
|
||||
raise QubesException("Cannot start qubes-guid!")
|
||||
if retcode != 0:
|
||||
raise QubesException('Cannot start qubes-guid!')
|
||||
|
||||
self.log.info('Sending monitor layout')
|
||||
|
||||
try:
|
||||
subprocess.call([system_path["monitor_layout_notify_cmd"], self.name])
|
||||
subprocess.call(
|
||||
[system_path['monitor_layout_notify_cmd'], self.name])
|
||||
except Exception as e:
|
||||
self.log.error('ERROR: {!s}'.format(e))
|
||||
|
||||
@ -937,8 +977,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
qrexec_env['QREXEC_STARTUP_TIMEOUT'] = str(self.qrexec_timeout)
|
||||
retcode = subprocess.call([system_path["qrexec_daemon_path"]] +
|
||||
qrexec_args, env=qrexec_env)
|
||||
if (retcode != 0) :
|
||||
raise OSError("Cannot execute qrexec-daemon!")
|
||||
if retcode != 0:
|
||||
raise OSError('Cannot execute qrexec-daemon!')
|
||||
|
||||
|
||||
def start_qubesdb(self):
|
||||
@ -998,7 +1038,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
os.path.join(self.dir_path,
|
||||
qubes.config.vm_files["kernels_subdir"], f))
|
||||
|
||||
self.log.info('Creating icon symlink: {0} -> {1}'.format(self.icon_path, self.label.icon_path))
|
||||
self.log.info('Creating icon symlink: {} -> {}'.format(
|
||||
self.icon_path, self.label.icon_path))
|
||||
if hasattr(os, "symlink"):
|
||||
os.symlink(self.label.icon_path, self.icon_path)
|
||||
else:
|
||||
@ -1021,8 +1062,12 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
# FIXME move this to qubes.storage.xen.XenVMStorage
|
||||
retcode = 0
|
||||
if self.is_running():
|
||||
retcode = self.run("while [ \"`blockdev --getsize64 /dev/xvdb`\" -lt {0} ]; do ".format(size) +
|
||||
"head /dev/xvdb > /dev/null; sleep 0.2; done; resize2fs /dev/xvdb", user="root", wait=True)
|
||||
retcode = self.run('''
|
||||
while [ "`blockdev --getsize64 /dev/xvdb`" -lt {0} ]; do
|
||||
head /dev/xvdb >/dev/null;
|
||||
sleep 0.2;
|
||||
done;
|
||||
resize2fs /dev/xvdb'''.format(size), user="root", wait=True)
|
||||
if retcode != 0:
|
||||
raise QubesException("resize2fs failed")
|
||||
|
||||
@ -1123,7 +1168,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
is undefined).
|
||||
=============== ========================================================
|
||||
|
||||
``Paused`` state is currently unavailable because of missing code in libvirt/xen glue.
|
||||
``Paused`` state is currently unavailable because of missing code in
|
||||
libvirt/xen glue.
|
||||
|
||||
FIXME: graph below may be incomplete and wrong. Click on method name to
|
||||
see its documentation.
|
||||
@ -1195,9 +1241,12 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
{ rank=sink; Paused Suspended };
|
||||
}
|
||||
|
||||
.. seealso:: http://wiki.libvirt.org/page/VM_lifecycle
|
||||
.. seealso::
|
||||
http://wiki.libvirt.org/page/VM_lifecycle
|
||||
Description of VM life cycle from the point of view of libvirt.
|
||||
|
||||
.. seealso:: https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState
|
||||
https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainState
|
||||
Libvirt API for changing state of a domain.
|
||||
|
||||
'''
|
||||
|
||||
@ -1230,7 +1279,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
def is_running(self):
|
||||
'''Check whether this domain is running.
|
||||
|
||||
:returns: :py:obj:`True` if this domain is started, :py:obj:`False` otherwise.
|
||||
:returns: :py:obj:`True` if this domain is started, \
|
||||
:py:obj:`False` otherwise.
|
||||
:rtype: bool
|
||||
'''
|
||||
|
||||
@ -1240,7 +1290,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
def is_paused(self):
|
||||
'''Check whether this domain is paused.
|
||||
|
||||
:returns: :py:obj:`True` if this domain is paused, :py:obj:`False` otherwise.
|
||||
:returns: :py:obj:`True` if this domain is paused, \
|
||||
:py:obj:`False` otherwise.
|
||||
:rtype: bool
|
||||
'''
|
||||
|
||||
@ -1251,7 +1302,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
def is_guid_running(self):
|
||||
'''Check whether gui daemon for this domain is available.
|
||||
|
||||
:returns: :py:obj:`True` if guid is running, :py:obj:`False` otherwise.
|
||||
:returns: :py:obj:`True` if guid is running, \
|
||||
:py:obj:`False` otherwise.
|
||||
:rtype: bool
|
||||
'''
|
||||
xid = self.xid
|
||||
@ -1265,7 +1317,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
def is_qrexec_running(self):
|
||||
'''Check whether qrexec for this domain is available.
|
||||
|
||||
:returns: :py:obj:`True` if qrexec is running, :py:obj:`False` otherwise.
|
||||
:returns: :py:obj:`True` if qrexec is running, \
|
||||
:py:obj:`False` otherwise.
|
||||
:rtype: bool
|
||||
'''
|
||||
if self.xid < 0:
|
||||
@ -1278,7 +1331,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
Currently this checks for running guid and qrexec.
|
||||
|
||||
:returns: :py:obj:`True` if qrexec is running, :py:obj:`False` otherwise.
|
||||
:returns: :py:obj:`True` if qrexec is running, \
|
||||
:py:obj:`False` otherwise.
|
||||
:rtype: bool
|
||||
'''
|
||||
|
||||
@ -1402,7 +1456,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
|
||||
def get_disk_utilization(self):
|
||||
'''Return total space actually occuppied by all files belonging to this domain.
|
||||
'''Return total space actually occuppied by all files belonging to \
|
||||
this domain.
|
||||
|
||||
:returns: domain's total disk usage [FIXME unit]
|
||||
:rtype: FIXME
|
||||
@ -1445,7 +1500,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
return None
|
||||
|
||||
# TODO shouldn't this be qubesdb?
|
||||
start_time = self.app.vmm.xs.read('', "/vm/%s/start_time" % str(self.uuid))
|
||||
start_time = self.app.vmm.xs.read('',
|
||||
'/vm/{}/start_time'.format(self.uuid))
|
||||
if start_time != '':
|
||||
return datetime.datetime.fromtimestamp(float(start_time))
|
||||
else:
|
||||
@ -1454,7 +1510,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
# XXX this probably should go to AppVM
|
||||
def is_outdated(self):
|
||||
'''Check whether domain needs restart to update root image from template.
|
||||
'''Check whether domain needs restart to update root image from \
|
||||
template.
|
||||
|
||||
:returns: :py:obj:`True` if is outdated, :py:obj:`False` otherwise.
|
||||
:rtype: bool
|
||||
@ -1485,7 +1542,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
# FIXME
|
||||
# 51712 (0xCA00) is xvda
|
||||
# backend node name not available through xenapi :(
|
||||
used_dmdev = vmm.xs.read('', "/local/domain/0/backend/vbd/{0}/51712/node".format(self.xid))
|
||||
used_dmdev = vmm.xs.read('',
|
||||
'/local/domain/0/backend/vbd/{}/51712/node'.format(self.xid))
|
||||
|
||||
return used_dmdev != current_dmdev
|
||||
|
||||
@ -1493,7 +1551,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
def is_networked(self):
|
||||
'''Check whether this VM can reach network (firewall notwithstanding).
|
||||
|
||||
:returns: :py:obj:`True` if is machine can reach network, :py:obj:`False` otherwise.
|
||||
:returns: :py:obj:`True` if is machine can reach network, \
|
||||
:py:obj:`False` otherwise.
|
||||
:rtype: bool
|
||||
'''
|
||||
|
||||
@ -1539,7 +1598,7 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
tzname = qubes.utils.get_timezone()
|
||||
if tzname:
|
||||
self.qdb.write("/qubes-timezone", tzname)
|
||||
self.qdb.write("/qubes-timezone", tzname)
|
||||
|
||||
for srv in self.services.keys():
|
||||
# convert True/False to "1"/"0"
|
||||
@ -1555,8 +1614,9 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
# TODO: Currently the whole qmemman is quite Xen-specific, so stay with
|
||||
# xenstore for it until decided otherwise
|
||||
if qmemman_present:
|
||||
vmm.xs.set_permissions('', '/local/domain/{0}/memory'.format(self.xid),
|
||||
[{ 'dom': self.xid }])
|
||||
vmm.xs.set_permissions('',
|
||||
'/local/domain/{}/memory'.format(self.xid),
|
||||
[{'dom': self.xid}])
|
||||
|
||||
self.fire_event('qdb-created')
|
||||
|
||||
@ -1570,7 +1630,8 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
self._libvirt_domain = vmm.libvirt_conn.defineXML(domain_config)
|
||||
self.uuid = uuid.UUID(bytes=self._libvirt_domain.UUID())
|
||||
except libvirt.libvirtError:
|
||||
if vmm.libvirt_conn.virConnGetLastError()[0] == libvirt.VIR_ERR_NO_DOMAIN:
|
||||
if vmm.libvirt_conn.virConnGetLastError()[0] == \
|
||||
libvirt.VIR_ERR_NO_DOMAIN:
|
||||
# accept the fact that libvirt doesn't know anything about this
|
||||
# domain...
|
||||
pass
|
||||
@ -1592,13 +1653,15 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
dev_basepath = '/local/domain/%d/device/vif' % self.xid
|
||||
for dev in self.app.vmm.xs.ls('', dev_basepath):
|
||||
# check if backend domain is alive
|
||||
backend_xid = int(self.app.vmm.xs.read('', '%s/%s/backend-id' % (dev_basepath, dev)))
|
||||
backend_xid = int(self.app.vmm.xs.read('',
|
||||
'{}/{}/backend-id'.format(dev_basepath, dev)))
|
||||
if backend_xid in self.app.vmm.libvirt_conn.listDomainsID():
|
||||
# check if device is still active
|
||||
if self.app.vmm.xs.read('', '%s/%s/state' % (dev_basepath, dev)) == '4':
|
||||
if self.app.vmm.xs.read('',
|
||||
'{}/{}/state'.format(dev_basepath, dev)) == '4':
|
||||
continue
|
||||
# remove dead device
|
||||
self.app.vmm.xs.rm('', '%s/%s' % (dev_basepath, dev))
|
||||
self.app.vmm.xs.rm('', '{}/{}'.format(dev_basepath, dev))
|
||||
|
||||
|
||||
|
||||
@ -1635,17 +1698,13 @@ class QubesVM(qubes.vm.BaseVM):
|
||||
|
||||
|
||||
# attrs = {
|
||||
#
|
||||
##### Internal attributes - will be overriden in __init__ regardless of args
|
||||
|
||||
# those should be __builtin__.property of something
|
||||
# used to suppress side effects of clone_attrs
|
||||
# XXX probably will be obsoleted by .events_enabled
|
||||
# "_do_not_reset_firewall": { "func": lambda x: False },
|
||||
|
||||
# XXX WTF?
|
||||
# "kernels_dir": {
|
||||
# # for backward compatibility (or another rare case): kernel=None -> kernel in VM dir
|
||||
# # for backward compatibility (or another rare case): kernel=None ->
|
||||
# # kernel in VM dir
|
||||
# "func": lambda x: \
|
||||
# os.path.join(system_path["qubes_kernels_base_dir"],
|
||||
# self.kernel) if self.kernel is not None \
|
||||
|
Loading…
Reference in New Issue
Block a user