Browse Source

qubes/tools: custom QubesArgumentParser

Common functions that revolve around running the tool (like
`dont_run_as_root`) will be methods of this class.
Wojtek Porczyk 8 years ago
parent
commit
55e4ddcd3d

+ 66 - 54
qubes/tools/__init__.py

@@ -27,6 +27,7 @@
 
 import argparse
 import importlib
+import logging
 import os
 
 import qubes.log
@@ -85,37 +86,82 @@ class SinglePropertyAction(argparse.Action):
             if self.const is None else self.const
 
 
-# TODO --verbose, logger setup
-def get_parser_base(want_force_root=False, **kwargs):
-    '''Get base parser with options common to all Qubes OS tools.
+class QubesArgumentParser(argparse.ArgumentParser):
+    '''Parser preconfigured for use in most of the Qubes command-line tools.
 
     :param bool want_force_root: add ``--force-root`` option
+    :param bool want_vmname: add ``VMNAME`` as first positional argument
     *kwargs* are passed to :py:class:`argparser.ArgumentParser`.
 
-    Currently supported options: ``--force-root`` (optional), ``--xml``.
+    Currenty supported options:
+        ``--force-root`` (optional)
+        ``--xml`` location of :file:`qubes.xml` (help is suppressed)
+        ``--verbose`` and ``--quiet``
     '''
-    parser = argparse.ArgumentParser(**kwargs)
 
-    parser.add_argument('--xml', metavar='XMLFILE',
-        action='store',
-        help=argparse.SUPPRESS)
+    def __init__(self,
+            want_force_root=False,
+            want_vmname=False,
+            **kwargs):
+        self.add_argument('--xml', metavar='XMLFILE',
+            action='store',
+            help=argparse.SUPPRESS)
 
-    parser.add_argument('--verbose', '-v',
-        action='count',
-        help='increase verbosity')
+        self.add_argument('--verbose', '-v',
+            action='count',
+            help='increase verbosity')
 
-    parser.add_argument('--quiet', '-q',
-        action='count',
-        help='decrease verbosity')
+        self.add_argument('--quiet', '-q',
+            action='count',
+            help='decrease verbosity')
 
-    if want_force_root:
-        parser.add_argument('--force-root',
-            action='store_true', default=False,
-            help='Force to run as root.')
+        if want_force_root:
+            self.add_argument('--force-root',
+                action='store_true', default=False,
+                help='force to run as root')
 
-    parser.set_defaults(verbose=1, quiet=0)
+        if want_vmname:
+            self.add_argument('vmname', metavar='VMNAME',
+                action='store',
+                help='name of the domain')
 
-    return parser
+        self.set_defaults(verbose=1, quiet=0)
+
+
+    def dont_run_as_root(self, args):
+        '''Prevent running as root.
+
+        :param argparse.Namespace args: if there is ``.force_root`` attribute \
+            set to true, run anyway
+        '''
+        try:
+            euid = os.geteuid()
+        except AttributeError: # no geteuid(), probably NT
+            return
+
+        if euid == 0 and not args.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
+
+
+    @staticmethod
+    def set_qubes_verbosity(args):
+        '''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
+
+        if verbose >= 2:
+            qubes.log.enable_debug()
+        elif verbose >= 1:
+            qubes.log.enable()
 
 
 def get_parser_for_command(command):
@@ -139,37 +185,3 @@ def get_parser_for_command(command):
             raise AttributeError('cannot find parser in module')
 
     return parser
-
-
-def dont_run_as_root(parser, args):
-    '''Prevent running as root.
-
-    :param argparse.ArgumentParser parser: parser on which we invoke error
-    :param argparse.Namespace args: if there is ``.force_root`` attribute set \
-        to true, run anyway
-    :return: If we should back off
-    :rtype bool:
-    '''
-    try:
-        euid = os.geteuid()
-    except AttributeError: # no geteuid(), probably NT
-        return
-
-    if euid == 0 and not args.force_root:
-        parser.error('refusing to run as root; add --force-root to override')
-
-
-def set_verbosity(parser, args):
-    '''Apply a verbosity setting.
-
-    This is done by configuring global logging.
-    :param argparse.ArgumentParser parser: command parser
-    :param argparse.Namespace args: args as parsed by parser
-    '''
-
-    verbose = args.verbose - args.quiet
-
-    if verbose >= 2:
-        qubes.log.enable_debug()
-    elif verbose >= 1:
-        qubes.log.enable()

+ 2 - 2
qubes/tools/qmemmand.py

@@ -170,7 +170,7 @@ class QMemmanReqHandler(SocketServer.BaseRequestHandler):
             # XXX no release of lock?
 
 
-parser = qubes.tools.get_parser_base()
+parser = qubes.tools.QubesArgumentParser()
 
 parser.add_argument('--config', '-c', metavar='FILE',
     action='store', default='/etc/qubes/qmemman.conf',
@@ -208,7 +208,7 @@ def main():
 
     sys.stdin.close()
 
-    logging.root.setLevel((args.quiet - args.verbose) * 10 + logging.WARNING)
+    logging.root.setLevel(parser.get_loglevel_from_verbosity(args))
 
     log = logging.getLogger('qmemman.daemon')
 

+ 3 - 2
qubes/tools/qubes_create.py

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

+ 3 - 3
qubes/tools/qvm_create.py

@@ -36,7 +36,7 @@ import qubes
 import qubes.tools
 
 
-parser = qubes.tools.get_parser_base(want_force_root=True)
+parser = qubes.tools.QubesArgumentParser(want_force_root=True)
 
 parser.add_argument('--class', '-C', dest='cls',
     default='AppVM',
@@ -75,8 +75,8 @@ parser.add_argument('name', metavar='VMNAME',
 
 def main():
     args = parser.parse_args()
-    qubes.tools.set_verbosity(parser, args)
-    qubes.tools.dont_run_as_root(parser, args)
+    parser.set_verbosity(args)
+    parser.dont_run_as_root(args)
 
     if 'label' not in args.properties:
         parser.error('--label option is mandatory')

+ 1 - 1
qubes/tools/qvm_ls.py

@@ -595,7 +595,7 @@ def main(args=None):
 
     parser = get_parser()
     args = parser.parse_args(args)
-    qubes.tools.set_verbosity(parser, args)
+    parser.set_qubes_verbosity(args)
     app = qubes.Qubes(args.xml)
 
     if args.fields:

+ 13 - 14
qubes/tools/qvm_prefs.py

@@ -70,13 +70,12 @@ class _HelpPropertiesAction(argparse.Action):
             + '\n\nThere may be more properties in specific domain classes.\n')
 
 
-parser = qubes.tools.get_parser_base(want_force_root=True)
+parser = qubes.tools.QubesArgumentParser(
+    want_force_root=True,
+    want_vmname=True)
 
 parser.add_argument('--help-properties', action=_HelpPropertiesAction)
 
-parser.add_argument('name', metavar='VMNAME',
-    help='name of the domain to change')
-
 parser.add_argument('property', metavar='PROPERTY',
     nargs='?',
     help='name of the property to show or change')
@@ -96,28 +95,28 @@ parser.add_argument('--unset', '--default', '--delete', '-D',
 
 def main():
     args = parser.parse_args()
-    qubes.tools.set_verbosity(parser, args)
-    qubes.tools.dont_run_as_root(parser, args)
+    parser.set_verbosity(args)
+    parser.dont_run_as_root(args)
 
     app = qubes.Qubes(args.xml)
     try:
-        domain = app.domains[args.name]
+        vm = app.domains[args.vmname]
     except KeyError:
-        parser.error('no such domain: {!r}'.format(args.name))
+        parser.error('no such domain: {!r}'.format(args.vmname))
 
     if args.property is None:
-        properties = domain.property_list()
+        properties = vm.property_list()
         width = max(len(prop.__name__) for prop in properties)
 
         for prop in sorted(properties):
             try:
-                value = getattr(domain, prop.__name__)
+                value = getattr(vm, prop.__name__)
             except AttributeError:
                 print('{name:{width}s}  U'.format(
                     name=prop.__name__, width=width))
                 continue
 
-            if domain.property_is_default(prop):
+            if vm.property_is_default(prop):
                 print('{name:{width}s}  D  {value!r}'.format(
                     name=prop.__name__, width=width, value=value))
             else:
@@ -128,17 +127,17 @@ def main():
 
 
     if args.value is not None:
-        setattr(domain, args.property, args.value)
+        setattr(vm, args.property, args.value)
         app.save()
         return True
 
     if args.delete:
-        delattr(domain, args.property)
+        delattr(vm, args.property)
         app.save()
         return True
 
 
-    print(str(getattr(domain, args.property)))
+    print(str(getattr(vm, args.property)))
 
     return True
 

+ 4 - 5
qubes/tools/qvm_start.py

@@ -47,7 +47,9 @@ class DriveAction(argparse.Action):
         setattr(namespace, self.dest, prefix + value)
 
 
-parser = qubes.tools.get_parser_base(description='start a domain')
+parser = qubes.tools.QubesArgumentParser(
+    want_vmname=True,
+    description='start a domain')
 
 
 parser_drive = parser.add_mutually_exclusive_group()
@@ -90,9 +92,6 @@ parser.add_argument('--no-start-guid',
 #parser.add_option ("--tray", action="store_true", dest="tray", default=False,
 #                   help="Use tray notifications instead of stdout" )
 
-parser.add_argument('name', metavar='VMNAME',
-    help='domain to start')
-
 parser.set_defaults(drive=None)
 
 def main(args=None):
@@ -103,7 +102,7 @@ def main(args=None):
     '''
 
     args = parser.parse_args(args)
-    qubes.tools.set_verbosity(parser, args)
+    parser.set_qubes_verbosity(parser, args)
     app = qubes.Qubes(args.xml)
 
 #   if options.tray: