""" 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 # Anthony Liguori # # 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 qemu.qmp import ExecuteError 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] . Set a QOM property value positional arguments: . QOM path and property, separated by a period '.' 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='', 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] . Get a QOM property value positional arguments: . 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 .') 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] List QOM properties at a given path positional arguments: 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='', 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] [] Show QOM tree from a given path positional arguments: 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='', 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 ExecuteError as err: print(f" {item.name}: ({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)