qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qom.py (7580B)


      1 """
      2 QEMU Object Model testing tools.
      3 
      4 usage: qom [-h] {set,get,list,tree,fuse} ...
      5 
      6 Query and manipulate QOM data
      7 
      8 optional arguments:
      9   -h, --help           show this help message and exit
     10 
     11 QOM commands:
     12   {set,get,list,tree,fuse}
     13     set                Set a QOM property value
     14     get                Get a QOM property value
     15     list               List QOM properties at a given path
     16     tree               Show QOM tree from a given path
     17     fuse               Mount a QOM tree as a FUSE filesystem
     18 """
     19 ##
     20 # Copyright John Snow 2020, for Red Hat, Inc.
     21 # Copyright IBM, Corp. 2011
     22 #
     23 # Authors:
     24 #  John Snow <jsnow@redhat.com>
     25 #  Anthony Liguori <aliguori@amazon.com>
     26 #
     27 # This work is licensed under the terms of the GNU GPL, version 2 or later.
     28 # See the COPYING file in the top-level directory.
     29 #
     30 # Based on ./scripts/qmp/qom-[set|get|tree|list]
     31 ##
     32 
     33 import argparse
     34 
     35 from qemu.qmp import ExecuteError
     36 
     37 from .qom_common import QOMCommand
     38 
     39 
     40 try:
     41     from .qom_fuse import QOMFuse
     42 except ModuleNotFoundError as _err:
     43     if _err.name != 'fuse':
     44         raise
     45 else:
     46     assert issubclass(QOMFuse, QOMCommand)
     47 
     48 
     49 class QOMSet(QOMCommand):
     50     """
     51     QOM Command - Set a property to a given value.
     52 
     53     usage: qom-set [-h] [--socket SOCKET] <path>.<property> <value>
     54 
     55     Set a QOM property value
     56 
     57     positional arguments:
     58       <path>.<property>     QOM path and property, separated by a period '.'
     59       <value>               new QOM property value
     60 
     61     optional arguments:
     62       -h, --help            show this help message and exit
     63       --socket SOCKET, -s SOCKET
     64                             QMP socket path or address (addr:port). May also be
     65                             set via QMP_SOCKET environment variable.
     66     """
     67     name = 'set'
     68     help = 'Set a QOM property value'
     69 
     70     @classmethod
     71     def configure_parser(cls, parser: argparse.ArgumentParser) -> None:
     72         super().configure_parser(parser)
     73         cls.add_path_prop_arg(parser)
     74         parser.add_argument(
     75             'value',
     76             metavar='<value>',
     77             action='store',
     78             help='new QOM property value'
     79         )
     80 
     81     def __init__(self, args: argparse.Namespace):
     82         super().__init__(args)
     83         self.path, self.prop = args.path_prop.rsplit('.', 1)
     84         self.value = args.value
     85 
     86     def run(self) -> int:
     87         rsp = self.qmp.command(
     88             'qom-set',
     89             path=self.path,
     90             property=self.prop,
     91             value=self.value
     92         )
     93         print(rsp)
     94         return 0
     95 
     96 
     97 class QOMGet(QOMCommand):
     98     """
     99     QOM Command - Get a property's current value.
    100 
    101     usage: qom-get [-h] [--socket SOCKET] <path>.<property>
    102 
    103     Get a QOM property value
    104 
    105     positional arguments:
    106       <path>.<property>     QOM path and property, separated by a period '.'
    107 
    108     optional arguments:
    109       -h, --help            show this help message and exit
    110       --socket SOCKET, -s SOCKET
    111                             QMP socket path or address (addr:port). May also be
    112                             set via QMP_SOCKET environment variable.
    113     """
    114     name = 'get'
    115     help = 'Get a QOM property value'
    116 
    117     @classmethod
    118     def configure_parser(cls, parser: argparse.ArgumentParser) -> None:
    119         super().configure_parser(parser)
    120         cls.add_path_prop_arg(parser)
    121 
    122     def __init__(self, args: argparse.Namespace):
    123         super().__init__(args)
    124         try:
    125             tmp = args.path_prop.rsplit('.', 1)
    126         except ValueError as err:
    127             raise ValueError('Invalid format for <path>.<property>') from err
    128         self.path = tmp[0]
    129         self.prop = tmp[1]
    130 
    131     def run(self) -> int:
    132         rsp = self.qmp.command(
    133             'qom-get',
    134             path=self.path,
    135             property=self.prop
    136         )
    137         if isinstance(rsp, dict):
    138             for key, value in rsp.items():
    139                 print(f"{key}: {value}")
    140         else:
    141             print(rsp)
    142         return 0
    143 
    144 
    145 class QOMList(QOMCommand):
    146     """
    147     QOM Command - List the properties at a given path.
    148 
    149     usage: qom-list [-h] [--socket SOCKET] <path>
    150 
    151     List QOM properties at a given path
    152 
    153     positional arguments:
    154       <path>                QOM path
    155 
    156     optional arguments:
    157       -h, --help            show this help message and exit
    158       --socket SOCKET, -s SOCKET
    159                             QMP socket path or address (addr:port). May also be
    160                             set via QMP_SOCKET environment variable.
    161     """
    162     name = 'list'
    163     help = 'List QOM properties at a given path'
    164 
    165     @classmethod
    166     def configure_parser(cls, parser: argparse.ArgumentParser) -> None:
    167         super().configure_parser(parser)
    168         parser.add_argument(
    169             'path',
    170             metavar='<path>',
    171             action='store',
    172             help='QOM path',
    173         )
    174 
    175     def __init__(self, args: argparse.Namespace):
    176         super().__init__(args)
    177         self.path = args.path
    178 
    179     def run(self) -> int:
    180         rsp = self.qom_list(self.path)
    181         for item in rsp:
    182             if item.child:
    183                 print(f"{item.name}/")
    184             elif item.link:
    185                 print(f"@{item.name}/")
    186             else:
    187                 print(item.name)
    188         return 0
    189 
    190 
    191 class QOMTree(QOMCommand):
    192     """
    193     QOM Command - Show the full tree below a given path.
    194 
    195     usage: qom-tree [-h] [--socket SOCKET] [<path>]
    196 
    197     Show QOM tree from a given path
    198 
    199     positional arguments:
    200       <path>                QOM path
    201 
    202     optional arguments:
    203       -h, --help            show this help message and exit
    204       --socket SOCKET, -s SOCKET
    205                             QMP socket path or address (addr:port). May also be
    206                             set via QMP_SOCKET environment variable.
    207     """
    208     name = 'tree'
    209     help = 'Show QOM tree from a given path'
    210 
    211     @classmethod
    212     def configure_parser(cls, parser: argparse.ArgumentParser) -> None:
    213         super().configure_parser(parser)
    214         parser.add_argument(
    215             'path',
    216             metavar='<path>',
    217             action='store',
    218             help='QOM path',
    219             nargs='?',
    220             default='/'
    221         )
    222 
    223     def __init__(self, args: argparse.Namespace):
    224         super().__init__(args)
    225         self.path = args.path
    226 
    227     def _list_node(self, path: str) -> None:
    228         print(path)
    229         items = self.qom_list(path)
    230         for item in items:
    231             if item.child:
    232                 continue
    233             try:
    234                 rsp = self.qmp.command('qom-get', path=path,
    235                                        property=item.name)
    236                 print(f"  {item.name}: {rsp} ({item.type})")
    237             except ExecuteError as err:
    238                 print(f"  {item.name}: <EXCEPTION: {err!s}> ({item.type})")
    239         print('')
    240         for item in items:
    241             if not item.child:
    242                 continue
    243             if path == '/':
    244                 path = ''
    245             self._list_node(f"{path}/{item.name}")
    246 
    247     def run(self) -> int:
    248         self._list_node(self.path)
    249         return 0
    250 
    251 
    252 def main() -> int:
    253     """QOM script main entry point."""
    254     parser = argparse.ArgumentParser(
    255         description='Query and manipulate QOM data'
    256     )
    257     subparsers = parser.add_subparsers(
    258         title='QOM commands',
    259         dest='command'
    260     )
    261 
    262     for command in QOMCommand.__subclasses__():
    263         command.register(subparsers)
    264 
    265     args = parser.parse_args()
    266 
    267     if args.command is None:
    268         parser.error('Command not specified.')
    269         return 1
    270 
    271     cmd_class = args.cmd_class
    272     assert isinstance(cmd_class, type(QOMCommand))
    273     return cmd_class.command_runner(args)