diff --git a/qubes/__init__.py b/qubes/__init__.py index 1a5859df..44b7156b 100644 --- a/qubes/__init__.py +++ b/qubes/__init__.py @@ -132,7 +132,7 @@ class Label(object): self.icon_dispvm) + ".png" -class property(object): # pylint: disable=redefined-builtin,invalid-name +class property(object): # pylint: disable=redefined-builtin,invalid-name '''Qubes property. This class holds one property that can be saved to and loaded from @@ -157,8 +157,6 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name :param int order: order of evaluation (bigger order values are later) :param bool clone: :py:meth:`PropertyHolder.clone_properties` will not \ include this property by default if :py:obj:`False` - :param str ls_head: column head for :program:`qvm-ls` - :param int ls_width: column width in :program:`qvm-ls` :param str doc: docstring; this should be one paragraph of plain RST, no \ sphinx-specific features @@ -192,7 +190,7 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name def __init__(self, name, setter=None, saver=None, type=None, default=_NO_DEFAULT, write_once=False, load_stage=2, order=0, save_via_ref=False, clone=True, - ls_head=None, ls_width=None, doc=None): + doc=None): # pylint: disable=redefined-builtin self.__name__ = name self._setter = setter @@ -208,11 +206,6 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name self.__doc__ = doc self._attr_name = '_qubesprop_' + name - if ls_head is not None or ls_width is not None: - self.ls_head = ls_head or self.__name__.replace('_', '-').upper() - self.ls_width = max(ls_width or 0, len(self.ls_head) + 1) - - def __get__(self, instance, owner): if instance is None: return self diff --git a/qubes/tests/__init__.py b/qubes/tests/__init__.py index e35a2f88..cc6682ad 100644 --- a/qubes/tests/__init__.py +++ b/qubes/tests/__init__.py @@ -908,7 +908,6 @@ def load_tests(loader, tests, pattern): # pylint: disable=unused-argument 'qubes.tests.mgmt', 'qubes.tests.tools.qvm_device', 'qubes.tests.tools.qvm_firewall', - 'qubes.tests.tools.qvm_ls', 'qubespolicy.tests', ): tests.addTests(loader.loadTestsFromName(modname)) diff --git a/qubes/tests/tools/qvm_ls.py b/qubes/tests/tools/qvm_ls.py deleted file mode 100644 index 969e0681..00000000 --- a/qubes/tests/tools/qvm_ls.py +++ /dev/null @@ -1,76 +0,0 @@ -# pylint: disable=protected-access,pointless-statement - -# -# The Qubes OS Project, https://www.qubes-os.org/ -# -# Copyright (C) 2015 Joanna Rutkowska -# Copyright (C) 2015 Wojtek Porczyk -# -# 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. -# - -import qubes -import qubes.vm.adminvm -import qubes.tools.qvm_ls - -import qubes.tests -import qubes.tests.vm - -class TC_00_Column(qubes.tests.QubesTestCase): - def test_000_collected(self): - self.assertIn('NAME', qubes.tools.qvm_ls.Column.columns) - - def test_100_init(self): - try: - testcolumn = qubes.tools.qvm_ls.Column('TESTCOLUMN', width=50) - self.assertEqual(testcolumn.ls_head, 'TESTCOLUMN') - self.assertEqual(testcolumn.ls_width, 50) - finally: - try: - qubes.tools.qvm_ls.Column.columns['TESTCOLUMN'] - except KeyError: - pass - - def test_101_fix_width(self): - try: - testcolumn = qubes.tools.qvm_ls.Column('TESTCOLUMN', width=2) - self.assertGreater(testcolumn.ls_width, len('TESTCOLUMN')) - finally: - try: - qubes.tools.qvm_ls.Column.columns['TESTCOLUMN'] - except KeyError: - pass - - -class TC_90_globals(qubes.tests.QubesTestCase): -# @qubes.tests.skipUnlessDom0 - def test_100_simple_flag(self): - flag = qubes.tools.qvm_ls.simple_flag(1, 'T', 'internal') - - # TODO after serious testing of QubesVM and Qubes app, this should be - # using normal components - app = qubes.tests.vm.TestApp() - vm = qubes.vm.adminvm.AdminVM(app, None, - qid=0, name='dom0', internal='False') - - self.assertFalse(flag(None, vm)) - vm.internal = True - self.assertTrue(flag(None, vm)) - - - def test_900_formats_columns(self): - for fmt in qubes.tools.qvm_ls.formats: - for col in qubes.tools.qvm_ls.formats[fmt]: - self.assertIn(col.upper(), qubes.tools.qvm_ls.Column.columns) diff --git a/qubes/tools/qvm_ls.py b/qubes/tools/qvm_ls.py deleted file mode 100644 index 352f1bed..00000000 --- a/qubes/tools/qvm_ls.py +++ /dev/null @@ -1,634 +0,0 @@ -# pylint: disable=too-few-public-methods - -# -# The Qubes OS Project, https://www.qubes-os.org/ -# -# Copyright (C) 2015 Joanna Rutkowska -# Copyright (C) 2015 Wojtek Porczyk -# -# 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. -# - -'''qvm-ls - List available domains''' - - -from __future__ import print_function - -import argparse -import collections -import sys -import textwrap - -import qubes -import qubes.config -import qubes.tools -import qubes.utils - - -# -# columns -# - -class Column(object): - '''A column in qvm-ls output characterised by its head, a width and a way - to fetch a parameter describing the domain. - - :param str head: Column head (usually uppercase). - :param int width: Column width. - :param str attr: Attribute, possibly complex (containing ``.``). This may \ - also be a callable that gets as its only argument the domain. - :param str doc: Description of column (will be visible in --help-columns). - ''' - - #: collection of all columns - columns = {} - - def __init__(self, head, width=0, attr=None, doc=None): - self.ls_head = head - self.ls_width = max(width, len(self.ls_head) + 1) - self.__doc__ = doc if doc is None else qubes.utils.format_doc(doc) - - # intentionally not always do set self._attr, - # to cause AttributeError in self.format() - if attr is not None: - self._attr = attr - - self.__class__.columns[self.ls_head] = self - - - def cell(self, vm): - '''Format one cell. - - .. note:: - - This is only for technical formatting (filling with space). If you - want to subclass the :py:class:`Column` class, you should override - :py:meth:`Column.format` method instead. - - :param qubes.vm.qubesvm.QubesVM: Domain to get a value from. - :returns: string that is at least as wide as needed to fill table row. - :rtype: str - ''' - - value = self.format(vm) or '-' - return value.ljust(self.ls_width) - - - def format(self, vm): - '''Format one cell value. - - Return value to put in a table cell. - - :param qubes.vm.qubesvm.QubesVM: Domain to get a value from. - :returns: Value to put, or :py:obj:`None` if no value. - :rtype: str or None - ''' - - ret = None - try: - if isinstance(self._attr, str): - ret = vm - for attrseg in self._attr.split('.'): - ret = getattr(ret, attrseg) - elif isinstance(self._attr, collections.Callable): - ret = self._attr(vm) - - except (AttributeError, ZeroDivisionError): - # division by 0 may be caused by arithmetic in callable attr - return None - - if ret is None: - return None - - # late import to avoid circular import - # pylint: disable=redefined-outer-name - import qubes.vm - if isinstance(ret, (qubes.vm.BaseVM, qubes.Label)): - return ret.name - - if isinstance(ret, int): - return str(ret) - - return ret - - def __repr__(self): - return '{}(head={!r}, width={!r})'.format(self.__class__.__name__, - self.ls_head, self.ls_width) - - - def __eq__(self, other): - return self.ls_head == other.ls_head - - - def __lt__(self, other): - return self.ls_head < other.ls_head - - -def column(width=0, head=None): - '''Mark function or plain property as valid column in :program:`qvm-ls`. - - By default all instances of :py:class:`qubes.property` are valid. - - :param int width: Column width - :param str head: Column head (default: take property's name) - ''' - - def decorator(obj): - # pylint: disable=missing-docstring - # we keep hints on fget, so the order of decorators does not matter - holder = obj.fget if isinstance(obj, property) else obj - - try: - holder.ls_head = head or holder.__name__.replace('_', '-').upper() - except AttributeError: - raise TypeError('Cannot find default column name ' - 'for a strange object {!r}'.format(obj)) - - holder.ls_width = max(width, len(holder.ls_head) + 1) - - return obj - - return decorator - - -class PropertyColumn(Column): - '''Column that displays value from property (:py:class:`property` or - :py:class:`qubes.property`) of domain. - - You shouldn't use this class directly, see :py:func:`column` decorator. - - :param holder: Holder of magic attributes. - ''' - - def __init__(self, holder): - super(PropertyColumn, self).__init__( - head=holder.ls_head, - width=holder.ls_width, - attr=holder.__name__, - doc=holder.__doc__) - self.holder = holder - - def __repr__(self): - return '{}(head={!r}, width={!r} holder={!r})'.format( - self.__class__.__name__, - self.ls_head, - self.ls_width, - self.holder) - - -def process_class(cls): - '''Process class after definition to find all listable properties. - - It is used in metaclass of the domain. - - :param qubes.vm.BaseVMMeta cls: Class to round up. - ''' - - for klass in cls.__mro__: - for prop in klass.__dict__.values(): - holder = prop.fget \ - if isinstance(prop, property) \ - else prop - if not hasattr(holder, 'ls_head') or holder.ls_head is None: - continue - - for col in Column.columns.values(): - if not isinstance(col, PropertyColumn): - continue - - if col.holder.__name__ != holder.__name__: - continue - - if col.ls_head != holder.ls_head: - raise TypeError('Found column head mismatch in class {!r} ' - '({!r} != {!r})'.format(cls.__name__, - holder.ls_head, col.ls_head)) - - if col.ls_width != holder.ls_width: - raise TypeError('Found column width mismatch in class {!r} ' - '({!r} != {!r})'.format(cls.__name__, - holder.ls_width, col.ls_width)) - - PropertyColumn(holder) - - -def flag(field): - '''Mark method as flag field. - - :param int field: Which field to fill (counted from 1) - ''' - - def decorator(obj): - # pylint: disable=missing-docstring - obj.field = field - return obj - return decorator - - -def simple_flag(field, letter, attr, doc=None): - '''Create simple, binary flag. - - :param str attr: Attribute name to check. If result is true, flag is fired. - :param str letter: The letter to show. - ''' - - def helper(self, vm): - # pylint: disable=missing-docstring,unused-argument - try: - value = getattr(vm, attr) - except AttributeError: - value = False - - if value: - return letter[0] - - helper.__doc__ = doc - helper.field = field - return helper - - -class StatusColumn(Column): - '''Some fancy flags that describe general status of the domain.''' - # pylint: disable=no-self-use - - def __init__(self): - super(StatusColumn, self).__init__( - head='STATUS', - width=len(self.get_flags()) + 1, - doc=self.__class__.__doc__) - - - @flag(1) - def type(self, vm): - '''Type of domain. - - 0 AdminVM (AKA Dom0) - aA AppVM - dD DisposableVM - sS StandaloneVM - tT TemplateVM - - When it is HVM (optimised VM), the letter is capital. - ''' - - # late import because of circular dependency - # pylint: disable=redefined-outer-name - import qubes.vm - import qubes.vm.adminvm - import qubes.vm.appvm - import qubes.vm.dispvm - import qubes.vm.qubesvm - import qubes.vm.templatevm - - if isinstance(vm, qubes.vm.adminvm.AdminVM): - return '0' - - ret = None - # TODO right order, depending on inheritance - if isinstance(vm, qubes.vm.templatevm.TemplateVM): - ret = 't' - if isinstance(vm, qubes.vm.appvm.AppVM): - ret = 'a' -# if isinstance(vm, qubes.vm.standalonevm.StandaloneVM): -# ret = 's' - if isinstance(vm, qubes.vm.dispvm.DispVM): - ret = 'd' - - if ret is not None: - if getattr(vm, 'hvm', False): - return ret.upper() - - return ret - - - @flag(2) - def power(self, vm): - '''Current power state. - - r running - t transient - p paused - s suspended - h halting - d dying - c crashed - ? unknown - ''' - - state = vm.get_power_state().lower() - if state == 'unknown': - return '?' - elif state in ('running', 'transient', 'paused', 'suspended', - 'halting', 'dying', 'crashed'): - return state[0] - - - updateable = simple_flag(3, 'U', 'updateable', - doc='If the domain is updateable.') - - provides_network = simple_flag(4, 'N', 'provides_network', - doc='If the domain provides network.') - - installed_by_rpm = simple_flag(5, 'R', 'installed_by_rpm', - doc='If the domain is installed by RPM.') - - internal = simple_flag(6, 'i', 'internal', - doc='If the domain is internal (not normally shown, no appmenus).') - - debug = simple_flag(7, 'D', 'debug', - doc='If the domain is being debugged.') - - autostart = simple_flag(8, 'A', 'autostart', - doc='If the domain is marked for autostart.') - - # TODO (not sure if really): - # include in backups - # uses_custom_config - - def _no_flag(self, vm): - '''Reserved for future use.''' - - - @classmethod - def get_flags(cls): - '''Get all flags as list. - - Holes between flags are filled with :py:meth:`_no_flag`. - - :rtype: list - ''' - - flags = {} - for mycls in cls.__mro__: - for attr in mycls.__dict__.values(): - if not hasattr(attr, 'field'): - continue - if attr.field in flags: - continue - flags[attr.field] = attr - - return [(flags[i] if i in flags else cls._no_flag) - for i in range(1, max(flags) + 1)] - - - def format(self, vm): - return ''.join((flag(self, vm) or '-') for flag in self.get_flags()) - - -def calc_size(vm, volume_name): - ''' Calculates the volume size in MB ''' - try: - return vm.volumes[volume_name].size // 1024 // 1024 - except KeyError: - return 0 - -def calc_usage(vm, volume_name): - ''' Calculates the volume usage in MB ''' - try: - return vm.volumes[volume_name].usage // 1024 // 1024 - except KeyError: - return 0 - -def calc_used(vm, volume_name): - ''' Calculates the volume usage in percent ''' - size = calc_size(vm, volume_name) - if size == 0: - return 0 - usage = calc_usage(vm, volume_name) - return usage * 100 // size - - -# todo maxmem - -Column('GATEWAY', width=15, - attr='netvm.gateway', - doc='Network gateway.') - -Column('MEMORY', width=5, - attr=(lambda vm: vm.get_mem() / 1024 if vm.is_running() else None), - doc='Memory currently used by VM') - -Column('DISK', width=5, - attr=(lambda vm: vm.storage.get_disk_utilization() / 1024 / 1024), - doc='Total disk utilisation.') - - -Column('PRIV-CURR', width=5, - attr=(lambda vm: calc_usage(vm, 'private')), - doc='Disk utilisation by private image (/home, /usr/local).') - -Column('PRIV-MAX', width=5, - attr=(lambda vm: calc_size(vm, 'private')), - doc='Maximum available space for private image.') - -Column('PRIV-USED', width=5, - attr=(lambda vm: calc_used(vm, 'private')), - doc='Disk utilisation by private image as a percentage of available space.') - - -Column('ROOT-CURR', width=5, - attr=(lambda vm: calc_usage(vm, 'root')), - doc='Disk utilisation by root image (/usr, /lib, /etc, ...).') - -Column('ROOT-MAX', width=5, - attr=(lambda vm: calc_size(vm, 'root')), - doc='Maximum available space for root image.') - -Column('ROOT-USED', width=5, - attr=(lambda vm: calc_used(vm, 'root')), - doc='Disk utilisation by root image as a percentage of available space.') - - -StatusColumn() - - -class Table(object): - '''Table that is displayed to the user. - - :param qubes.Qubes app: Qubes application object. - :param list colnames: Names of the columns (need not to be uppercase). - ''' - def __init__(self, app, colnames, raw_data=False): - self.app = app - self.columns = tuple(Column.columns[col.upper()] for col in colnames) - self.raw_data = raw_data - - - def format_head(self): - '''Format table head (all column heads).''' - return ''.join('{head:{width}s}'.format( - head=col.ls_head, width=col.ls_width) - for col in self.columns[:-1]) + \ - self.columns[-1].ls_head - - - def format_row(self, vm): - '''Format single table row (all columns for one domain).''' - if self.raw_data: - return '|'.join(col.format(vm) for col in self.columns) - - return ''.join(col.cell(vm) for col in self.columns) - - - def write_table(self, stream=sys.stdout): - '''Write whole table to file-like object. - - :param file stream: Stream to write the table to. - ''' - - if not self.raw_data: - stream.write(self.format_head() + '\n') - for vm in self.app.domains: - stream.write(self.format_row(vm) + '\n') - - -#: Available formats. Feel free to plug your own one. -formats = { - 'simple': ('name', 'status', 'label', 'template', 'netvm'), - 'network': ('name', 'status', 'netvm', 'ip', 'ipback', 'gateway'), - 'full': ('name', 'status', 'label', 'qid', 'xid', 'uuid'), -# 'perf': ('name', 'status', 'cpu', 'memory'), - 'disk': ('name', 'status', 'disk', - 'priv-curr', 'priv-max', 'priv-used', - 'root-curr', 'root-max', 'root-used'), -} - - -class _HelpColumnsAction(argparse.Action): - '''Action for argument parser that displays all columns and exits.''' - # pylint: disable=redefined-builtin - def __init__(self, - option_strings, - dest=argparse.SUPPRESS, - default=argparse.SUPPRESS, - help='list all available columns with short descriptions and exit'): - super(_HelpColumnsAction, self).__init__( - option_strings=option_strings, - dest=dest, - default=default, - nargs=0, - help=help) - - def __call__(self, parser, namespace, values, option_string=None): - width = max(len(column.ls_head) for column in Column.columns.values()) - wrapper = textwrap.TextWrapper(width=80, - initial_indent=' ', subsequent_indent=' ' * (width + 6)) - - text = 'Available columns:\n' + '\n'.join( - wrapper.fill('{head:{width}s} {doc}'.format( - head=column.ls_head, - doc=column.__doc__ or '', - width=width)) - for column in sorted(Column.columns.values())) - parser.exit(message=text + '\n') - -class _HelpFormatsAction(argparse.Action): - '''Action for argument parser that displays all formats and exits.''' - # pylint: disable=redefined-builtin - def __init__(self, - option_strings, - dest=argparse.SUPPRESS, - default=argparse.SUPPRESS, - help='list all available formats with their definitions and exit'): - super(_HelpFormatsAction, self).__init__( - option_strings=option_strings, - dest=dest, - default=default, - nargs=0, - help=help) - - def __call__(self, parser, namespace, values, option_string=None): - width = max(len(fmt) for fmt in formats) - text = 'Available formats:\n' + ''.join( - ' {fmt:{width}s} {columns}\n'.format( - fmt=fmt, columns=','.join(formats[fmt]).upper(), width=width) - for fmt in sorted(formats)) - parser.exit(message=text) - - -def get_parser(): - '''Create :py:class:`argparse.ArgumentParser` suitable for - :program:`qvm-ls`. - ''' - # parser creation is delayed to get all the columns that are scattered - # thorough the modules - - wrapper = textwrap.TextWrapper(width=80, break_on_hyphens=False, - initial_indent=' ', subsequent_indent=' ') - - parser = qubes.tools.QubesArgumentParser( - formatter_class=argparse.RawTextHelpFormatter, - description='List Qubes domains and their parametres.', - epilog='available formats (see --help-formats):\n{}\n\n' - 'available columns (see --help-columns):\n{}'.format( - wrapper.fill(', '.join(sorted(formats.keys()))), - wrapper.fill(', '.join(sorted(sorted(Column.columns.keys())))))) - - parser.add_argument('--help-columns', action=_HelpColumnsAction) - parser.add_argument('--help-formats', action=_HelpFormatsAction) - - - parser_formats = parser.add_mutually_exclusive_group() - - parser_formats.add_argument('--format', '-o', metavar='FORMAT', - action='store', choices=formats.keys(), default='simple', - help='preset format') - - parser_formats.add_argument('--fields', '-O', metavar='FIELD,...', - action='store', - help='user specified format (see available columns below)') - - - parser.add_argument('--raw-data', action='store_true', - help='Display specify data of specified VMs. Intended for ' - 'bash-parsing.') - -# parser.add_argument('--conf', '-c', -# action='store', metavar='CFGFILE', -# help='Qubes config file') - - return parser - - -def main(args=None): - '''Main routine of :program:`qvm-ls`. - - :param list args: Optional arguments to override those delivered from \ - command line. - ''' - - parser = get_parser() - try: - args = parser.parse_args(args) - except qubes.exc.QubesException as e: - parser.print_error(str(e)) - return 1 - - if args.fields: - columns = [col.strip() for col in args.fields.split(',')] - for col in columns: - if col.upper() not in Column.columns: - parser.error('no such column: {!r}'.format(col)) - else: - columns = formats[args.format] - - table = Table(args.app, columns) - table.write_table(sys.stdout) - - return 0 - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/qubes/vm/__init__.py b/qubes/vm/__init__.py index 1efedd79..7f408bf0 100644 --- a/qubes/vm/__init__.py +++ b/qubes/vm/__init__.py @@ -38,7 +38,6 @@ import qubes import qubes.devices import qubes.events import qubes.log -import qubes.tools.qvm_ls VM_ENTRY_POINT = 'qubes.vm' @@ -164,7 +163,6 @@ class BaseVMMeta(qubes.events.EmitterMeta): '''Metaclass for :py:class:`.BaseVM`''' def __init__(cls, name, bases, dict_): super(BaseVMMeta, cls).__init__(name, bases, dict_) - qubes.tools.qvm_ls.process_class(cls) class BaseVM(qubes.PropertyHolder, metaclass=BaseVMMeta): diff --git a/qubes/vm/appvm.py b/qubes/vm/appvm.py index d5269742..70a1e753 100644 --- a/qubes/vm/appvm.py +++ b/qubes/vm/appvm.py @@ -34,7 +34,6 @@ class AppVM(qubes.vm.qubesvm.QubesVM): template = qubes.VMProperty('template', load_stage=4, vmclass=qubes.vm.templatevm.TemplateVM, - ls_width=31, doc='Template, on which this AppVM is based.') dispvm_allowed = qubes.property('dispvm_allowed', diff --git a/qubes/vm/dispvm.py b/qubes/vm/dispvm.py index bd421831..dd660b55 100644 --- a/qubes/vm/dispvm.py +++ b/qubes/vm/dispvm.py @@ -33,12 +33,10 @@ class DispVM(qubes.vm.qubesvm.QubesVM): template = qubes.VMProperty('template', load_stage=4, vmclass=qubes.vm.appvm.AppVM, - ls_width=31, doc='AppVM, on which this DispVM is based.') dispid = qubes.property('dispid', type=int, write_once=True, clone=False, - ls_width=3, doc='''Internal, persistent identifier of particular DispVM.''') def __init__(self, *args, **kwargs): diff --git a/qubes/vm/mix/net.py b/qubes/vm/mix/net.py index 7d1913d3..1ce9d651 100644 --- a/qubes/vm/mix/net.py +++ b/qubes/vm/mix/net.py @@ -68,20 +68,17 @@ class NetVMMixin(qubes.events.Emitter): mac = qubes.property('mac', type=str, default='00:16:3E:5E:6C:00', setter=_setter_mac, - ls_width=17, doc='MAC address of the NIC emulated inside VM') ip = qubes.property('ip', type=str, default=_default_ip, setter=_setter_ip, - ls_width=15, doc='IP address of this domain.') # CORE2: swallowed uses_default_netvm netvm = qubes.VMProperty('netvm', load_stage=4, allow_none=True, default=(lambda self: self.app.default_fw_netvm if self.provides_network else self.app.default_netvm), - ls_width=31, doc='''VM that provides network connection to this domain. When `None`, machine is disconnected. When absent, domain uses default NetVM.''') @@ -101,21 +98,18 @@ class NetVMMixin(qubes.events.Emitter): # - @qubes.tools.qvm_ls.column(width=15) @property def visible_ip(self): '''IP address of this domain as seen by the domain.''' return self.features.check_with_template('net/fake-ip', None) or \ self.ip - @qubes.tools.qvm_ls.column(width=15) @property def visible_gateway(self): '''Default gateway of this domain as seen by the domain.''' return self.features.check_with_template('net/fake-gateway', None) or \ self.netvm.gateway - @qubes.tools.qvm_ls.column(width=15) @property def visible_netmask(self): '''Netmask as seen by the domain.''' @@ -139,13 +133,11 @@ class NetVMMixin(qubes.events.Emitter): # does not happen, because qid < 253, but may happen in the future. return '10.137.{}.{}'.format((vm.qid >> 8) & 7, vm.qid & 7) - @qubes.tools.qvm_ls.column(head='IPBACK', width=15) @property def gateway(self): '''Gateway for other domains that use this domain as netvm.''' return self.visible_ip if self.provides_network else None - @qubes.tools.qvm_ls.column(width=15) @property def netmask(self): '''Netmask for gateway address.''' @@ -164,7 +156,6 @@ class NetVMMixin(qubes.events.Emitter): # used in both # - @qubes.tools.qvm_ls.column(width=15) @property def dns(self): '''Secondary DNS server set up for this domain.''' diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index 45818be6..30ae8e8a 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -47,7 +47,6 @@ 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 @@ -357,7 +356,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): label = qubes.property('label', setter=_setter_label, saver=(lambda self, prop, value: 'label-{}'.format(value.index)), - ls_width=14, doc='''Colourful label assigned to VM. This is where the colour of the padlock is set.''') @@ -368,18 +366,15 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): qid = qubes.property('qid', type=int, write_once=True, setter=_setter_qid, clone=False, - ls_width=3, doc='''Internal, persistent identificator of particular domain. Note this is different from Xen domid.''') name = qubes.property('name', type=str, clone=False, - ls_width=31, doc='User-specified name of the domain.') uuid = qubes.property('uuid', type=uuid.UUID, write_once=True, clone=False, - ls_width=36, doc='UUID from libvirt.') hvm = qubes.property('hvm', @@ -416,14 +411,12 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): type=int, setter=_setter_positive_int, default=(lambda self: self.app.host.no_cpus), - ls_width=2, doc='FIXME') # CORE2: swallowed uses_default_kernel kernel = qubes.property('kernel', type=str, setter=_setter_kernel, default=(lambda self: self.app.default_kernel), - ls_width=12, doc='Kernel used by this domain.') # CORE2: swallowed uses_default_kernelopts @@ -434,7 +427,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): if list(self.devices['pci'].persistent()) else self.template.kernelopts if hasattr(self, 'template') else qubes.config.defaults['kernelopts']), - ls_width=30, doc='Kernel command line passed to domain.') debug = qubes.property('debug', type=bool, default=False, @@ -449,7 +441,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): default=(lambda self: self.template.default_user if hasattr(self, 'template') else 'user'), setter=_setter_default_user, - ls_width=12, doc='FIXME') # pylint: enable=no-member @@ -463,7 +454,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): qrexec_timeout = qubes.property('qrexec_timeout', type=int, default=60, setter=_setter_positive_int, - ls_width=3, doc='''Time in seconds after which qrexec connection attempt is deemed failed. Operating system inside VM should be able to boot in this time.''') @@ -512,7 +502,6 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): # VMM-related - @qubes.tools.qvm_ls.column(width=3) @property def xid(self): '''Xen ID. diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index 0f1a9de3..15abef01 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -288,7 +288,6 @@ fi %{python3_sitelib}/qubes/tools/qvm_check.py %{python3_sitelib}/qubes/tools/qvm_clone.py %{python3_sitelib}/qubes/tools/qvm_kill.py -%{python3_sitelib}/qubes/tools/qvm_ls.py %{python3_sitelib}/qubes/tools/qvm_pause.py %{python3_sitelib}/qubes/tools/qvm_pool.py %{python3_sitelib}/qubes/tools/qvm_prefs.py @@ -349,7 +348,6 @@ fi %{python3_sitelib}/qubes/tests/tools/init.py %{python3_sitelib}/qubes/tests/tools/qvm_device.py %{python3_sitelib}/qubes/tests/tools/qvm_firewall.py -%{python3_sitelib}/qubes/tests/tools/qvm_ls.py %dir %{python3_sitelib}/qubes/tests/integ %dir %{python3_sitelib}/qubes/tests/integ/__pycache__