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