qubes/tools: custom QubesArgumentParser
Common functions that revolve around running the tool (like `dont_run_as_root`) will be methods of this class.
This commit is contained in:
parent
c9cbf8ffe2
commit
55e4ddcd3d
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import importlib
|
import importlib
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import qubes.log
|
import qubes.log
|
||||||
@ -85,37 +86,82 @@ class SinglePropertyAction(argparse.Action):
|
|||||||
if self.const is None else self.const
|
if self.const is None else self.const
|
||||||
|
|
||||||
|
|
||||||
# TODO --verbose, logger setup
|
class QubesArgumentParser(argparse.ArgumentParser):
|
||||||
def get_parser_base(want_force_root=False, **kwargs):
|
'''Parser preconfigured for use in most of the Qubes command-line tools.
|
||||||
'''Get base parser with options common to all Qubes OS tools.
|
|
||||||
|
|
||||||
:param bool want_force_root: add ``--force-root`` option
|
: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`.
|
*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',
|
def __init__(self,
|
||||||
action='store',
|
want_force_root=False,
|
||||||
help=argparse.SUPPRESS)
|
want_vmname=False,
|
||||||
|
**kwargs):
|
||||||
|
self.add_argument('--xml', metavar='XMLFILE',
|
||||||
|
action='store',
|
||||||
|
help=argparse.SUPPRESS)
|
||||||
|
|
||||||
parser.add_argument('--verbose', '-v',
|
self.add_argument('--verbose', '-v',
|
||||||
action='count',
|
action='count',
|
||||||
help='increase verbosity')
|
help='increase verbosity')
|
||||||
|
|
||||||
parser.add_argument('--quiet', '-q',
|
self.add_argument('--quiet', '-q',
|
||||||
action='count',
|
action='count',
|
||||||
help='decrease verbosity')
|
help='decrease verbosity')
|
||||||
|
|
||||||
if want_force_root:
|
if want_force_root:
|
||||||
parser.add_argument('--force-root',
|
self.add_argument('--force-root',
|
||||||
action='store_true', default=False,
|
action='store_true', default=False,
|
||||||
help='Force to run as root.')
|
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):
|
def get_parser_for_command(command):
|
||||||
@ -139,37 +185,3 @@ def get_parser_for_command(command):
|
|||||||
raise AttributeError('cannot find parser in module')
|
raise AttributeError('cannot find parser in module')
|
||||||
|
|
||||||
return parser
|
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()
|
|
||||||
|
@ -170,7 +170,7 @@ class QMemmanReqHandler(SocketServer.BaseRequestHandler):
|
|||||||
# XXX no release of lock?
|
# XXX no release of lock?
|
||||||
|
|
||||||
|
|
||||||
parser = qubes.tools.get_parser_base()
|
parser = qubes.tools.QubesArgumentParser()
|
||||||
|
|
||||||
parser.add_argument('--config', '-c', metavar='FILE',
|
parser.add_argument('--config', '-c', metavar='FILE',
|
||||||
action='store', default='/etc/qubes/qmemman.conf',
|
action='store', default='/etc/qubes/qmemman.conf',
|
||||||
@ -208,7 +208,7 @@ def main():
|
|||||||
|
|
||||||
sys.stdin.close()
|
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')
|
log = logging.getLogger('qmemman.daemon')
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ import argparse
|
|||||||
import qubes
|
import qubes
|
||||||
import qubes.tools
|
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',
|
parser.add_argument('--property', '--prop', '-p',
|
||||||
action=qubes.tools.PropertyAction,
|
action=qubes.tools.PropertyAction,
|
||||||
@ -45,7 +46,7 @@ def main(args=None):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
args = parser.parse_args(args)
|
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)
|
app = qubes.Qubes.create_empty_store(args.xml, **args.properties)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ import qubes
|
|||||||
import qubes.tools
|
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',
|
parser.add_argument('--class', '-C', dest='cls',
|
||||||
default='AppVM',
|
default='AppVM',
|
||||||
@ -75,8 +75,8 @@ parser.add_argument('name', metavar='VMNAME',
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
qubes.tools.set_verbosity(parser, args)
|
parser.set_verbosity(args)
|
||||||
qubes.tools.dont_run_as_root(parser, args)
|
parser.dont_run_as_root(args)
|
||||||
|
|
||||||
if 'label' not in args.properties:
|
if 'label' not in args.properties:
|
||||||
parser.error('--label option is mandatory')
|
parser.error('--label option is mandatory')
|
||||||
|
@ -595,7 +595,7 @@ def main(args=None):
|
|||||||
|
|
||||||
parser = get_parser()
|
parser = get_parser()
|
||||||
args = parser.parse_args(args)
|
args = parser.parse_args(args)
|
||||||
qubes.tools.set_verbosity(parser, args)
|
parser.set_qubes_verbosity(args)
|
||||||
app = qubes.Qubes(args.xml)
|
app = qubes.Qubes(args.xml)
|
||||||
|
|
||||||
if args.fields:
|
if args.fields:
|
||||||
|
@ -70,13 +70,12 @@ class _HelpPropertiesAction(argparse.Action):
|
|||||||
+ '\n\nThere may be more properties in specific domain classes.\n')
|
+ '\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('--help-properties', action=_HelpPropertiesAction)
|
||||||
|
|
||||||
parser.add_argument('name', metavar='VMNAME',
|
|
||||||
help='name of the domain to change')
|
|
||||||
|
|
||||||
parser.add_argument('property', metavar='PROPERTY',
|
parser.add_argument('property', metavar='PROPERTY',
|
||||||
nargs='?',
|
nargs='?',
|
||||||
help='name of the property to show or change')
|
help='name of the property to show or change')
|
||||||
@ -96,28 +95,28 @@ parser.add_argument('--unset', '--default', '--delete', '-D',
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
qubes.tools.set_verbosity(parser, args)
|
parser.set_verbosity(args)
|
||||||
qubes.tools.dont_run_as_root(parser, args)
|
parser.dont_run_as_root(args)
|
||||||
|
|
||||||
app = qubes.Qubes(args.xml)
|
app = qubes.Qubes(args.xml)
|
||||||
try:
|
try:
|
||||||
domain = app.domains[args.name]
|
vm = app.domains[args.vmname]
|
||||||
except KeyError:
|
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:
|
if args.property is None:
|
||||||
properties = domain.property_list()
|
properties = vm.property_list()
|
||||||
width = max(len(prop.__name__) for prop in properties)
|
width = max(len(prop.__name__) for prop in properties)
|
||||||
|
|
||||||
for prop in sorted(properties):
|
for prop in sorted(properties):
|
||||||
try:
|
try:
|
||||||
value = getattr(domain, prop.__name__)
|
value = getattr(vm, prop.__name__)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print('{name:{width}s} U'.format(
|
print('{name:{width}s} U'.format(
|
||||||
name=prop.__name__, width=width))
|
name=prop.__name__, width=width))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if domain.property_is_default(prop):
|
if vm.property_is_default(prop):
|
||||||
print('{name:{width}s} D {value!r}'.format(
|
print('{name:{width}s} D {value!r}'.format(
|
||||||
name=prop.__name__, width=width, value=value))
|
name=prop.__name__, width=width, value=value))
|
||||||
else:
|
else:
|
||||||
@ -128,17 +127,17 @@ def main():
|
|||||||
|
|
||||||
|
|
||||||
if args.value is not None:
|
if args.value is not None:
|
||||||
setattr(domain, args.property, args.value)
|
setattr(vm, args.property, args.value)
|
||||||
app.save()
|
app.save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if args.delete:
|
if args.delete:
|
||||||
delattr(domain, args.property)
|
delattr(vm, args.property)
|
||||||
app.save()
|
app.save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
print(str(getattr(domain, args.property)))
|
print(str(getattr(vm, args.property)))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -47,7 +47,9 @@ class DriveAction(argparse.Action):
|
|||||||
setattr(namespace, self.dest, prefix + value)
|
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()
|
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,
|
#parser.add_option ("--tray", action="store_true", dest="tray", default=False,
|
||||||
# help="Use tray notifications instead of stdout" )
|
# help="Use tray notifications instead of stdout" )
|
||||||
|
|
||||||
parser.add_argument('name', metavar='VMNAME',
|
|
||||||
help='domain to start')
|
|
||||||
|
|
||||||
parser.set_defaults(drive=None)
|
parser.set_defaults(drive=None)
|
||||||
|
|
||||||
def main(args=None):
|
def main(args=None):
|
||||||
@ -103,7 +102,7 @@ def main(args=None):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
args = parser.parse_args(args)
|
args = parser.parse_args(args)
|
||||||
qubes.tools.set_verbosity(parser, args)
|
parser.set_qubes_verbosity(parser, args)
|
||||||
app = qubes.Qubes(args.xml)
|
app = qubes.Qubes(args.xml)
|
||||||
|
|
||||||
# if options.tray:
|
# if options.tray:
|
||||||
|
Loading…
Reference in New Issue
Block a user