Browse Source

qubes/tools: unify looking up the domain

This is common operation that is repeatable.
Wojtek Porczyk 8 years ago
parent
commit
015b01fe46

+ 48 - 15
qubes/tools/__init__.py

@@ -89,23 +89,37 @@ class SinglePropertyAction(argparse.Action):
 class QubesArgumentParser(argparse.ArgumentParser):
     '''Parser preconfigured for use in most of the Qubes command-line tools.
 
+    :param bool want_app: instantiate :py:class:`qubes.Qubes` object
+    :param bool want_app_no_instance: don't actually instantiate \
+        :py:class:`qubes.Qubes` object, just add argument for custom xml file
     :param bool want_force_root: add ``--force-root`` option
-    :param bool want_vmname: add ``VMNAME`` as first positional argument
+    :param bool want_vm: add ``VMNAME`` as first positional argument
     *kwargs* are passed to :py:class:`argparser.ArgumentParser`.
 
     Currenty supported options:
         ``--force-root`` (optional)
-        ``--xml`` location of :file:`qubes.xml` (help is suppressed)
+        ``--qubesxml`` location of :file:`qubes.xml` (help is suppressed)
         ``--verbose`` and ``--quiet``
     '''
 
     def __init__(self,
+            want_app=True,
+            want_app_no_instance=False,
             want_force_root=False,
-            want_vmname=False,
+            want_vm=False,
             **kwargs):
-        self.add_argument('--xml', metavar='XMLFILE',
-            action='store',
-            help=argparse.SUPPRESS)
+
+        super(QubesArgumentParser, self).__init__(**kwargs)
+
+        self._want_app = want_app
+        self._want_app_no_instance = want_app_no_instance
+        self._want_force_root = want_force_root
+        self._want_vm = want_vm
+
+        if self._want_app:
+            self.add_argument('--qubesxml', metavar='FILE',
+                action='store', dest='app',
+                help=argparse.SUPPRESS)
 
         self.add_argument('--verbose', '-v',
             action='count',
@@ -115,20 +129,39 @@ class QubesArgumentParser(argparse.ArgumentParser):
             action='count',
             help='decrease verbosity')
 
-        if want_force_root:
+        if self._want_force_root:
             self.add_argument('--force-root',
                 action='store_true', default=False,
                 help='force to run as root')
 
-        if want_vmname:
-            self.add_argument('vmname', metavar='VMNAME',
+        if self._want_vm:
+            self.add_argument('vm', metavar='VMNAME',
                 action='store',
                 help='name of the domain')
 
         self.set_defaults(verbose=1, quiet=0)
 
 
-    def dont_run_as_root(self, args):
+    def parse_args(self, *args, **kwargs):
+        namespace = super(QubesArgumentParser, self).parse_args(*args, **kwargs)
+
+        if self._want_app and not self._want_app_no_instance:
+            self.set_qubes_verbosity(namespace)
+            namespace.app = qubes.Qubes(namespace.app)
+
+            if self._want_vm:
+                try:
+                    namespace.vm = namespace.app.domains[namespace.vm]
+                except KeyError:
+                    self.error('no such domain: {!r}'.format(namespace.vm))
+
+        if self._want_force_root:
+            self.dont_run_as_root(namespace)
+
+        return namespace
+
+
+    def dont_run_as_root(self, namespace):
         '''Prevent running as root.
 
         :param argparse.Namespace args: if there is ``.force_root`` attribute \
@@ -139,24 +172,24 @@ class QubesArgumentParser(argparse.ArgumentParser):
         except AttributeError: # no geteuid(), probably NT
             return
 
-        if euid == 0 and not args.force_root:
+        if euid == 0 and not namespace.force_root:
             self.error('refusing to run as root; add --force-root to override')
 
 
     @staticmethod
-    def get_loglevel_from_verbosity(args):
-        return (args.quiet - args.verbose) * 10 + logging.WARNING
+    def get_loglevel_from_verbosity(namespace):
+        return (namespace.quiet - namespace.verbose) * 10 + logging.WARNING
 
 
     @staticmethod
-    def set_qubes_verbosity(args):
+    def set_qubes_verbosity(namespace):
         '''Apply a verbosity setting.
 
         This is done by configuring global logging.
         :param argparse.Namespace args: args as parsed by parser
         '''
 
-        verbose = args.verbose - args.quiet
+        verbose = namespace.verbose - namespace.quiet
 
         if verbose >= 2:
             qubes.log.enable_debug()

+ 1 - 1
qubes/tools/qmemmand.py

@@ -170,7 +170,7 @@ class QMemmanReqHandler(SocketServer.BaseRequestHandler):
             # XXX no release of lock?
 
 
-parser = qubes.tools.QubesArgumentParser()
+parser = qubes.tools.QubesArgumentParser(want_app=False)
 
 parser.add_argument('--config', '-c', metavar='FILE',
     action='store', default='/etc/qubes/qmemman.conf',

+ 4 - 3
qubes/tools/qubes_create.py

@@ -31,7 +31,9 @@ import qubes
 import qubes.tools
 
 parser = qubes.tools.QubesArgumentParser(
-    description='Create new Qubes OS store.')
+    description='Create new Qubes OS store.',
+    want_app=True,
+    want_app_no_instance=True)
 
 parser.add_argument('--property', '--prop', '-p',
     action=qubes.tools.PropertyAction,
@@ -46,8 +48,7 @@ def main(args=None):
     '''
 
     args = parser.parse_args(args)
-    parser.set_qubes_verbosity(args)
-    app = qubes.Qubes.create_empty_store(args.xml, **args.properties)
+    app = qubes.Qubes.create_empty_store(args.app, **args.properties)
     return True
 
 

+ 6 - 9
qubes/tools/qvm_create.py

@@ -73,10 +73,8 @@ parser.add_argument('name', metavar='VMNAME',
 
 #parser.add_option ("-q", "--quiet", action="store_false", dest="verbose", default=True)
 
-def main():
-    args = parser.parse_args()
-    parser.set_verbosity(args)
-    parser.dont_run_as_root(args)
+def main(args=None):
+    args = parser.parse_args(args)
 
     if 'label' not in args.properties:
         parser.error('--label option is mandatory')
@@ -84,12 +82,11 @@ def main():
     if 'name' not in args.properties:
         parser.error('VMNAME is mandatory')
 
-    app = qubes.Qubes(args.xml)
     try:
-        label = app.get_label(args.properties['label'])
+        label = args.app.get_label(args.properties['label'])
     except KeyError:
         parser.error('no such label: {!r}; available: {}'.format(args.label,
-            ', '.join(repr(l.name) for l in app.labels)))
+            ', '.join(repr(l.name) for l in args.app.labels)))
 
     try:
         cls = qubes.vm.BaseVM.register[args.cls]
@@ -100,7 +97,7 @@ def main():
             'template' not in (prop.__name__ for prop in cls.property_list()):
         parser.error('this domain class does not support template')
 
-    vm = app.add_new_vm(cls, **args.properties)
+    vm = args.app.add_new_vm(cls, **args.properties)
 
 #   if not options.standalone and any([options.root_copy_from, options.root_move_from]):
 #       print >> sys.stderr, "root.img can be specified only for standalone VMs"
@@ -146,7 +143,7 @@ def main():
         except (IOError, OSError) as err:
             parser.error(str(err))
 
-    app.save()
+    args.app.save()
 
     return True
 

+ 1 - 3
qubes/tools/qvm_ls.py

@@ -595,8 +595,6 @@ def main(args=None):
 
     parser = get_parser()
     args = parser.parse_args(args)
-    parser.set_qubes_verbosity(args)
-    app = qubes.Qubes(args.xml)
 
     if args.fields:
         columns = [col.strip() for col in args.fields.split(',')]
@@ -606,7 +604,7 @@ def main(args=None):
     else:
         columns = formats[args.format]
 
-    table = Table(app, columns)
+    table = Table(args.app, columns)
     table.write_table(sys.stdout)
 
     return True

+ 9 - 17
qubes/tools/qvm_prefs.py

@@ -72,7 +72,7 @@ class _HelpPropertiesAction(argparse.Action):
 
 parser = qubes.tools.QubesArgumentParser(
     want_force_root=True,
-    want_vmname=True)
+    want_vm=True)
 
 parser.add_argument('--help-properties', action=_HelpPropertiesAction)
 
@@ -95,28 +95,20 @@ parser.add_argument('--unset', '--default', '--delete', '-D',
 
 def main():
     args = parser.parse_args()
-    parser.set_verbosity(args)
-    parser.dont_run_as_root(args)
-
-    app = qubes.Qubes(args.xml)
-    try:
-        vm = app.domains[args.vmname]
-    except KeyError:
-        parser.error('no such domain: {!r}'.format(args.vmname))
 
     if args.property is None:
-        properties = vm.property_list()
+        properties = args.vm.property_list()
         width = max(len(prop.__name__) for prop in properties)
 
         for prop in sorted(properties):
             try:
-                value = getattr(vm, prop.__name__)
+                value = getattr(args.vm, prop.__name__)
             except AttributeError:
                 print('{name:{width}s}  U'.format(
                     name=prop.__name__, width=width))
                 continue
 
-            if vm.property_is_default(prop):
+            if args.vm.property_is_default(prop):
                 print('{name:{width}s}  D  {value!r}'.format(
                     name=prop.__name__, width=width, value=value))
             else:
@@ -127,17 +119,17 @@ def main():
 
 
     if args.value is not None:
-        setattr(vm, args.property, args.value)
-        app.save()
+        setattr(args.vm, args.property, args.value)
+        args.app.save()
         return True
 
     if args.delete:
-        delattr(vm, args.property)
-        app.save()
+        delattr(args.vm, args.property)
+        args.app.save()
         return True
 
 
-    print(str(getattr(vm, args.property)))
+    print(str(getattr(args.vm, args.property)))
 
     return True
 

+ 2 - 7
qubes/tools/qvm_start.py

@@ -48,7 +48,7 @@ class DriveAction(argparse.Action):
 
 
 parser = qubes.tools.QubesArgumentParser(
-    want_vmname=True,
+    want_vm=True,
     description='start a domain')
 
 
@@ -102,16 +102,11 @@ def main(args=None):
     '''
 
     args = parser.parse_args(args)
-    parser.set_qubes_verbosity(parser, args)
-    app = qubes.Qubes(args.xml)
 
 #   if options.tray:
 #       tray_notify_init()
 
-    try:
-        vm = app.domains[args.name]
-    except KeyError:
-        parser.error('no such domain: {!r}'.format(args.name))
+    vm = args.vm
 
     if args.drive is not None:
         if 'drive' not in (prop.__name__ for prop in vm.property_list()):