Python patches

A few fixes to the Python CI tests, a few fixes to the (async) QMP
 library, and a set of patches that begin to shift us towards using the
 new qmp lib.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAmHrSt4ACgkQfe+BBqr8
 OQ4BLg/5AdhcWsAtKq+xZj/nz2DNAbvXmrGJRuVln1yofrj22w2MYUTGfpQ0m8JO
 Ezu+LYtSTPQAaQw54WByaliD5h2ucYl5W8H13cDc8NPZkbsX+dD7G99u4XkSIY4I
 sSCYDMKi4j/P+4YR2MN1Iol4362fWbi3O3rsRX6PqNymIAaaklDrH3QZCGMiBMjl
 2OAcgba31uguyXnMuM3WY8XAnnRsib3wZ/a+a3WWcEsEm1HAUC0pb8VmrRzH5Rv9
 CpR3EBYoVc3of96jd/qLjucnoUL0+K2RVN2qPeie3+o7yEM2VYj5o+cG2H8pEG5p
 Fk/J7kqs0XWBOeX3A3IlGqKEXFPGDjEJZpcjwd8+IhgA2Y/MByTqRr1EvrOSO+bg
 q3njEg5DsORQS/xgZrnAidk5fdgLj7Cv39LfsxMnv77RBnlLubEAet7pT1XtprAv
 DI7STKknVpPu0VtYI8ALVjVhpeCkIt95DXACMtPZiSJ5X1NdoY5qubV1y8/vsExI
 RMDMepcS2A75Un2DA1bkStHTPN2PSUfM15fmUCebxbHp53FlJCh44gxAAsfj9j41
 xUmwSz1c81bCU4m+jsMBdNrbtkpPz/gX/3ZS8KqGoZmWN0wDkh3vEYFj5Y/310HY
 xmzug6o+tR7OD3bBGxZ73k9rn86X3+1PsYxOZjvYM0wiJIisPk4=
 =D2kj
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/jsnow-gitlab/tags/python-pull-request' into staging

Python patches

A few fixes to the Python CI tests, a few fixes to the (async) QMP
library, and a set of patches that begin to shift us towards using the
new qmp lib.

# gpg: Signature made Sat 22 Jan 2022 00:07:58 GMT
# 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:
  scripts/render-block-graph: switch to AQMP
  scripts/cpu-x86-uarch-abi: switch to AQMP
  scripts/cpu-x86-uarch-abi: fix CLI parsing
  python: move qmp-shell under the AQMP package
  python: move qmp utilities to python/qemu/utils
  python/qmp: switch qmp-shell to AQMP
  python/qmp: switch qom tools to AQMP
  python/qmp: switch qemu-ga-client to AQMP
  python/qemu-ga-client: don't use deprecated CLI syntax in usage comment
  python/aqmp: rename AQMPError to QMPError
  python/aqmp: add SocketAddrT to package root
  python/aqmp: copy type definitions from qmp
  python/aqmp: handle asyncio.TimeoutError on execute()
  python/aqmp: add __del__ method to legacy interface
  python/aqmp: fix docstring typo
  python: use avocado's "new" runner
  python: pin setuptools below v60.0.0

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-01-22 12:03:22 +00:00
commit aeb0ae95b7
24 changed files with 151 additions and 90 deletions

View File

@ -68,6 +68,8 @@ $(QEMU_VENV_DIR) $(QEMU_VENV_DIR)/bin/activate: setup.cfg
echo "ACTIVATE $(QEMU_VENV_DIR)"; \
. $(QEMU_VENV_DIR)/bin/activate; \
echo "INSTALL qemu[devel] $(QEMU_VENV_DIR)"; \
pip install --disable-pip-version-check \
"setuptools<60.0.0" 1>/dev/null; \
make develop 1>/dev/null; \
)
@touch $(QEMU_VENV_DIR)

View File

@ -59,7 +59,7 @@ Package installation also normally provides executable console scripts,
so that tools like ``qmp-shell`` are always available via $PATH. To
invoke them without installation, you can invoke e.g.:
``> PYTHONPATH=~/src/qemu/python python3 -m qemu.qmp.qmp_shell``
``> PYTHONPATH=~/src/qemu/python python3 -m qemu.aqmp.qmp_shell``
The mappings between console script name and python module path can be
found in ``setup.cfg``.

View File

@ -1,5 +1,5 @@
[run]
test_runner = runner
test_runner = nrunner
[simpletests]
# Don't show stdout/stderr in the test *summary*

View File

@ -6,7 +6,7 @@ asynchronously with QMP protocol servers, as implemented by QEMU, the
QEMU Guest Agent, and the QEMU Storage Daemon.
`QMPClient` provides the main functionality of this package. All errors
raised by this library dervive from `AQMPError`, see `aqmp.error` for
raised by this library derive from `QMPError`, see `aqmp.error` for
additional detail. See `aqmp.events` for an in-depth tutorial on
managing QMP events.
"""
@ -23,10 +23,15 @@ managing QMP events.
import logging
from .error import AQMPError
from .error import QMPError
from .events import EventListener
from .message import Message
from .protocol import ConnectError, Runstate, StateError
from .protocol import (
ConnectError,
Runstate,
SocketAddrT,
StateError,
)
from .qmp_client import ExecInterruptedError, ExecuteError, QMPClient
@ -43,9 +48,12 @@ __all__ = (
'Runstate',
# Exceptions, most generic to most explicit
'AQMPError',
'QMPError',
'StateError',
'ConnectError',
'ExecuteError',
'ExecInterruptedError',
# Type aliases
'SocketAddrT',
)

View File

@ -1,21 +1,21 @@
"""
AQMP Error Classes
QMP Error Classes
This package seeks to provide semantic error classes that are intended
to be used directly by clients when they would like to handle particular
semantic failures (e.g. "failed to connect") without needing to know the
enumeration of possible reasons for that failure.
AQMPError serves as the ancestor for all exceptions raised by this
QMPError serves as the ancestor for all exceptions raised by this
package, and is suitable for use in handling semantic errors from this
library. In most cases, individual public methods will attempt to catch
and re-encapsulate various exceptions to provide a semantic
error-handling interface.
.. admonition:: AQMP Exception Hierarchy Reference
.. admonition:: QMP Exception Hierarchy Reference
| `Exception`
| +-- `AQMPError`
| +-- `QMPError`
| +-- `ConnectError`
| +-- `StateError`
| +-- `ExecInterruptedError`
@ -31,11 +31,11 @@ error-handling interface.
"""
class AQMPError(Exception):
class QMPError(Exception):
"""Abstract error class for all errors originating from this package."""
class ProtocolError(AQMPError):
class ProtocolError(QMPError):
"""
Abstract error class for protocol failures.

View File

@ -443,7 +443,7 @@ from typing import (
Union,
)
from .error import AQMPError
from .error import QMPError
from .message import Message
@ -451,7 +451,7 @@ EventNames = Union[str, Iterable[str], None]
EventFilter = Callable[[Message], bool]
class ListenerError(AQMPError):
class ListenerError(QMPError):
"""
Generic error class for `EventListener`-related problems.
"""

View File

@ -6,7 +6,9 @@ This class pretends to be qemu.qmp.QEMUMonitorProtocol.
import asyncio
from typing import (
Any,
Awaitable,
Dict,
List,
Optional,
TypeVar,
@ -14,11 +16,32 @@ from typing import (
)
import qemu.qmp
from qemu.qmp import QMPMessage, QMPReturnValue, SocketAddrT
from .error import QMPError
from .protocol import Runstate, SocketAddrT
from .qmp_client import QMPClient
# (Temporarily) Re-export QMPBadPortError
QMPBadPortError = qemu.qmp.QMPBadPortError
#: QMPMessage is an entire QMP message of any kind.
QMPMessage = Dict[str, Any]
#: QMPReturnValue is the 'return' value of a command.
QMPReturnValue = object
#: QMPObject is any object in a QMP message.
QMPObject = Dict[str, object]
# QMPMessage can be outgoing commands or incoming events/returns.
# QMPReturnValue is usually a dict/json object, but due to QAPI's
# 'returns-whitelist', it can actually be anything.
#
# {'return': {}} is a QMPMessage,
# {} is the QMPReturnValue.
# pylint: disable=missing-docstring
@ -136,3 +159,19 @@ class QEMUMonitorProtocol(qemu.qmp.QEMUMonitorProtocol):
def send_fd_scm(self, fd: int) -> None:
self._aqmp.send_fd_scm(fd)
def __del__(self) -> None:
if self._aqmp.runstate == Runstate.IDLE:
return
if not self._aloop.is_running():
self.close()
else:
# Garbage collection ran while the event loop was running.
# Nothing we can do about it now, but if we don't raise our
# own error, the user will be treated to a lot of traceback
# they might not understand.
raise QMPError(
"QEMUMonitorProtocol.close()"
" was not called before object was garbage collected"
)

View File

@ -29,7 +29,7 @@ from typing import (
cast,
)
from .error import AQMPError
from .error import QMPError
from .util import (
bottom_half,
create_task,
@ -46,6 +46,10 @@ T = TypeVar('T')
_U = TypeVar('_U')
_TaskFN = Callable[[], Awaitable[None]] # aka ``async def func() -> None``
InternetAddrT = Tuple[str, int]
UnixAddrT = str
SocketAddrT = Union[UnixAddrT, InternetAddrT]
class Runstate(Enum):
"""Protocol session runstate."""
@ -61,7 +65,7 @@ class Runstate(Enum):
DISCONNECTING = 3
class ConnectError(AQMPError):
class ConnectError(QMPError):
"""
Raised when the initial connection process has failed.
@ -86,7 +90,7 @@ class ConnectError(AQMPError):
return f"{self.error_message}: {cause}"
class StateError(AQMPError):
class StateError(QMPError):
"""
An API command (connect, execute, etc) was issued at an inappropriate time.
@ -257,7 +261,7 @@ class AsyncProtocol(Generic[T]):
@upper_half
@require(Runstate.IDLE)
async def accept(self, address: Union[str, Tuple[str, int]],
async def accept(self, address: SocketAddrT,
ssl: Optional[SSLContext] = None) -> None:
"""
Accept a connection and begin processing message queues.
@ -275,7 +279,7 @@ class AsyncProtocol(Generic[T]):
@upper_half
@require(Runstate.IDLE)
async def connect(self, address: Union[str, Tuple[str, int]],
async def connect(self, address: SocketAddrT,
ssl: Optional[SSLContext] = None) -> None:
"""
Connect to the server and begin processing message queues.
@ -337,7 +341,7 @@ class AsyncProtocol(Generic[T]):
@upper_half
async def _new_session(self,
address: Union[str, Tuple[str, int]],
address: SocketAddrT,
ssl: Optional[SSLContext] = None,
accept: bool = False) -> None:
"""
@ -359,7 +363,7 @@ class AsyncProtocol(Generic[T]):
This exception will wrap a more concrete one. In most cases,
the wrapped exception will be `OSError` or `EOFError`. If a
protocol-level failure occurs while establishing a new
session, the wrapped error may also be an `AQMPError`.
session, the wrapped error may also be an `QMPError`.
"""
assert self.runstate == Runstate.IDLE
@ -397,7 +401,7 @@ class AsyncProtocol(Generic[T]):
@upper_half
async def _establish_connection(
self,
address: Union[str, Tuple[str, int]],
address: SocketAddrT,
ssl: Optional[SSLContext] = None,
accept: bool = False
) -> None:
@ -424,7 +428,7 @@ class AsyncProtocol(Generic[T]):
await self._do_connect(address, ssl)
@upper_half
async def _do_accept(self, address: Union[str, Tuple[str, int]],
async def _do_accept(self, address: SocketAddrT,
ssl: Optional[SSLContext] = None) -> None:
"""
Acting as the transport server, accept a single connection.
@ -482,7 +486,7 @@ class AsyncProtocol(Generic[T]):
self.logger.debug("Connection accepted.")
@upper_half
async def _do_connect(self, address: Union[str, Tuple[str, int]],
async def _do_connect(self, address: SocketAddrT,
ssl: Optional[SSLContext] = None) -> None:
"""
Acting as the transport client, initiate a connection to a server.

View File

@ -20,7 +20,7 @@ from typing import (
cast,
)
from .error import AQMPError, ProtocolError
from .error import ProtocolError, QMPError
from .events import Events
from .message import Message
from .models import ErrorResponse, Greeting
@ -66,7 +66,7 @@ class NegotiationError(_WrappedProtocolError):
"""
class ExecuteError(AQMPError):
class ExecuteError(QMPError):
"""
Exception raised by `QMPClient.execute()` on RPC failure.
@ -87,7 +87,7 @@ class ExecuteError(AQMPError):
self.error_class: str = error_response.error.class_
class ExecInterruptedError(AQMPError):
class ExecInterruptedError(QMPError):
"""
Exception raised by `execute()` (et al) when an RPC is interrupted.
@ -435,7 +435,11 @@ class QMPClient(AsyncProtocol[Message], Events):
msg_id = msg['id']
self._pending[msg_id] = asyncio.Queue(maxsize=1)
await self._outgoing.put(msg)
try:
await self._outgoing.put(msg)
except:
del self._pending[msg_id]
raise
return msg_id
@ -452,9 +456,9 @@ class QMPClient(AsyncProtocol[Message], Events):
was lost, or some other problem.
"""
queue = self._pending[msg_id]
result = await queue.get()
try:
result = await queue.get()
if isinstance(result, ExecInterruptedError):
raise result
return result
@ -637,7 +641,7 @@ class QMPClient(AsyncProtocol[Message], Events):
sock = self._writer.transport.get_extra_info('socket')
if sock.family != socket.AF_UNIX:
raise AQMPError("Sending file descriptors requires a UNIX socket.")
raise QMPError("Sending file descriptors requires a UNIX socket.")
if not hasattr(sock, 'sendmsg'):
# We need to void the warranty sticker.

View File

@ -95,8 +95,13 @@ from typing import (
Sequence,
)
from qemu import qmp
from qemu.qmp import QMPMessage
from qemu.aqmp import ConnectError, QMPError, SocketAddrT
from qemu.aqmp.legacy import (
QEMUMonitorProtocol,
QMPBadPortError,
QMPMessage,
QMPObject,
)
LOG = logging.getLogger(__name__)
@ -125,7 +130,7 @@ class QMPCompleter:
return None
class QMPShellError(qmp.QMPError):
class QMPShellError(QMPError):
"""
QMP Shell Base error class.
"""
@ -153,7 +158,7 @@ class FuzzyJSON(ast.NodeTransformer):
return node
class QMPShell(qmp.QEMUMonitorProtocol):
class QMPShell(QEMUMonitorProtocol):
"""
QMPShell provides a basic readline-based QMP shell.
@ -161,7 +166,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
:param pretty: Pretty-print QMP messages.
:param verbose: Echo outgoing QMP messages to console.
"""
def __init__(self, address: qmp.SocketAddrT,
def __init__(self, address: SocketAddrT,
pretty: bool = False, verbose: bool = False):
super().__init__(address)
self._greeting: Optional[QMPMessage] = None
@ -237,7 +242,7 @@ class QMPShell(qmp.QEMUMonitorProtocol):
def _cli_expr(self,
tokens: Sequence[str],
parent: qmp.QMPObject) -> None:
parent: QMPObject) -> None:
for arg in tokens:
(key, sep, val) = arg.partition('=')
if sep != '=':
@ -403,7 +408,7 @@ class HMPShell(QMPShell):
:param pretty: Pretty-print QMP messages.
:param verbose: Echo outgoing QMP messages to console.
"""
def __init__(self, address: qmp.SocketAddrT,
def __init__(self, address: SocketAddrT,
pretty: bool = False, verbose: bool = False):
super().__init__(address, pretty, verbose)
self._cpu_index = 0
@ -512,19 +517,17 @@ def main() -> None:
try:
address = shell_class.parse_address(args.qmp_server)
except qmp.QMPBadPortError:
except QMPBadPortError:
parser.error(f"Bad port number: {args.qmp_server}")
return # pycharm doesn't know error() is noreturn
with shell_class(address, args.pretty, args.verbose) as qemu:
try:
qemu.connect(negotiate=not args.skip_negotiation)
except qmp.QMPConnectError:
die("Didn't get QMP greeting message")
except qmp.QMPCapabilitiesError:
die("Couldn't negotiate capabilities")
except OSError as err:
die(f"Couldn't connect to {args.qmp_server}: {err!s}")
except ConnectError as err:
if isinstance(err.exc, OSError):
die(f"Couldn't connect to {args.qmp_server}: {err!s}")
die(str(err))
for _ in qemu.repl():
pass

View File

@ -5,7 +5,7 @@ Usage:
Start QEMU with:
# qemu [...] -chardev socket,path=/tmp/qga.sock,server,wait=off,id=qga0 \
# qemu [...] -chardev socket,path=/tmp/qga.sock,server=on,wait=off,id=qga0 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
@ -37,8 +37,8 @@ See also: https://wiki.qemu.org/Features/QAPI/GuestAgent
# the COPYING file in the top-level directory.
import argparse
import asyncio
import base64
import errno
import os
import random
import sys
@ -50,8 +50,8 @@ from typing import (
Sequence,
)
from qemu import qmp
from qemu.qmp import SocketAddrT
from qemu.aqmp import ConnectError, SocketAddrT
from qemu.aqmp.legacy import QEMUMonitorProtocol
# This script has not seen many patches or careful attention in quite
@ -61,7 +61,7 @@ from qemu.qmp import SocketAddrT
# pylint: disable=missing-docstring
class QemuGuestAgent(qmp.QEMUMonitorProtocol):
class QemuGuestAgent(QEMUMonitorProtocol):
def __getattr__(self, name: str) -> Callable[..., Any]:
def wrapper(**kwds: object) -> object:
return self.command('guest-' + name.replace('_', '-'), **kwds)
@ -149,7 +149,7 @@ class QemuGuestAgentClient:
self.qga.settimeout(timeout)
try:
self.qga.ping()
except TimeoutError:
except asyncio.TimeoutError:
return False
return True
@ -172,7 +172,7 @@ class QemuGuestAgentClient:
try:
getattr(self.qga, 'suspend' + '_' + mode)()
# On error exception will raise
except TimeoutError:
except asyncio.TimeoutError:
# On success command will timed out
return
@ -182,7 +182,7 @@ class QemuGuestAgentClient:
try:
self.qga.shutdown(mode=mode)
except TimeoutError:
except asyncio.TimeoutError:
pass
@ -277,7 +277,7 @@ commands = [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m]
def send_command(address: str, cmd: str, args: Sequence[str]) -> None:
if not os.path.exists(address):
print('%s not found' % address)
print(f"'{address}' not found. (Is QEMU running?)")
sys.exit(1)
if cmd not in commands:
@ -287,10 +287,10 @@ def send_command(address: str, cmd: str, args: Sequence[str]) -> None:
try:
client = QemuGuestAgentClient(address)
except OSError as err:
except ConnectError as err:
print(err)
if err.errno == errno.ECONNREFUSED:
print('Hint: qemu is not running?')
if isinstance(err.exc, ConnectionError):
print('(Is QEMU running?)')
sys.exit(1)
if cmd == 'fsfreeze' and args[0] == 'freeze':

View File

@ -32,7 +32,8 @@ QOM commands:
import argparse
from . import QMPResponseError
from qemu.aqmp import ExecuteError
from .qom_common import QOMCommand
@ -233,7 +234,7 @@ class QOMTree(QOMCommand):
rsp = self.qmp.command('qom-get', path=path,
property=item.name)
print(f" {item.name}: {rsp} ({item.type})")
except QMPResponseError as err:
except ExecuteError as err:
print(f" {item.name}: <EXCEPTION: {err!s}> ({item.type})")
print('')
for item in items:

View File

@ -27,7 +27,8 @@ from typing import (
TypeVar,
)
from . import QEMUMonitorProtocol, QMPError
from qemu.aqmp import QMPError
from qemu.aqmp.legacy import QEMUMonitorProtocol
class ObjectPropertyInfo:

View File

@ -48,7 +48,8 @@ from typing import (
import fuse
from fuse import FUSE, FuseOSError, Operations
from . import QMPResponseError
from qemu.aqmp import ExecuteError
from .qom_common import QOMCommand
@ -99,7 +100,7 @@ class QOMFuse(QOMCommand, Operations):
try:
self.qom_list(path)
return True
except QMPResponseError:
except ExecuteError:
return False
def is_property(self, path: str) -> bool:
@ -112,7 +113,7 @@ class QOMFuse(QOMCommand, Operations):
if item.name == prop:
return True
return False
except QMPResponseError:
except ExecuteError:
return False
def is_link(self, path: str) -> bool:
@ -125,7 +126,7 @@ class QOMFuse(QOMCommand, Operations):
if item.name == prop and item.link:
return True
return False
except QMPResponseError:
except ExecuteError:
return False
def read(self, path: str, size: int, offset: int, fh: IO[bytes]) -> bytes:
@ -138,7 +139,7 @@ class QOMFuse(QOMCommand, Operations):
try:
data = str(self.qmp.command('qom-get', path=path, property=prop))
data += '\n' # make values shell friendly
except QMPResponseError as err:
except ExecuteError as err:
raise FuseOSError(EPERM) from err
if offset > len(data):

View File

@ -60,14 +60,14 @@ tui =
[options.entry_points]
console_scripts =
qom = qemu.qmp.qom:main
qom-set = qemu.qmp.qom:QOMSet.entry_point
qom-get = qemu.qmp.qom:QOMGet.entry_point
qom-list = qemu.qmp.qom:QOMList.entry_point
qom-tree = qemu.qmp.qom:QOMTree.entry_point
qom-fuse = qemu.qmp.qom_fuse:QOMFuse.entry_point [fuse]
qemu-ga-client = qemu.qmp.qemu_ga_client:main
qmp-shell = qemu.qmp.qmp_shell:main
qom = qemu.utils.qom:main
qom-set = qemu.utils.qom:QOMSet.entry_point
qom-get = qemu.utils.qom:QOMGet.entry_point
qom-list = qemu.utils.qom:QOMList.entry_point
qom-tree = qemu.utils.qom:QOMTree.entry_point
qom-fuse = qemu.utils.qom_fuse:QOMFuse.entry_point [fuse]
qemu-ga-client = qemu.utils.qemu_ga_client:main
qmp-shell = qemu.aqmp.qmp_shell:main
aqmp-tui = qemu.aqmp.aqmp_tui:main [tui]
[flake8]
@ -80,7 +80,7 @@ python_version = 3.6
warn_unused_configs = True
namespace_packages = True
[mypy-qemu.qmp.qom_fuse]
[mypy-qemu.utils.qom_fuse]
# fusepy has no type stubs:
allow_subclassing_any = True
@ -163,6 +163,7 @@ deps =
.[devel]
.[fuse] # Workaround to trigger tox venv rebuild
.[tui] # Workaround to trigger tox venv rebuild
setuptools < 60 # Workaround, please see commit msg.
commands =
make check

View File

@ -6,10 +6,10 @@
# compatibility levels for each CPU model.
#
from qemu import qmp
from qemu.aqmp.legacy import QEMUMonitorProtocol
import sys
if len(sys.argv) != 1:
if len(sys.argv) != 2:
print("syntax: %s QMP-SOCK\n\n" % __file__ +
"Where QMP-SOCK points to a QEMU process such as\n\n" +
" # qemu-system-x86_64 -qmp unix:/tmp/qmp,server,nowait " +
@ -66,8 +66,7 @@ levels = [
sock = sys.argv[1]
cmd = sys.argv[2]
shell = qmp.QEMUMonitorProtocol(sock)
shell = QEMUMonitorProtocol(sock)
shell.connect()
models = shell.cmd("query-cpu-definitions")

View File

@ -4,7 +4,7 @@ import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu.qmp import qemu_ga_client
from qemu.utils import qemu_ga_client
if __name__ == '__main__':

View File

@ -4,7 +4,7 @@ import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu.qmp import qmp_shell
from qemu.aqmp import qmp_shell
if __name__ == '__main__':

View File

@ -4,7 +4,7 @@ import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu.qmp.qom_fuse import QOMFuse
from qemu.utils.qom_fuse import QOMFuse
if __name__ == '__main__':

View File

@ -4,7 +4,7 @@ import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu.qmp.qom import QOMGet
from qemu.utils.qom import QOMGet
if __name__ == '__main__':

View File

@ -4,7 +4,7 @@ import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu.qmp.qom import QOMList
from qemu.utils.qom import QOMList
if __name__ == '__main__':

View File

@ -4,7 +4,7 @@ import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu.qmp.qom import QOMSet
from qemu.utils.qom import QOMSet
if __name__ == '__main__':

View File

@ -4,7 +4,7 @@ import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
from qemu.qmp.qom import QOMTree
from qemu.utils.qom import QOMTree
if __name__ == '__main__':

View File

@ -25,10 +25,8 @@ import json
from graphviz import Digraph
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'python'))
from qemu.qmp import (
QEMUMonitorProtocol,
QMPResponseError,
)
from qemu.aqmp import QMPError
from qemu.aqmp.legacy import QEMUMonitorProtocol
def perm(arr):
@ -104,7 +102,7 @@ class LibvirtGuest():
reply = json.loads(subprocess.check_output(ar))
if 'error' in reply:
raise QMPResponseError(reply)
raise QMPError(reply)
return reply['return']