From bb770b47447558a5f6d06498b7ffe44802b23e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Wed, 1 Mar 2017 15:21:55 +0100 Subject: [PATCH] tools: include a few simple tools QubesOS/qubes-issues#853 --- qubesmgmt/tools/qubes_prefs.py | 115 +++++++++++++++++++++++++++++++ qubesmgmt/tools/qvm_kill.py | 55 +++++++++++++++ qubesmgmt/tools/qvm_pause.py | 48 +++++++++++++ qubesmgmt/tools/qvm_prefs.py | 116 ++++++++++++++++++++++++++++++++ qubesmgmt/tools/qvm_shutdown.py | 82 ++++++++++++++++++++++ qubesmgmt/tools/qvm_unpause.py | 49 ++++++++++++++ 6 files changed, 465 insertions(+) create mode 100644 qubesmgmt/tools/qubes_prefs.py create mode 100644 qubesmgmt/tools/qvm_kill.py create mode 100644 qubesmgmt/tools/qvm_pause.py create mode 100644 qubesmgmt/tools/qvm_prefs.py create mode 100644 qubesmgmt/tools/qvm_shutdown.py create mode 100644 qubesmgmt/tools/qvm_unpause.py diff --git a/qubesmgmt/tools/qubes_prefs.py b/qubesmgmt/tools/qubes_prefs.py new file mode 100644 index 0000000..1146dee --- /dev/null +++ b/qubesmgmt/tools/qubes_prefs.py @@ -0,0 +1,115 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010-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. +# + +''' Manipulate global properties.''' + +# TODO merge printing with qvm-prefs +# TODO list only non-default properties + +from __future__ import print_function + +import argparse +import sys + +import qubesmgmt +import qubesmgmt.tools +import qubesmgmt.utils + + +parser = qubesmgmt.tools.QubesArgumentParser() + +# keep it here for compatibility with earlier and possibly future versions +parser.add_argument('--force-root', + action='store_true', help=argparse.SUPPRESS) + +# parser.add_argument('--help-properties', +# action=qubesmgmt.tools.HelpPropertiesAction) + +parser.add_argument('--get', '-g', + action='store_true', + help='Ignored; for compatibility with older scripts.') + +parser.add_argument('--set', '-s', + action='store_true', + help='Ignored; for compatibility with older scripts.') + +parser.add_argument('property', metavar='PROPERTY', + nargs='?', + help='name of the property to show or change') + +parser_value = parser.add_mutually_exclusive_group() + +parser_value.add_argument('value', metavar='VALUE', + nargs='?', + help='new value of the property') + +parser.add_argument('--unset', '--default', '--delete', '-D', + dest='delete', + action='store_true', + help='unset the property; if property has default value, it will be used' + ' instead') + + +def main(args=None): # pylint: disable=missing-docstring + args = parser.parse_args(args) + + if args.property is None: + properties = args.app.property_list() + width = max(len(prop.__name__) for prop in properties) + + for prop in sorted(properties): + try: + value = getattr(args.app, prop.__name__) + except AttributeError: + print('{name:{width}s} U'.format( + name=prop.__name__, width=width)) + continue + + if args.app.property_is_default(prop): + print('{name:{width}s} D {value!s}'.format( + name=prop.__name__, width=width, value=value)) + else: + print('{name:{width}s} - {value!s}'.format( + name=prop.__name__, width=width, value=value)) + + return 0 + else: + args.property = args.property.replace('-', '_') + + + if args.value is not None: + setattr(args.app, args.property, args.value) + args.app.save() + return 0 + + if args.delete: + delattr(args.app, args.property) + args.app.save() + return 0 + + + print(str(getattr(args.app, args.property))) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/qubesmgmt/tools/qvm_kill.py b/qubesmgmt/tools/qvm_kill.py new file mode 100644 index 0000000..6711879 --- /dev/null +++ b/qubesmgmt/tools/qvm_kill.py @@ -0,0 +1,55 @@ +# encoding=utf-8 +# +# 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-kill - forceful shutdown''' + + +import sys +import qubesmgmt.exc +import qubesmgmt.tools + +parser = qubesmgmt.tools.QubesArgumentParser( + description='forceful shutdown of a domain', vmname_nargs='+') + + +def main(args=None): + '''Main routine of :program:`qvm-kill`. + + :param list args: Optional arguments to override those delivered from \ + command line. + ''' + + args = parser.parse_args(args) + + exit_code = 0 + for domain in args.domains: + try: + domain.force_shutdown() + except (IOError, OSError, qubesmgmt.exc.QubesException) as e: + exit_code = 1 + parser.print_error(str(e)) + + return exit_code + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/qubesmgmt/tools/qvm_pause.py b/qubesmgmt/tools/qvm_pause.py new file mode 100644 index 0000000..74734ba --- /dev/null +++ b/qubesmgmt/tools/qvm_pause.py @@ -0,0 +1,48 @@ +# encoding=utf-8 +# +# The Qubes OS Project, https://www.qubes-os.org/ +# +# Copyright (C) 2010-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-pause - Pause a domain''' + +import sys +import qubesmgmt + + +parser = qubesmgmt.tools.QubesArgumentParser(vmname_nargs='+', + description='pause a domain') + + +def main(args=None): + '''Main routine of :program:`qvm-pause`. + + :param list args: Optional arguments to override those delivered from \ + command line. + ''' + + args = parser.parse_args(args) + for domain in args.domains: + domain.pause() + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/qubesmgmt/tools/qvm_prefs.py b/qubesmgmt/tools/qvm_prefs.py new file mode 100644 index 0000000..31235d2 --- /dev/null +++ b/qubesmgmt/tools/qvm_prefs.py @@ -0,0 +1,116 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010-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. +# + +''' Manipulate VM properties.''' +# TODO list properties for all classes +# TODO list only non-default properties + +from __future__ import print_function + +import sys + +import qubesmgmt +import qubesmgmt.tools +import qubesmgmt.utils +import qubesmgmt.vm + + +parser = qubesmgmt.tools.QubesArgumentParser( + want_force_root=True, + vmname_nargs=1) + +# parser.add_argument('--help-properties', +# action=qubesmgmt.tools.HelpPropertiesAction, +# klass=qubesmgmt.vm.QubesVM) + +parser.add_argument('--get', '-g', + action='store_true', + help='Ignored; for compatibility with older scripts.') + +parser.add_argument('--set', '-s', + action='store_true', + help='Ignored; for compatibility with older scripts.') + +parser.add_argument('property', metavar='PROPERTY', + nargs='?', + help='name of the property to show or change') + +parser_value = parser.add_mutually_exclusive_group() + +parser_value.add_argument('value', metavar='VALUE', + nargs='?', + help='new value of the property') + +parser.add_argument('--unset', '--default', '--delete', '-D', + dest='delete', + action='store_true', + help='unset the property; if property has default value, it will be used' + ' instead') + + +def main(args=None): # pylint: disable=missing-docstring + args = parser.parse_args(args) + args.domain = args.domains.pop() + + if args.property is None: + properties = args.domain.property_list() + width = max(len(prop.__name__) for prop in properties) + + for prop in sorted(properties): + try: + value = getattr(args.domain, prop.__name__) + except AttributeError: + print('{name:{width}s} U'.format( + name=prop.__name__, width=width)) + continue + + if args.domain.property_is_default(prop): + print('{name:{width}s} D {value!s}'.format( + name=prop.__name__, width=width, value=value)) + else: + print('{name:{width}s} - {value!s}'.format( + name=prop.__name__, width=width, value=value)) + + return 0 + else: + args.property = args.property.replace('-', '_') + + if args.property not in [prop.__name__ + for prop in args.domain.property_list()]: + parser.error('no such property: {!r}'.format(args.property)) + + if args.value is not None: + setattr(args.domain, args.property, args.value) + args.app.save() + return 0 + + if args.delete: + delattr(args.domain, args.property) + args.app.save() + return 0 + + print(str(getattr(args.domain, args.property))) + + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/qubesmgmt/tools/qvm_shutdown.py b/qubesmgmt/tools/qvm_shutdown.py new file mode 100644 index 0000000..5c71caa --- /dev/null +++ b/qubesmgmt/tools/qvm_shutdown.py @@ -0,0 +1,82 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2010-2016 Joanna Rutkowska +# Copyright (C) 2011-2016 Marek Marczykowski-Górecki +# +# Copyright (C) 2016 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. +# + +''' Shutdown a qube ''' + +from __future__ import print_function + +import sys +import time + +import qubesmgmt.tools + +parser = qubesmgmt.tools.QubesArgumentParser( + description=__doc__, vmname_nargs='+') + +parser.add_argument('--force', + action='store_true', default=False, + help='force operation, even if may damage other VMs (eg. shutdown of' + ' network provider)') + +parser.add_argument('--wait', + action='store_true', default=False, + help='wait for the VMs to shut down') + +parser.add_argument('--timeout', + action='store', type=float, + default=60, + help='timeout after which domains are killed when using --wait' + ' (default: %d)') + + +def main(args=None): # pylint: disable=missing-docstring + args = parser.parse_args(args) + + for vm in args.domains: + if not vm.is_halted(): + vm.shutdown(force=args.force) + + if not args.wait: + return + + timeout = args.timeout + current_vms = list(sorted(args.domains)) + while timeout >= 0: + current_vms = [vm for vm in current_vms + if vm.get_power_state() != 'Halted'] + if not current_vms: + return 0 + args.app.log.info('Waiting for shutdown ({}): {}'.format( + timeout, ', '.join([str(vm) for vm in current_vms]))) + time.sleep(1) + timeout -= 1 + + args.app.log.info( + 'Killing remaining qubes: {}' + .format(', '.join([str(vm) for vm in current_vms]))) + for vm in current_vms: + vm.kill() + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/qubesmgmt/tools/qvm_unpause.py b/qubesmgmt/tools/qvm_unpause.py new file mode 100644 index 0000000..adc71a5 --- /dev/null +++ b/qubesmgmt/tools/qvm_unpause.py @@ -0,0 +1,49 @@ +# encoding=utf-8 +# +# The Qubes OS Project, https://www.qubes-os.org/ +# +# Copyright (C) 2010-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-unpause - Unpause a domain''' + +import sys +import qubesmgmt + + +parser = qubesmgmt.tools.QubesArgumentParser( + vmname_nargs='+', + description='unpause a domain') + + +def main(args=None): + '''Main routine of :program:`qvm-unpause`. + + :param list args: Optional arguments to override those delivered from \ + command line. + ''' + + args = parser.parse_args(args) + for domain in args.domains: + domain.unpause() + + return 0 + + +if __name__ == '__main__': + sys.exit(main())