QMP Protocol

QMP Protocol Implementation

This module provides the QMPClient class, which can be used to connect and send commands to a QMP server such as QEMU. The QMP class can be used to either connect to a listening server, or used to listen and accept an incoming connection from that server.

exception qemu.qmp.qmp_client.GreetingError(error_message: str, exc: Exception)[source]

Bases: _WrappedProtocolError

An exception occurred during the Greeting phase.

Parameters:
  • error_message – Human-readable string describing the error.

  • exc – The root-cause exception.

exception qemu.qmp.qmp_client.NegotiationError(error_message: str, exc: Exception)[source]

Bases: _WrappedProtocolError

An exception occurred during the Negotiation phase.

Parameters:
  • error_message – Human-readable string describing the error.

  • exc – The root-cause exception.

exception qemu.qmp.qmp_client.ExecuteError(error_response: ErrorResponse, sent: Message, received: Message)[source]

Bases: QMPError

Exception raised by QMPClient.execute() on RPC failure.

This exception is raised when the server received, interpreted, and replied to a command successfully; but the command itself returned a failure status.

For example:

await qmp.execute('block-dirty-bitmap-add',
                  {'node': 'foo', 'name': 'my_bitmap'})
# qemu.qmp.qmp_client.ExecuteError:
#     Cannot find device='foo' nor node-name='foo'
Parameters:
  • error_response – The RPC error response object.

  • sent – The sent RPC message that caused the failure.

  • received – The raw RPC error reply received.

sent: Message

The sent Message that caused the failure

received: Message

The received Message that indicated failure

error: ErrorResponse

The parsed error response

property error_class: str

The QMP error class

exception qemu.qmp.qmp_client.ExecInterruptedError[source]

Bases: QMPError

Exception raised by execute() (et al) when an RPC is interrupted.

This error is raised when an execute() statement could not be completed. This can occur because the connection itself was terminated before a reply was received. The true cause of the interruption will be available via disconnect().

The QMP protocol does not make it possible to know if a command succeeded or failed after such an event; the client will need to query the server to determine the state of the server on a case-by-case basis.

For example, ECONNRESET might look like this:

try:
    await qmp.execute('query-block')
    # ExecInterruptedError: Disconnected
except ExecInterruptedError:
    await qmp.disconnect()
    # ConnectionResetError: [Errno 104] Connection reset by peer
exception qemu.qmp.qmp_client.ServerParseError(error_message: str, msg: Message, *args: object)[source]

Bases: _MsgProtocolError

The Server sent a Message indicating parsing failure.

i.e. A reply has arrived from the server, but it is missing the “ID” field, indicating a parsing error.

Parameters:
  • error_message – Human-readable string describing the error.

  • msg – The QMP Message that caused the error.

exception qemu.qmp.qmp_client.BadReplyError(error_message: str, msg: Message, sent: Message)[source]

Bases: _MsgProtocolError

An execution reply was successfully routed, but not understood.

If a QMP message is received with an ‘id’ field to allow it to be routed, but is otherwise malformed, this exception will be raised.

A reply message is malformed if it is missing either the ‘return’ or ‘error’ keys, or if the ‘error’ value has missing keys or members of the wrong type.

Parameters:
  • error_message – Human-readable string describing the error.

  • msg – The malformed reply that was received.

  • sent – The message that was sent that prompted the error.

sent

The sent Message that caused the failure

class qemu.qmp.qmp_client.QMPClient(name: str | None = None)[source]

Bases: AsyncProtocol[Message], Events

Implements a QMP client connection.

QMPClient can be used to either connect or listen to a QMP server, but always acts as the QMP client.

Parameters:

name – Optional nickname for the connection, used to differentiate instances when logging.

Basic script-style usage looks like this:

import asyncio
from qemu.qmp import QMPClient

async def main():
    qmp = QMPClient('my_virtual_machine_name')
    await qmp.connect(('127.0.0.1', 1234))
    ...
    res = await qmp.execute('query-block')
    ...
    await qmp.disconnect()

asyncio.run(main())

A more advanced example that starts to take advantage of asyncio might look like this:

class Client:
    def __init__(self, name: str):
        self.qmp = QMPClient(name)

    async def watch_events(self):
        try:
            async for event in self.qmp.events:
                print(f"Event: {event['event']}")
        except asyncio.CancelledError:
            return

    async def run(self, address='/tmp/qemu.socket'):
        await self.qmp.connect(address)
        asyncio.create_task(self.watch_events())
        await self.qmp.runstate_changed.wait()
        await self.disconnect()

See qmp.events for more detail on event handling patterns.

logger: logging.Logger = <Logger qemu.qmp.qmp_client (WARNING)>

Logger object used for debugging messages.

await_greeting: bool

Whether or not to await a greeting after establishing a connection. Defaults to True; QGA servers expect this to be False.

negotiate: bool

Whether or not to perform capabilities negotiation upon connection. Implies await_greeting. Defaults to True; QGA servers expect this to be False.

property greeting: Greeting | None

The Greeting from the QMP server, if any.

Defaults to None, and will be set after a greeting is received during the connection process. It is reset at the start of each connection attempt.

async execute_msg(msg: Message) object[source]

Execute a QMP command on the server and return its value.

Parameters:

msg – The QMP Message to execute.

Returns:

The command execution return value from the server. The type of object returned depends on the command that was issued, though most in QEMU return a dict.

Raises:
  • ValueError – If the QMP Message does not have either the ‘execute’ or ‘exec-oob’ fields set.

  • ExecuteError – When the server returns an error response.

  • ExecInterruptedError – If the connection was disrupted before receiving a reply from the server.

classmethod make_execute_msg(cmd: str, arguments: Mapping[str, object] | None = None, oob: bool = False) Message[source]

Create an executable message to be sent by execute_msg later.

Parameters:
  • cmd – QMP command name.

  • arguments – Arguments (if any). Must be JSON-serializable.

  • oob – If True, execute “out of band”.

Returns:

A QMP Message that can be executed with execute_msg().

async execute(cmd: str, arguments: Mapping[str, object] | None = None, oob: bool = False) object[source]

Execute a QMP command on the server and return its value.

Parameters:
  • cmd – QMP command name.

  • arguments – Arguments (if any). Must be JSON-serializable.

  • oob

    If True, execute “out of band”.

Returns:

The command execution return value from the server. The type of object returned depends on the command that was issued, though most in QEMU return a dict.

Raises:
  • ExecuteError – When the server returns an error response.

  • ExecInterruptedError – If the connection was disrupted before receiving a reply from the server.

send_fd_scm(fd: int) None[source]

Send a file descriptor to the remote via SCM_RIGHTS.

This method does not close the file descriptor.

Parameters:

fd – The file descriptor to send to QEMU.

This is an advanced feature of QEMU where file descriptors can be passed from client to server. This is usually used as a security measure to isolate the QEMU process from being able to open its own files. See the QMP commands getfd and add-fd for more information.

See socket.socket.sendmsg for more information on the Python implementation for sending file descriptors over a UNIX socket.

events: EventListener

Default, all-events EventListener. See qmp.events for more info.