diff --git a/qubesmgmt/exc.py b/qubesmgmt/exc.py index 9c0c7ae..0441ade 100644 --- a/qubesmgmt/exc.py +++ b/qubesmgmt/exc.py @@ -103,6 +103,10 @@ class QubesMemoryError(QubesException, MemoryError): '''Cannot start domain, because not enough memory is available''' +class QubesFeatureNotFoundError(QubesException, KeyError): + '''Feature not set for a given domain''' + + class StoragePoolException(QubesException): ''' A general storage exception ''' diff --git a/qubesmgmt/features.py b/qubesmgmt/features.py new file mode 100644 index 0000000..e421251 --- /dev/null +++ b/qubesmgmt/features.py @@ -0,0 +1,69 @@ +# -*- encoding: utf8 -*- +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2017 Marek Marczykowski-Górecki +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License along +# with this program; if not, see . + +'''VM features interface''' + + +class Features(object): + '''Manager of the features. + + Features can have three distinct values: no value (not present in mapping, + which is closest thing to :py:obj:`None`), empty string (which is + interpreted as :py:obj:`False`) and non-empty string, which is + :py:obj:`True`. Anything assigned to the mapping is coerced to strings, + however if you assign instances of :py:class:`bool`, they are converted as + described above. Be aware that assigning the number `0` (which is considered + false in Python) will result in string `'0'`, which is considered true. + ''' + # pylint: disable=too-few-public-methods + + def __init__(self, vm): + super(Features, self).__init__() + self.vm = vm + + def __delitem__(self, key): + self.vm.qubesd_call(self.vm.name, 'mgmt.vm.feature.Remove', key) + + def __setitem__(self, key, value): + self.vm.qubesd_call(self.vm.name, 'mgmt.vm.feature.Set', key, value) + + def __getitem__(self, item): + return self.vm.qubesd_call( + self.vm.name, 'mgmt.vm.feature.Get', item).decode('utf-8') + + def __iter__(self): + qubesd_response = self.vm.qubesd_call(self.vm.name, + 'mgmt.vm.feature.List') + return iter(qubesd_response.decode('utf-8').splitlines()) + + keys = __iter__ + + _NO_DEFAULT = object() + + def check_with_template(self, feature, default=_NO_DEFAULT): + ''' Check if the vm's template has the specified feature. ''' + try: + qubesd_response = self.vm.qubesd_call( + self.vm.name, 'mgmt.vm.feature.CheckWithTemplate', feature) + return qubesd_response.decode('utf-8') + except KeyError: + if default is self._NO_DEFAULT: + raise + return default diff --git a/qubesmgmt/vm/__init__.py b/qubesmgmt/vm/__init__.py index c97718c..522fb8a 100644 --- a/qubesmgmt/vm/__init__.py +++ b/qubesmgmt/vm/__init__.py @@ -23,6 +23,7 @@ import logging import qubesmgmt.base import qubesmgmt.storage +import qubesmgmt.features class QubesVM(qubesmgmt.base.PropertyHolder): @@ -30,10 +31,13 @@ class QubesVM(qubesmgmt.base.PropertyHolder): log = None + features = None + def __init__(self, app, name): super(QubesVM, self).__init__(app, 'mgmt.vm.property.', name) self._volumes = None self.log = logging.getLogger(name) + self.features = qubesmgmt.features.Features(self) @property def name(self):