diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2021-06-21 16:11:33 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2021-06-21 16:11:33 +0100 |
| commit | 0add99ea3ea91af8230e3933ad7826b2da25a44d (patch) | |
| tree | 8ee70c67b5e9024eebe8ee0d592c0f6c9f926e62 /python/qemu/qmp/qom.py | |
| parent | 53f306f316549d20c76886903181413d20842423 (diff) | |
| parent | d08caefe6648fc0713af5361e2b88bee53b67ebb (diff) | |
| download | focaccia-qemu-0add99ea3ea91af8230e3933ad7826b2da25a44d.tar.gz focaccia-qemu-0add99ea3ea91af8230e3933ad7826b2da25a44d.zip | |
Merge remote-tracking branch 'remotes/jsnow-gitlab/tags/python-pull-request' into staging
Python Pull request Moves QMP-related tools not used for build or automatic testing from scripts/ to python/qemu/qmp/ where they will be protected from bitrot by the check-python-* CI jobs. stub forwarders are left in the old locations for now. # gpg: Signature made Sat 19 Jun 2021 00:02:40 BST # gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full] # Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB # Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E * remotes/jsnow-gitlab/tags/python-pull-request: (72 commits) scripts/qmp-shell: add redirection shim python: add qmp-shell entry point scripts/qmp-shell: move to python/qemu/qmp/qmp_shell.py scripts/qmp-shell: add docstrings scripts/qmp-shell: make QMPShellError inherit QMPError scripts/qmp-shell: remove double-underscores scripts/qmp-shell: convert usage comment to docstring scripts/qmp-shell: Remove too-broad-exception scripts/qmp-shell: Fix empty-transaction invocation scripts/qmp-shell: remove TODO scripts/qmp-shell: use logging to show warnings scripts/qmp-shell: Use context manager instead of atexit python/qmp: return generic type from context manager scripts/qmp-shell: unprivatize 'pretty' property scripts/qmp-shell: Accept SocketAddrT instead of string scripts/qmp-shell: add mypy types python/qmp: add QMPObject type alias scripts/qmp-shell: initialize completer early scripts/qmp-shell: refactor QMPCompleter scripts/qmp-shell: Fix "FuzzyJSON" parser ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'python/qemu/qmp/qom.py')
| -rw-r--r-- | python/qemu/qmp/qom.py | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/python/qemu/qmp/qom.py b/python/qemu/qmp/qom.py new file mode 100644 index 0000000000..7ec7843d57 --- /dev/null +++ b/python/qemu/qmp/qom.py @@ -0,0 +1,272 @@ +""" +QEMU Object Model testing tools. + +usage: qom [-h] {set,get,list,tree,fuse} ... + +Query and manipulate QOM data + +optional arguments: + -h, --help show this help message and exit + +QOM commands: + {set,get,list,tree,fuse} + set Set a QOM property value + get Get a QOM property value + list List QOM properties at a given path + tree Show QOM tree from a given path + fuse Mount a QOM tree as a FUSE filesystem +""" +## +# Copyright John Snow 2020, for Red Hat, Inc. +# Copyright IBM, Corp. 2011 +# +# Authors: +# John Snow <jsnow@redhat.com> +# Anthony Liguori <aliguori@amazon.com> +# +# This work is licensed under the terms of the GNU GPL, version 2 or later. +# See the COPYING file in the top-level directory. +# +# Based on ./scripts/qmp/qom-[set|get|tree|list] +## + +import argparse + +from . import QMPResponseError +from .qom_common import QOMCommand + + +try: + from .qom_fuse import QOMFuse +except ModuleNotFoundError as err: + if err.name != 'fuse': + raise +else: + assert issubclass(QOMFuse, QOMCommand) + + +class QOMSet(QOMCommand): + """ + QOM Command - Set a property to a given value. + + usage: qom-set [-h] [--socket SOCKET] <path>.<property> <value> + + Set a QOM property value + + positional arguments: + <path>.<property> QOM path and property, separated by a period '.' + <value> new QOM property value + + optional arguments: + -h, --help show this help message and exit + --socket SOCKET, -s SOCKET + QMP socket path or address (addr:port). May also be + set via QMP_SOCKET environment variable. + """ + name = 'set' + help = 'Set a QOM property value' + + @classmethod + def configure_parser(cls, parser: argparse.ArgumentParser) -> None: + super().configure_parser(parser) + cls.add_path_prop_arg(parser) + parser.add_argument( + 'value', + metavar='<value>', + action='store', + help='new QOM property value' + ) + + def __init__(self, args: argparse.Namespace): + super().__init__(args) + self.path, self.prop = args.path_prop.rsplit('.', 1) + self.value = args.value + + def run(self) -> int: + rsp = self.qmp.command( + 'qom-set', + path=self.path, + property=self.prop, + value=self.value + ) + print(rsp) + return 0 + + +class QOMGet(QOMCommand): + """ + QOM Command - Get a property's current value. + + usage: qom-get [-h] [--socket SOCKET] <path>.<property> + + Get a QOM property value + + positional arguments: + <path>.<property> QOM path and property, separated by a period '.' + + optional arguments: + -h, --help show this help message and exit + --socket SOCKET, -s SOCKET + QMP socket path or address (addr:port). May also be + set via QMP_SOCKET environment variable. + """ + name = 'get' + help = 'Get a QOM property value' + + @classmethod + def configure_parser(cls, parser: argparse.ArgumentParser) -> None: + super().configure_parser(parser) + cls.add_path_prop_arg(parser) + + def __init__(self, args: argparse.Namespace): + super().__init__(args) + try: + tmp = args.path_prop.rsplit('.', 1) + except ValueError as err: + raise ValueError('Invalid format for <path>.<property>') from err + self.path = tmp[0] + self.prop = tmp[1] + + def run(self) -> int: + rsp = self.qmp.command( + 'qom-get', + path=self.path, + property=self.prop + ) + if isinstance(rsp, dict): + for key, value in rsp.items(): + print(f"{key}: {value}") + else: + print(rsp) + return 0 + + +class QOMList(QOMCommand): + """ + QOM Command - List the properties at a given path. + + usage: qom-list [-h] [--socket SOCKET] <path> + + List QOM properties at a given path + + positional arguments: + <path> QOM path + + optional arguments: + -h, --help show this help message and exit + --socket SOCKET, -s SOCKET + QMP socket path or address (addr:port). May also be + set via QMP_SOCKET environment variable. + """ + name = 'list' + help = 'List QOM properties at a given path' + + @classmethod + def configure_parser(cls, parser: argparse.ArgumentParser) -> None: + super().configure_parser(parser) + parser.add_argument( + 'path', + metavar='<path>', + action='store', + help='QOM path', + ) + + def __init__(self, args: argparse.Namespace): + super().__init__(args) + self.path = args.path + + def run(self) -> int: + rsp = self.qom_list(self.path) + for item in rsp: + if item.child: + print(f"{item.name}/") + elif item.link: + print(f"@{item.name}/") + else: + print(item.name) + return 0 + + +class QOMTree(QOMCommand): + """ + QOM Command - Show the full tree below a given path. + + usage: qom-tree [-h] [--socket SOCKET] [<path>] + + Show QOM tree from a given path + + positional arguments: + <path> QOM path + + optional arguments: + -h, --help show this help message and exit + --socket SOCKET, -s SOCKET + QMP socket path or address (addr:port). May also be + set via QMP_SOCKET environment variable. + """ + name = 'tree' + help = 'Show QOM tree from a given path' + + @classmethod + def configure_parser(cls, parser: argparse.ArgumentParser) -> None: + super().configure_parser(parser) + parser.add_argument( + 'path', + metavar='<path>', + action='store', + help='QOM path', + nargs='?', + default='/' + ) + + def __init__(self, args: argparse.Namespace): + super().__init__(args) + self.path = args.path + + def _list_node(self, path: str) -> None: + print(path) + items = self.qom_list(path) + for item in items: + if item.child: + continue + try: + rsp = self.qmp.command('qom-get', path=path, + property=item.name) + print(f" {item.name}: {rsp} ({item.type})") + except QMPResponseError as err: + print(f" {item.name}: <EXCEPTION: {err!s}> ({item.type})") + print('') + for item in items: + if not item.child: + continue + if path == '/': + path = '' + self._list_node(f"{path}/{item.name}") + + def run(self) -> int: + self._list_node(self.path) + return 0 + + +def main() -> int: + """QOM script main entry point.""" + parser = argparse.ArgumentParser( + description='Query and manipulate QOM data' + ) + subparsers = parser.add_subparsers( + title='QOM commands', + dest='command' + ) + + for command in QOMCommand.__subclasses__(): + command.register(subparsers) + + args = parser.parse_args() + + if args.command is None: + parser.error('Command not specified.') + return 1 + + cmd_class = args.cmd_class + assert isinstance(cmd_class, type(QOMCommand)) + return cmd_class.command_runner(args) |