]> Git Repo - qemu.git/blob - python/qemu/qmp.py
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
[qemu.git] / python / qemu / qmp.py
1 # QEMU Monitor Protocol Python class
2 #
3 # Copyright (C) 2009, 2010 Red Hat Inc.
4 #
5 # Authors:
6 #  Luiz Capitulino <[email protected]>
7 #
8 # This work is licensed under the terms of the GNU GPL, version 2.  See
9 # the COPYING file in the top-level directory.
10
11 import json
12 import errno
13 import socket
14 import logging
15
16
17 class QMPError(Exception):
18     pass
19
20
21 class QMPConnectError(QMPError):
22     pass
23
24
25 class QMPCapabilitiesError(QMPError):
26     pass
27
28
29 class QMPTimeoutError(QMPError):
30     pass
31
32
33 class QEMUMonitorProtocol(object):
34
35     #: Logger object for debugging messages
36     logger = logging.getLogger('QMP')
37     #: Socket's error class
38     error = socket.error
39     #: Socket's timeout
40     timeout = socket.timeout
41
42     def __init__(self, address, server=False):
43         """
44         Create a QEMUMonitorProtocol class.
45
46         @param address: QEMU address, can be either a unix socket path (string)
47                         or a tuple in the form ( address, port ) for a TCP
48                         connection
49         @param server: server mode listens on the socket (bool)
50         @raise socket.error on socket connection errors
51         @note No connection is established, this is done by the connect() or
52               accept() methods
53         """
54         self.__events = []
55         self.__address = address
56         self.__sock = self.__get_sock()
57         self.__sockfile = None
58         if server:
59             self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
60             self.__sock.bind(self.__address)
61             self.__sock.listen(1)
62
63     def __get_sock(self):
64         if isinstance(self.__address, tuple):
65             family = socket.AF_INET
66         else:
67             family = socket.AF_UNIX
68         return socket.socket(family, socket.SOCK_STREAM)
69
70     def __negotiate_capabilities(self):
71         greeting = self.__json_read()
72         if greeting is None or "QMP" not in greeting:
73             raise QMPConnectError
74         # Greeting seems ok, negotiate capabilities
75         resp = self.cmd('qmp_capabilities')
76         if "return" in resp:
77             return greeting
78         raise QMPCapabilitiesError
79
80     def __json_read(self, only_event=False):
81         while True:
82             data = self.__sockfile.readline()
83             if not data:
84                 return
85             resp = json.loads(data)
86             if 'event' in resp:
87                 self.logger.debug("<<< %s", resp)
88                 self.__events.append(resp)
89                 if not only_event:
90                     continue
91             return resp
92
93     def __get_events(self, wait=False):
94         """
95         Check for new events in the stream and cache them in __events.
96
97         @param wait (bool): block until an event is available.
98         @param wait (float): If wait is a float, treat it as a timeout value.
99
100         @raise QMPTimeoutError: If a timeout float is provided and the timeout
101                                 period elapses.
102         @raise QMPConnectError: If wait is True but no events could be
103                                 retrieved or if some other error occurred.
104         """
105
106         # Check for new events regardless and pull them into the cache:
107         self.__sock.setblocking(0)
108         try:
109             self.__json_read()
110         except socket.error as err:
111             if err[0] == errno.EAGAIN:
112                 # No data available
113                 pass
114         self.__sock.setblocking(1)
115
116         # Wait for new events, if needed.
117         # if wait is 0.0, this means "no wait" and is also implicitly false.
118         if not self.__events and wait:
119             if isinstance(wait, float):
120                 self.__sock.settimeout(wait)
121             try:
122                 ret = self.__json_read(only_event=True)
123             except socket.timeout:
124                 raise QMPTimeoutError("Timeout waiting for event")
125             except:
126                 raise QMPConnectError("Error while reading from socket")
127             if ret is None:
128                 raise QMPConnectError("Error while reading from socket")
129             self.__sock.settimeout(None)
130
131     def connect(self, negotiate=True):
132         """
133         Connect to the QMP Monitor and perform capabilities negotiation.
134
135         @return QMP greeting dict
136         @raise socket.error on socket connection errors
137         @raise QMPConnectError if the greeting is not received
138         @raise QMPCapabilitiesError if fails to negotiate capabilities
139         """
140         self.__sock.connect(self.__address)
141         self.__sockfile = self.__sock.makefile()
142         if negotiate:
143             return self.__negotiate_capabilities()
144
145     def accept(self):
146         """
147         Await connection from QMP Monitor and perform capabilities negotiation.
148
149         @return QMP greeting dict
150         @raise socket.error on socket connection errors
151         @raise QMPConnectError if the greeting is not received
152         @raise QMPCapabilitiesError if fails to negotiate capabilities
153         """
154         self.__sock.settimeout(15)
155         self.__sock, _ = self.__sock.accept()
156         self.__sockfile = self.__sock.makefile()
157         return self.__negotiate_capabilities()
158
159     def cmd_obj(self, qmp_cmd):
160         """
161         Send a QMP command to the QMP Monitor.
162
163         @param qmp_cmd: QMP command to be sent as a Python dict
164         @return QMP response as a Python dict or None if the connection has
165                 been closed
166         """
167         self.logger.debug(">>> %s", qmp_cmd)
168         try:
169             self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8'))
170         except socket.error as err:
171             if err[0] == errno.EPIPE:
172                 return
173             raise socket.error(err)
174         resp = self.__json_read()
175         self.logger.debug("<<< %s", resp)
176         return resp
177
178     def cmd(self, name, args=None, cmd_id=None):
179         """
180         Build a QMP command and send it to the QMP Monitor.
181
182         @param name: command name (string)
183         @param args: command arguments (dict)
184         @param cmd_id: command id (dict, list, string or int)
185         """
186         qmp_cmd = {'execute': name}
187         if args:
188             qmp_cmd['arguments'] = args
189         if cmd_id:
190             qmp_cmd['id'] = cmd_id
191         return self.cmd_obj(qmp_cmd)
192
193     def command(self, cmd, **kwds):
194         """
195         Build and send a QMP command to the monitor, report errors if any
196         """
197         ret = self.cmd(cmd, kwds)
198         if "error" in ret:
199             raise Exception(ret['error']['desc'])
200         return ret['return']
201
202     def pull_event(self, wait=False):
203         """
204         Pulls a single event.
205
206         @param wait (bool): block until an event is available.
207         @param wait (float): If wait is a float, treat it as a timeout value.
208
209         @raise QMPTimeoutError: If a timeout float is provided and the timeout
210                                 period elapses.
211         @raise QMPConnectError: If wait is True but no events could be
212                                 retrieved or if some other error occurred.
213
214         @return The first available QMP event, or None.
215         """
216         self.__get_events(wait)
217
218         if self.__events:
219             return self.__events.pop(0)
220         return None
221
222     def get_events(self, wait=False):
223         """
224         Get a list of available QMP events.
225
226         @param wait (bool): block until an event is available.
227         @param wait (float): If wait is a float, treat it as a timeout value.
228
229         @raise QMPTimeoutError: If a timeout float is provided and the timeout
230                                 period elapses.
231         @raise QMPConnectError: If wait is True but no events could be
232                                 retrieved or if some other error occurred.
233
234         @return The list of available QMP events.
235         """
236         self.__get_events(wait)
237         return self.__events
238
239     def clear_events(self):
240         """
241         Clear current list of pending events.
242         """
243         self.__events = []
244
245     def close(self):
246         self.__sock.close()
247         self.__sockfile.close()
248
249     def settimeout(self, timeout):
250         self.__sock.settimeout(timeout)
251
252     def get_sock_fd(self):
253         return self.__sock.fileno()
254
255     def is_scm_available(self):
256         return self.__sock.family == socket.AF_UNIX
This page took 0.038452 seconds and 4 git commands to generate.