1 """ QEMU Monitor Protocol Python class """
2 # Copyright (C) 2009, 2010 Red Hat Inc.
5 # Luiz Capitulino <lcapitulino@redhat.com>
7 # This work is licensed under the terms of the GNU GPL, version 2. See
8 # the COPYING file in the top-level directory.
16 class QMPError(Exception):
22 class QMPConnectError(QMPError
):
24 QMP connection exception
28 class QMPCapabilitiesError(QMPError
):
30 QMP negotiate capabilities exception
34 class QMPTimeoutError(QMPError
):
40 class QEMUMonitorProtocol
:
42 Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP) and then
43 allow to handle commands and events.
46 #: Logger object for debugging messages
47 logger
= logging
.getLogger('QMP')
49 def __init__(self
, address
, server
=False):
51 Create a QEMUMonitorProtocol class.
53 @param address: QEMU address, can be either a unix socket path (string)
54 or a tuple in the form ( address, port ) for a TCP
56 @param server: server mode listens on the socket (bool)
57 @raise OSError on socket connection errors
58 @note No connection is established, this is done by the connect() or
62 self
.__address
= address
63 self
.__sock
= self
.__get
_sock
()
64 self
.__sockfile
= None
66 self
.__sock
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_REUSEADDR
, 1)
67 self
.__sock
.bind(self
.__address
)
71 if isinstance(self
.__address
, tuple):
72 family
= socket
.AF_INET
74 family
= socket
.AF_UNIX
75 return socket
.socket(family
, socket
.SOCK_STREAM
)
77 def __negotiate_capabilities(self
):
78 greeting
= self
.__json
_read
()
79 if greeting
is None or "QMP" not in greeting
:
81 # Greeting seems ok, negotiate capabilities
82 resp
= self
.cmd('qmp_capabilities')
83 if resp
and "return" in resp
:
85 raise QMPCapabilitiesError
87 def __json_read(self
, only_event
=False):
89 data
= self
.__sockfile
.readline()
92 resp
= json
.loads(data
)
94 self
.logger
.debug("<<< %s", resp
)
95 self
.__events
.append(resp
)
100 def __get_events(self
, wait
=False):
102 Check for new events in the stream and cache them in __events.
104 @param wait (bool): block until an event is available.
105 @param wait (float): If wait is a float, treat it as a timeout value.
107 @raise QMPTimeoutError: If a timeout float is provided and the timeout
109 @raise QMPConnectError: If wait is True but no events could be
110 retrieved or if some other error occurred.
113 # Check for new events regardless and pull them into the cache:
114 self
.__sock
.setblocking(0)
117 except OSError as err
:
118 if err
.errno
== errno
.EAGAIN
:
121 self
.__sock
.setblocking(1)
123 # Wait for new events, if needed.
124 # if wait is 0.0, this means "no wait" and is also implicitly false.
125 if not self
.__events
and wait
:
126 if isinstance(wait
, float):
127 self
.__sock
.settimeout(wait
)
129 ret
= self
.__json
_read
(only_event
=True)
130 except socket
.timeout
:
131 raise QMPTimeoutError("Timeout waiting for event")
133 raise QMPConnectError("Error while reading from socket")
135 raise QMPConnectError("Error while reading from socket")
136 self
.__sock
.settimeout(None)
139 # Implement context manager enter function.
142 def __exit__(self
, exc_type
, exc_value
, exc_traceback
):
143 # Implement context manager exit function.
147 def connect(self
, negotiate
=True):
149 Connect to the QMP Monitor and perform capabilities negotiation.
151 @return QMP greeting dict, or None if negotiate is false
152 @raise OSError on socket connection errors
153 @raise QMPConnectError if the greeting is not received
154 @raise QMPCapabilitiesError if fails to negotiate capabilities
156 self
.__sock
.connect(self
.__address
)
157 self
.__sockfile
= self
.__sock
.makefile()
159 return self
.__negotiate
_capabilities
()
162 def accept(self
, timeout
=15.0):
164 Await connection from QMP Monitor and perform capabilities negotiation.
166 @param timeout: timeout in seconds (nonnegative float number, or
167 None). The value passed will set the behavior of the
168 underneath QMP socket as described in [1]. Default value
170 @return QMP greeting dict
171 @raise OSError on socket connection errors
172 @raise QMPConnectError if the greeting is not received
173 @raise QMPCapabilitiesError if fails to negotiate capabilities
176 https://docs.python.org/3/library/socket.html#socket.socket.settimeout
178 self
.__sock
.settimeout(timeout
)
179 self
.__sock
, _
= self
.__sock
.accept()
180 self
.__sockfile
= self
.__sock
.makefile()
181 return self
.__negotiate
_capabilities
()
183 def cmd_obj(self
, qmp_cmd
):
185 Send a QMP command to the QMP Monitor.
187 @param qmp_cmd: QMP command to be sent as a Python dict
188 @return QMP response as a Python dict or None if the connection has
191 self
.logger
.debug(">>> %s", qmp_cmd
)
193 self
.__sock
.sendall(json
.dumps(qmp_cmd
).encode('utf-8'))
194 except OSError as err
:
195 if err
.errno
== errno
.EPIPE
:
198 resp
= self
.__json
_read
()
199 self
.logger
.debug("<<< %s", resp
)
202 def cmd(self
, name
, args
=None, cmd_id
=None):
204 Build a QMP command and send it to the QMP Monitor.
206 @param name: command name (string)
207 @param args: command arguments (dict)
208 @param cmd_id: command id (dict, list, string or int)
210 qmp_cmd
= {'execute': name
}
212 qmp_cmd
['arguments'] = args
214 qmp_cmd
['id'] = cmd_id
215 return self
.cmd_obj(qmp_cmd
)
217 def command(self
, cmd
, **kwds
):
219 Build and send a QMP command to the monitor, report errors if any
221 ret
= self
.cmd(cmd
, kwds
)
223 raise Exception(ret
['error']['desc'])
226 def pull_event(self
, wait
=False):
228 Pulls a single event.
230 @param wait (bool): block until an event is available.
231 @param wait (float): If wait is a float, treat it as a timeout value.
233 @raise QMPTimeoutError: If a timeout float is provided and the timeout
235 @raise QMPConnectError: If wait is True but no events could be
236 retrieved or if some other error occurred.
238 @return The first available QMP event, or None.
240 self
.__get
_events
(wait
)
243 return self
.__events
.pop(0)
246 def get_events(self
, wait
=False):
248 Get a list of available QMP events.
250 @param wait (bool): block until an event is available.
251 @param wait (float): If wait is a float, treat it as a timeout value.
253 @raise QMPTimeoutError: If a timeout float is provided and the timeout
255 @raise QMPConnectError: If wait is True but no events could be
256 retrieved or if some other error occurred.
258 @return The list of available QMP events.
260 self
.__get
_events
(wait
)
263 def clear_events(self
):
265 Clear current list of pending events.
271 Close the socket and socket file.
276 self
.__sockfile
.close()
278 def settimeout(self
, timeout
):
280 Set the socket timeout.
282 @param timeout (float): timeout in seconds, or None.
283 @note This is a wrap around socket.settimeout
285 self
.__sock
.settimeout(timeout
)
287 def get_sock_fd(self
):
289 Get the socket file descriptor.
291 @return The file descriptor number.
293 return self
.__sock
.fileno()
295 def is_scm_available(self
):
297 Check if the socket allows for SCM_RIGHTS.
299 @return True if SCM_RIGHTS is available, otherwise False.
301 return self
.__sock
.family
== socket
.AF_UNIX