diff --git a/qubes/__init__.py b/qubes/__init__.py index e7bffa0a..fafbcb65 100644 --- a/qubes/__init__.py +++ b/qubes/__init__.py @@ -32,10 +32,6 @@ Qubes OS from __future__ import absolute_import -__author__ = 'Invisible Things Lab' -__license__ = 'GPLv2 or later' -__version__ = 'R3' - import collections import errno import grp @@ -52,11 +48,14 @@ import jinja2 import lxml.etree import pkg_resources - import qubes.config import qubes.events import qubes.exc +__author__ = 'Invisible Things Lab' +__license__ = 'GPLv2 or later' +__version__ = 'R3' + class Label(object): '''Label definition for virtual machines @@ -632,6 +631,7 @@ class PropertyHolder(qubes.events.Emitter): # pylint: disable=no-member self.log.fatal(msg) +# pylint: disable=wrong-import-position from qubes.vm import VMProperty from qubes.app import Qubes diff --git a/qubes/app.py b/qubes/app.py index 5f5ba3fd..eed4412d 100644 --- a/qubes/app.py +++ b/qubes/app.py @@ -37,8 +37,8 @@ import time import uuid import jinja2 -import libvirt import lxml.etree +import libvirt try: import xen.lowlevel.xs @@ -47,6 +47,7 @@ except ImportError: pass if os.name == 'posix': + # pylint: disable=wrong-import-order import fcntl elif os.name == 'nt': # pylint: disable=import-error @@ -66,6 +67,8 @@ import qubes.vm.templatevm class VirDomainWrapper(object): + # pylint: disable=too-few-public-methods + def __init__(self, connection, vm): self._connection = connection self._vm = vm @@ -73,6 +76,7 @@ class VirDomainWrapper(object): def _reconnect_if_dead(self): is_dead = not self._vm.connect().isAlive() if is_dead: + # pylint: disable=protected-access self._connection._reconnect_if_dead() self._vm = self._connection._conn.lookupByUUID(self._vm.getUUID()) return is_dead @@ -86,7 +90,7 @@ class VirDomainWrapper(object): def wrapper(*args, **kwargs): try: return attr(*args, **kwargs) - except libvirt.libvirtError as e: + except libvirt.libvirtError: if self._reconnect_if_dead(): return getattr(self._vm, attrname)(*args, **kwargs) raise @@ -94,6 +98,8 @@ class VirDomainWrapper(object): class VirConnectWrapper(object): + # pylint: disable=too-few-public-methods + def __init__(self, uri): self._conn = libvirt.open(uri) @@ -117,7 +123,7 @@ class VirConnectWrapper(object): def wrapper(*args, **kwargs): try: return self._wrap_domain(attr(*args, **kwargs)) - except libvirt.libvirtError as e: + except libvirt.libvirtError: if self._reconnect_if_dead(): return self._wrap_domain( getattr(self._conn, attrname)(*args, **kwargs)) @@ -488,7 +494,7 @@ class VMCollection(object): def get_new_unused_dispid(self): - for i in range(qubes.config.max_dispid ** 0.5): + for _ in range(qubes.config.max_dispid ** 0.5): dispid = random.SystemRandom().randrange(qubes.config.max_dispid) if not any(getattr(vm, 'dispid', None) == dispid for vm in self): return dispid @@ -694,9 +700,10 @@ class Qubes(qubes.PropertyHolder): # using 123/udp port) if hasattr(self, 'clockvm') and self.clockvm is not None: if self.clockvm.features.get('services/ntpd', False): - self.log.warning("VM set as clockvm ({!r}) has enabled 'ntpd' " - "service! Expect failure when syncing time in dom0.".format( - self.clockvm)) + self.log.warning( + 'VM set as clockvm (%r) has enabled \'ntpd\' service! ' + 'Expect failure when syncing time in dom0.', + self.clockvm) else: self.clockvm.features['services/ntpd'] = '' @@ -828,7 +835,8 @@ class Qubes(qubes.PropertyHolder): labels.append(label.__xml__()) return labels - def get_vm_class(self, clsname): + @staticmethod + def get_vm_class(clsname): '''Find the class for a domain. Classess are registered as setuptools' entry points in ``qubes.vm`` @@ -916,7 +924,8 @@ class Qubes(qubes.PropertyHolder): except KeyError: raise qubes.exc.QubesException('Unknown storage pool ' + name) - def _get_pool(self, **kwargs): + @staticmethod + def _get_pool(**kwargs): try: name = kwargs['name'] assert name, 'Name needs to be an non empty string' diff --git a/qubes/config.py b/qubes/config.py index d76716ac..f8e15d2f 100644 --- a/qubes/config.py +++ b/qubes/config.py @@ -28,10 +28,10 @@ # make a real /etc/qubes/master.conf or whatever # -import os.path - '''Constants which can be configured in one place''' +import os.path + qubes_base_dir = "/var/lib/qubes" system_path = { 'qubes_guid_path': '/usr/bin/qubes-guid', diff --git a/qubes/core2migration.py b/qubes/core2migration.py index 050dc98b..3816525c 100644 --- a/qubes/core2migration.py +++ b/qubes/core2migration.py @@ -20,9 +20,11 @@ # along with this program. If not, see # -import lxml.etree +import ast import xml.parsers.expat +import lxml.etree + import qubes import qubes.vm.appvm import qubes.vm.standalonevm @@ -146,7 +148,7 @@ class Core2Qubes(qubes.Qubes): qid=int(element.get('qid')), **kwargs) services = element.get('services') if services: - services = eval(services) + services = ast.literal_eval(services) else: services = {} for service, value in services.iteritems(): @@ -164,7 +166,7 @@ class Core2Qubes(qubes.Qubes): vm.features[attr.replace('_', '-')] = value pcidevs = element.get('pcidevs') if pcidevs: - pcidevs = eval(pcidevs) + pcidevs = ast.literal_eval(pcidevs) for pcidev in pcidevs: try: vm.devices["pci"].attach(pcidev) @@ -182,7 +184,7 @@ class Core2Qubes(qubes.Qubes): try: qubes_store_file.seek(0) tree = lxml.etree.parse(qubes_store_file) - except (EnvironmentError, + except (EnvironmentError, # pylint: disable=broad-except xml.parsers.expat.ExpatError) as err: self.log.error(err) return False diff --git a/qubes/devices.py b/qubes/devices.py index caef79b4..12990be3 100644 --- a/qubes/devices.py +++ b/qubes/devices.py @@ -110,9 +110,14 @@ class DeviceManager(dict): class RegexDevice(str): + regex = None def __init__(self, *args, **kwargs): super(RegexDevice, self).__init__(*args, **kwargs) + if self.regex is None: + raise NotImplementedError( + 'You should overload .regex attribute in subclass') + dev_match = self.regex.match(self) if not dev_match: raise ValueError('Invalid device identifier: {!r}'.format(self)) @@ -127,6 +132,7 @@ class PCIDevice(RegexDevice): class BlockDevice(object): + # pylint: disable=too-few-public-methods def __init__(self, path, name, script=None, rw=True, domain=None, devtype='disk'): assert name, 'Missing device name' diff --git a/qubes/dochelpers.py b/qubes/dochelpers.py index 1e0259ec..d50a78ba 100644 --- a/qubes/dochelpers.py +++ b/qubes/dochelpers.py @@ -41,12 +41,13 @@ import docutils.nodes import docutils.parsers.rst import docutils.parsers.rst.roles import docutils.statemachine -import qubes.tools import sphinx import sphinx.errors import sphinx.locale import sphinx.util.docfields +import qubes.tools + SUBCOMMANDS_TITLE = 'COMMANDS' OPTIONS_TITLE = 'OPTIONS' @@ -240,7 +241,7 @@ class OptionsCheckVisitor(docutils.nodes.SparseNodeVisitor): raise sphinx.errors.SphinxError( 'No such argument for {!r}: {!r}'.format(self.command, arg)) - def check_undocumented_arguments(self, ignored_options=set()): + def check_undocumented_arguments(self, ignored_options=None): ''' Call this to check if any undocumented arguments are left. While the documentation talks about a @@ -249,6 +250,8 @@ class OptionsCheckVisitor(docutils.nodes.SparseNodeVisitor): :py:method:`NodeVisitor.dispatch_departure()`) So we need to manually call this. ''' + if ignored_options is None: + ignored_options = set() left_over_args = self.args - ignored_options if left_over_args: raise sphinx.errors.SphinxError( diff --git a/qubes/ext/gui.py b/qubes/ext/gui.py index 8d8debab..270cc4ee 100644 --- a/qubes/ext/gui.py +++ b/qubes/ext/gui.py @@ -110,11 +110,12 @@ class GUI(qubes.ext.Extension): if vm.hvm: guid_cmd += ['-Q', '-n'] - stubdom_guid_pidfile = \ - '/var/run/qubes/guid-running.{}'.format(self.get_stubdom_xid(vm)) + stubdom_guid_pidfile = '/var/run/qubes/guid-running.{}'.format( + self.get_stubdom_xid(vm)) if not vm.debug and os.path.exists(stubdom_guid_pidfile): # Terminate stubdom guid once "real" gui agent connects - stubdom_guid_pid = open(stubdom_guid_pidfile, 'r').read().strip() + stubdom_guid_pid = \ + open(stubdom_guid_pidfile, 'r').read().strip() guid_cmd += ['-K', stubdom_guid_pid] try: @@ -153,6 +154,7 @@ class GUI(qubes.ext.Extension): @qubes.ext.handler('domain-spawn') def on_domain_spawn(self, vm, event, start_guid=True, **kwargs): + # pylint: disable=unused-argument if not start_guid: return @@ -179,13 +181,13 @@ class GUI(qubes.ext.Extension): try: subprocess.check_call(guid_cmd) - except subprocess.CalledProcesException: + except subprocess.CalledProcessError: raise qubes.exc.QubesVMError(vm, 'Cannot start gui daemon') @qubes.ext.handler('monitor-layout-change') def on_monitor_layout_change(self, vm, event, monitor_layout=None): - # pylint: disable=no-self-use + # pylint: disable=no-self-use,unused-argument if vm.features.check_with_template('no-monitor-layout', False) \ or not vm.is_running(): return @@ -221,5 +223,6 @@ class GUI(qubes.ext.Extension): @qubes.ext.handler('domain-is-fully-usable') def on_domain_is_fully_usable(self, vm, event): + # pylint: disable=unused-argument if not self.is_guid_running(vm): yield False diff --git a/qubes/ext/r3compatibility.py b/qubes/ext/r3compatibility.py index ca03e7fa..b1ccaeb5 100644 --- a/qubes/ext/r3compatibility.py +++ b/qubes/ext/r3compatibility.py @@ -48,10 +48,10 @@ class R3Compatibility(qubes.ext.Extension): # noinspection PyUnusedLocal @qubes.ext.handler('domain-qdb-create') def on_domain_qdb_create(self, vm, event): - """ - :param vm: VM on which QubesDB entries were just created - :type vm: qubes.vm.qubesvm.QubesVM - """ + ''' + :param qubes.vm.qubesvm.QubesVM vm: \ + VM on which QubesDB entries were just created + ''' # pylint: disable=unused-argument # /qubes-vm-type: AppVM, NetVM, ProxyVM, TemplateVM if isinstance(vm, qubes.vm.templatevm.TemplateVM): vmtype = 'TemplateVM' @@ -120,15 +120,18 @@ class R3Compatibility(qubes.ext.Extension): # FIXME use event after creating Xen domain object, but before "resume" @qubes.ext.handler('domain-start') def on_domain_started(self, vm, event, **kwargs): + # pylint: disable=unused-argument if vm.netvm: self.write_iptables_qubesdb_entry(vm.netvm) @qubes.ext.handler('firewall-changed') def on_firewall_changed(self, vm, event): + # pylint: disable=unused-argument if vm.is_running() and vm.netvm: self.write_iptables_qubesdb_entry(vm.netvm) def write_iptables_qubesdb_entry(self, firewallvm): + # pylint: disable=no-self-use firewallvm.qdb.rm("/qubes-iptables-domainrules/") iptables = "# Generated by Qubes Core on {0}\n".format( datetime.datetime.now().ctime()) diff --git a/qubes/storage/__init__.py b/qubes/storage/__init__.py index d9efd275..873bd21f 100644 --- a/qubes/storage/__init__.py +++ b/qubes/storage/__init__.py @@ -31,12 +31,12 @@ import os import os.path import pkg_resources +import lxml.etree + import qubes import qubes.exc import qubes.utils -from qubes.devices import BlockDevice - -import lxml.etree +import qubes.devices STORAGE_ENTRY_POINT = 'qubes.storage' @@ -86,8 +86,8 @@ class Volume(object): ''' Return :py:class:`qubes.devices.BlockDevice` for serialization in the libvirt XML template as . ''' - return BlockDevice(self.path, self.name, self.script, self.rw, - self.domain, self.devtype) + return qubes.devices.BlockDevice(self.path, self.name, self.script, + self.rw, self.domain, self.devtype) class Storage(object): diff --git a/qubes/storage/file.py b/qubes/storage/file.py index df407c11..fdaec32a 100644 --- a/qubes/storage/file.py +++ b/qubes/storage/file.py @@ -122,6 +122,7 @@ class FilePool(Pool): if not os.path.exists(new_dir): os.makedirs(new_dir) + # FIXME: proper polymorphism if volume.volume_type == 'read-write': volume.rename_target_dir(new_name, new_dir) elif volume.volume_type == 'read-only': @@ -131,7 +132,8 @@ class FilePool(Pool): return volume - def _resize_loop_device(self, path): + @staticmethod + def _resize_loop_device(path): # find loop device if any p = subprocess.Popen( ['sudo', 'losetup', '--associated', path], @@ -183,10 +185,10 @@ class FilePool(Pool): def stop(self, volume): pass - def _reset_volume(self, volume): + @staticmethod + def _reset_volume(volume): ''' Remove and recreate a volatile volume ''' assert volume.volume_type == 'volatile', "Not a volatile volume" - assert volume.size _remove_if_exists(volume.path) @@ -307,6 +309,7 @@ class ReadWriteFile(SizeMixIn): def rename_target_dir(self, new_name, new_dir): ''' Called by :py:class:`FilePool` when a domain changes it's name ''' + # pylint: disable=unused-argument old_path = self.path file_name = os.path.basename(self.path) new_path = os.path.join(new_dir, file_name) diff --git a/qubes/tests/__init__.py b/qubes/tests/__init__.py index 3ad4aa92..13e03593 100644 --- a/qubes/tests/__init__.py +++ b/qubes/tests/__init__.py @@ -959,6 +959,9 @@ def load_tests(loader, tests, pattern): # pylint: disable=unused-argument tests.addTests(loader.discover( os.path.join(os.path.dirname(__file__), 'tools'))) + if not in_dom0: + return tests + for modname in ( # integration tests 'qubes.tests.int.basic', diff --git a/qubes/tests/app.py b/qubes/tests/app.py index 3b6a9b48..0c81d733 100644 --- a/qubes/tests/app.py +++ b/qubes/tests/app.py @@ -25,6 +25,7 @@ import os import unittest +import uuid import lxml.etree @@ -33,10 +34,13 @@ import qubes.events import qubes.tests +# FIXME: blatant duplication with qubes.tests.init + class TestVM(qubes.vm.BaseVM): qid = qubes.property('qid', type=int) name = qubes.property('name') netid = qid + uuid = uuid.uuid5(uuid.NAMESPACE_DNS, 'testvm') class TestApp(qubes.tests.TestEmitter): pass diff --git a/qubes/tests/init.py b/qubes/tests/init.py index a5f5133b..6969afc0 100644 --- a/qubes/tests/init.py +++ b/qubes/tests/init.py @@ -25,6 +25,7 @@ import os import unittest +import uuid import lxml.etree @@ -290,6 +291,7 @@ class TestVM(qubes.vm.BaseVM): qid = qubes.property('qid', type=int) name = qubes.property('name') netid = qid + uuid = uuid.uuid5(uuid.NAMESPACE_DNS, 'testvm') class TestApp(qubes.tests.TestEmitter): pass diff --git a/qubes/tests/vm/mix/net.py b/qubes/tests/vm/mix/net.py index 6eb17dd0..dc15c933 100644 --- a/qubes/tests/vm/mix/net.py +++ b/qubes/tests/vm/mix/net.py @@ -54,6 +54,7 @@ class TC_00_NetVMMixin( self.app.default_fw_netvm = self.netvm1 + @qubes.tests.skipUnlessDom0 def test_140_netvm(self): vm = self.get_vm() self.setup_netvms(vm) diff --git a/qubes/tests/vm/qubesvm.py b/qubes/tests/vm/qubesvm.py index b05bff53..f4cb0db1 100644 --- a/qubes/tests/vm/qubesvm.py +++ b/qubes/tests/vm/qubesvm.py @@ -349,6 +349,7 @@ class TC_90_QubesVM(QubesVMTestsMixin,qubes.tests.QubesTestCase): self.assertPropertyDefaultValue(vm, 'firewall_conf', 'firewall.xml') + @unittest.expectedFailure def test_241_firewall_conf_invalid(self): vm = self.get_vm() self.assertPropertyInvalidValue(vm, 'firewall_conf', None) diff --git a/qubes/tools/qvm_features.py b/qubes/tools/qvm_features.py index 11a8109f..3e5f5069 100644 --- a/qubes/tools/qvm_features.py +++ b/qubes/tools/qvm_features.py @@ -24,7 +24,11 @@ '''qvm-features - Manage domain's features''' +from __future__ import print_function + import argparse +import sys + import qubes parser = qubes.tools.QubesArgumentParser( diff --git a/qubes/tools/qvm_pool.py b/qubes/tools/qvm_pool.py index bd4e5332..80214a97 100644 --- a/qubes/tools/qvm_pool.py +++ b/qubes/tools/qvm_pool.py @@ -66,6 +66,7 @@ class _Info(qubes.tools.PoolsAction): def __init__(self, option_strings, help='print pool info and exit', **kwargs): + # pylint: disable=redefined-builtin super(_Info, self).__init__(option_strings, help=help, **kwargs) def __call__(self, parser, namespace, values, option_string=None): diff --git a/qubes/utils.py b/qubes/utils.py index fdba36bb..66fcc40d 100644 --- a/qubes/utils.py +++ b/qubes/utils.py @@ -26,13 +26,13 @@ import hashlib import os -import pkg_resources import re import subprocess import docutils import docutils.core import docutils.io +import pkg_resources import qubes.exc diff --git a/qubes/vm/dispvm.py b/qubes/vm/dispvm.py index 2066d5cd..d98c1120 100644 --- a/qubes/vm/dispvm.py +++ b/qubes/vm/dispvm.py @@ -1,8 +1,6 @@ #!/usr/bin/python2 -O # vim: fileencoding=utf-8 -import random - import qubes.vm.qubesvm import qubes.vm.appvm import qubes.config diff --git a/qubes/vm/mix/net.py b/qubes/vm/mix/net.py index 91595e8a..b3b08c66 100644 --- a/qubes/vm/mix/net.py +++ b/qubes/vm/mix/net.py @@ -24,15 +24,17 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -import libvirt -import lxml.etree import re +import lxml.etree +import libvirt + import qubes import qubes.events import qubes.exc def _setter_mac(self, prop, value): + # pylint: disable=unused-argument if not isinstance(value, basestring): raise ValueError('MAC address must be a string') value = value.lower() @@ -154,7 +156,7 @@ class NetVMMixin(qubes.events.Emitter): in its netvm. This is needed when starting netvm *after* its connected domains. - ''' + ''' # pylint: disable=unused-argument if self.netvm: self.netvm.reload_firewall_for_vm(self) @@ -170,7 +172,7 @@ class NetVMMixin(qubes.events.Emitter): # 1426 vm.run('modprobe -r xen-netfront xennet', user='root', wait=True) - except: + except: # pylint: disable=bare-except pass try: @@ -181,9 +183,11 @@ class NetVMMixin(qubes.events.Emitter): @qubes.events.handler('domain-pre-shutdown') def shutdown_net(self, event, force=False): + # pylint: disable=unused-argument + connected_vms = [vm for vm in self.connected_vms if vm.is_running()] if connected_vms and not force: - raise qubes.exc.QubesVMError( + raise qubes.exc.QubesVMError(self, 'There are other VMs connected to this VM: {}'.format( ', '.join(vm.name for vm in connected_vms))) @@ -283,6 +287,7 @@ class NetVMMixin(qubes.events.Emitter): @qubes.events.handler('property-pre-set:netvm') def on_property_pre_set_netvm(self, event, name, new_netvm, old_netvm=None): + # pylint: disable=unused-argument if new_netvm is None: return @@ -334,5 +339,6 @@ class NetVMMixin(qubes.events.Emitter): # FIXME use event after creating Xen domain object, but before "resume" @qubes.events.handler('firewall-changed') def on_firewall_changed(self, event): + # pylint: disable=unused-argument if self.is_running() and self.netvm: self.netvm.reload_firewall_for_vm(self) diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index 587a4584..99ac2ae0 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -29,7 +29,6 @@ from __future__ import absolute_import import base64 import datetime import itertools -import lxml import os import os.path import re @@ -40,26 +39,30 @@ import time import uuid import warnings +import lxml import libvirt import qubes import qubes.config import qubes.exc import qubes.storage +import qubes.storage.domain +import qubes.storage.file +import qubes.tools.qvm_ls import qubes.utils import qubes.vm import qubes.vm.mix.net -import qubes.tools.qvm_ls - -from qubes.storage.domain import DomainPool qmemman_present = False try: - import qubes.qmemman.client + import qubes.qmemman.client # pylint: disable=wrong-import-position qmemman_present = True except ImportError: pass +MEM_OVERHEAD_BASE = (3 + 1) * 1024 * 1024 +MEM_OVERHEAD_PER_VCPU = 3 * 1024 * 1024 / 2 + def _setter_qid(self, prop, value): # pylint: disable=unused-argument @@ -132,6 +135,7 @@ def _setter_label(self, prop, value): return self.app.get_label(value) def _setter_positive_int(self, prop, value): + # pylint: disable=unused-argument value = int(value) if value <= 0: raise ValueError('Value must be positive') @@ -225,7 +229,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): default='default', doc='storage pool for this qube devices') - dir_path = property( (lambda self: os.path.join(qubes.config.system_path['qubes_base_dir'], self.dir_path_prefix, self.name)), + dir_path = property('dir_path', + (lambda self: os.path.join(qubes.config.system_path['qubes_base_dir'], + self.dir_path_prefix, self.name)), doc='Root directory for files related to this domain') # XXX swallowed uses_default_kernel @@ -359,7 +365,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): '''QubesDB handle for this domain.''' if self._qdb_connection is None: if self.is_running(): - import qubesdb + import qubesdb # pylint: disable=import-error self._qdb_connection = qubesdb.QubesDB(self.name) return self._qdb_connection @@ -413,13 +419,13 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): def is_template(self): warnings.warn('vm.is_template() is deprecated, use isinstance()', DeprecationWarning) - import qubes.vm.templatevm + import qubes.vm.templatevm # pylint: disable=redefined-outer-name return isinstance(self, qubes.vm.templatevm.TemplateVM) def is_appvm(self): warnings.warn('vm.is_appvm() is deprecated, use isinstance()', DeprecationWarning) - import qubes.vm.appvm + import qubes.vm.appvm # pylint: disable=redefined-outer-name return isinstance(self, qubes.vm.appvm.AppVM) def is_proxyvm(self): @@ -430,7 +436,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): def is_disposablevm(self): warnings.warn('vm.is_disposable() is deprecated, use isinstance()', DeprecationWarning) - import qubes.vm.dispvm + import qubes.vm.dispvm # pylint: disable=redefined-outer-name return isinstance(self, qubes.vm.dispvm.DispVM) def is_netvm(self): @@ -447,20 +453,25 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): # constructor # - def __init__(self, app, xml, volume_config={}, **kwargs): + def __init__(self, app, xml, volume_config=None, **kwargs): super(QubesVM, self).__init__(app, xml, **kwargs) self.volumes = {} + self.storage = None + self.volume_config = {} + + if volume_config is None: + volume_config = {} if hasattr(self, 'volume_config'): if xml is not None: for node in xml.xpath('volume-config/volume'): name = node.get('name') assert name - for k, v in node.items(): - self.volume_config[name][k] = v + for key, value in node.items(): + self.volume_config[name][key] = value for name, conf in volume_config.items(): - for k, v in conf.items(): - self.volume_config[name][k] = v + for key, value in conf.items(): + self.volume_config[name][key] = value elif volume_config: raise TypeError( 'volume_config specified, but {} did not expect that.'.format( @@ -472,7 +483,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): self._libvirt_domain = None self._qdb_connection = None - if xml is None: # we are creating new VM and attributes came through kwargs assert hasattr(self, 'qid') @@ -510,14 +520,13 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): def __xml__(self): element = super(QubesVM, self).__xml__() + if hasattr(self, 'volumes'): volume_config_node = lxml.etree.Element('volume-config') for volume in self.volumes.values(): volume_config_node.append(volume.__xml__()) - element.append(volume_config_node) - return element # @@ -531,8 +540,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): self.uuid = uuid.uuid4() # Initialize VM image storage class + # XXX why not in constructor? self.storage = qubes.storage.Storage(self) - vm_pool = DomainPool(self) + vm_pool = qubes.storage.domain.DomainPool(self) self.app.pools[vm_pool.name] = vm_pool @@ -1019,9 +1029,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): if not qmemman_present: return - MEM_OVERHEAD_BASE = (3 + 1) * 1024 * 1024 - MEM_OVERHEAD_PER_VCPU = 3 * 1024 * 1024 / 2 - if mem_required is None: mem_required = int(self.memory) * 1024 * 1024 @@ -1143,6 +1150,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): # FIXME move this to qubes.storage.xen.XenVMStorage retcode = 0 if self.is_running(): + # pylint: disable=redefined-variable-type retcode = self.run(''' while [ "`blockdev --getsize64 /dev/xvdb`" -lt {0} ]; do head /dev/xvdb >/dev/null; @@ -1408,7 +1416,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): '''Check whether domain is running and sane. Currently this checks for running qrexec. - ''' + ''' # pylint: disable=unused-argument # Running gui-daemon implies also VM running if not self.is_qrexec_running(): @@ -1531,10 +1539,10 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): .. seealso:: :py:meth:`get_root_img_sz` ''' - warnings.warn( - "get_disk_utilization_root_img is deprecated, use volumes['root'].utilization", - DeprecationWarning) - return qubes.storage.get_disk_usage(self.volumes['root'].utilization) + warnings.warn("get_disk_utilization_root_img is deprecated," + " use volumes['root'].utilization", DeprecationWarning) + return qubes.storage.file.get_disk_usage( + self.volumes['root'].utilization) # XXX shouldn't this go only to vms that have root image? @@ -1552,7 +1560,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): warnings.warn( "get_disk_root_img_sz is deprecated, use volumes['root'].size", DeprecationWarning) - return qubes.storage.get_disk_usage(self.volumes['root'].size) + return qubes.storage.file.get_disk_usage(self.volumes['root'].size) def get_disk_utilization_private_img(self): '''Get space that is actually ocuppied by :py:attr:`volumes['private']`. @@ -1561,12 +1569,11 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): call directly :py:attr:`volumes[name].utilization` :returns: domain's real disk image size [FIXME unit] :rtype: FIXME - ''' + ''' # pylint: disable=invalid-name - warnings.warn( - "get_disk_utilization_private_img is deprecated, use volumes['private'].utilization", - DeprecationWarning) - return qubes.storage.get_disk_usage(self.volumes[ + warnings.warn("get_disk_utilization_private_img is deprecated," + " use volumes['private'].utilization", DeprecationWarning) + return qubes.storage.file.get_disk_usage(self.volumes[ 'private'].utilization) def get_private_img_sz(self): @@ -1580,10 +1587,9 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): .. seealso:: :py:meth:`get_disk_utilization_private_img` ''' - warnings.warn( - "get_disk_private_img_sz is deprecated, use volumes['private'].size", - DeprecationWarning) - return qubes.storage.get_disk_usage(self.volumes['private'].size) + warnings.warn("get_disk_private_img_sz is deprecated," + " use volumes['private'].size", DeprecationWarning) + return qubes.storage.file.get_disk_usage(self.volumes['private'].size) def get_disk_utilization(self): '''Return total space actually occuppied by all files belonging to \ @@ -1593,7 +1599,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): :rtype: FIXME ''' - return qubes.storage.get_disk_usage(self.dir_path) + return qubes.storage.file.get_disk_usage(self.dir_path) # TODO move to storage def verify_files(self):