2021-06-03 02:37:04 +02:00
|
|
|
"""
|
|
|
|
QEMU Object Model testing tools.
|
|
|
|
|
2021-06-03 02:37:19 +02:00
|
|
|
usage: qom [-h] {set,get,list,tree,fuse} ...
|
2021-06-03 02:37:04 +02:00
|
|
|
|
|
|
|
Query and manipulate QOM data
|
|
|
|
|
|
|
|
optional arguments:
|
|
|
|
-h, --help show this help message and exit
|
|
|
|
|
|
|
|
QOM commands:
|
2021-06-03 02:37:19 +02:00
|
|
|
{set,get,list,tree,fuse}
|
2021-06-03 02:37:04 +02:00
|
|
|
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
|
2021-06-03 02:37:19 +02:00
|
|
|
fuse Mount a QOM tree as a FUSE filesystem
|
2021-06-03 02:37:04 +02:00
|
|
|
"""
|
|
|
|
##
|
|
|
|
# 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
|
|
|
|
|
2022-03-30 19:28:10 +02:00
|
|
|
from qemu.qmp import ExecuteError
|
2022-01-11 00:28:52 +01:00
|
|
|
|
2021-06-03 02:37:04 +02:00
|
|
|
from .qom_common import QOMCommand
|
|
|
|
|
|
|
|
|
2021-06-03 02:37:19 +02:00
|
|
|
try:
|
|
|
|
from .qom_fuse import QOMFuse
|
2021-06-29 23:43:09 +02:00
|
|
|
except ModuleNotFoundError as _err:
|
|
|
|
if _err.name != 'fuse':
|
2021-06-03 02:37:19 +02:00
|
|
|
raise
|
|
|
|
else:
|
|
|
|
assert issubclass(QOMFuse, QOMCommand)
|
|
|
|
|
|
|
|
|
2021-06-03 02:37:04 +02:00
|
|
|
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})")
|
2022-01-11 00:28:52 +01:00
|
|
|
except ExecuteError as err:
|
2021-06-03 02:37:04 +02:00
|
|
|
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)
|