root / scripts / qmp / qmp.py @ 48645123
History | View | Annotate | Download (6 kB)
1 | cedebdac | Luiz Capitulino | # QEMU Monitor Protocol Python class
|
---|---|---|---|
2 | 22f3946b | Luiz Capitulino | #
|
3 | 1d00a07d | Luiz Capitulino | # Copyright (C) 2009, 2010 Red Hat Inc.
|
4 | cedebdac | Luiz Capitulino | #
|
5 | cedebdac | Luiz Capitulino | # Authors:
|
6 | cedebdac | Luiz Capitulino | # Luiz Capitulino <lcapitulino@redhat.com>
|
7 | cedebdac | Luiz Capitulino | #
|
8 | cedebdac | Luiz Capitulino | # This work is licensed under the terms of the GNU GPL, version 2. See
|
9 | cedebdac | Luiz Capitulino | # the COPYING file in the top-level directory.
|
10 | cedebdac | Luiz Capitulino | |
11 | 1d00a07d | Luiz Capitulino | import json |
12 | 1d00a07d | Luiz Capitulino | import errno |
13 | 1d00a07d | Luiz Capitulino | import socket |
14 | cedebdac | Luiz Capitulino | |
15 | cedebdac | Luiz Capitulino | class QMPError(Exception): |
16 | cedebdac | Luiz Capitulino | pass
|
17 | cedebdac | Luiz Capitulino | |
18 | cedebdac | Luiz Capitulino | class QMPConnectError(QMPError): |
19 | cedebdac | Luiz Capitulino | pass
|
20 | cedebdac | Luiz Capitulino | |
21 | 1d00a07d | Luiz Capitulino | class QMPCapabilitiesError(QMPError): |
22 | 1d00a07d | Luiz Capitulino | pass
|
23 | 1d00a07d | Luiz Capitulino | |
24 | cedebdac | Luiz Capitulino | class QEMUMonitorProtocol: |
25 | 37628f11 | Stefan Hajnoczi | def __init__(self, address, server=False): |
26 | 1d00a07d | Luiz Capitulino | """
|
27 | 1d00a07d | Luiz Capitulino | Create a QEMUMonitorProtocol class.
|
28 | 1d00a07d | Luiz Capitulino |
|
29 | 1d00a07d | Luiz Capitulino | @param address: QEMU address, can be either a unix socket path (string)
|
30 | 1d00a07d | Luiz Capitulino | or a tuple in the form ( address, port ) for a TCP
|
31 | 1d00a07d | Luiz Capitulino | connection
|
32 | 37628f11 | Stefan Hajnoczi | @param server: server mode listens on the socket (bool)
|
33 | 37628f11 | Stefan Hajnoczi | @raise socket.error on socket connection errors
|
34 | 37628f11 | Stefan Hajnoczi | @note No connection is established, this is done by the connect() or
|
35 | 37628f11 | Stefan Hajnoczi | accept() methods
|
36 | 1d00a07d | Luiz Capitulino | """
|
37 | 1d00a07d | Luiz Capitulino | self.__events = []
|
38 | 1d00a07d | Luiz Capitulino | self.__address = address
|
39 | 1d00a07d | Luiz Capitulino | self.__sock = self.__get_sock() |
40 | 37628f11 | Stefan Hajnoczi | if server:
|
41 | 37628f11 | Stefan Hajnoczi | self.__sock.bind(self.__address) |
42 | 37628f11 | Stefan Hajnoczi | self.__sock.listen(1) |
43 | 1d00a07d | Luiz Capitulino | |
44 | 1d00a07d | Luiz Capitulino | def __get_sock(self): |
45 | 1d00a07d | Luiz Capitulino | if isinstance(self.__address, tuple): |
46 | 1d00a07d | Luiz Capitulino | family = socket.AF_INET |
47 | 1d00a07d | Luiz Capitulino | else:
|
48 | 1d00a07d | Luiz Capitulino | family = socket.AF_UNIX |
49 | 1d00a07d | Luiz Capitulino | return socket.socket(family, socket.SOCK_STREAM)
|
50 | 1d00a07d | Luiz Capitulino | |
51 | 37628f11 | Stefan Hajnoczi | def __negotiate_capabilities(self): |
52 | 37628f11 | Stefan Hajnoczi | greeting = self.__json_read()
|
53 | 37628f11 | Stefan Hajnoczi | if greeting is None or not greeting.has_key('QMP'): |
54 | 37628f11 | Stefan Hajnoczi | raise QMPConnectError
|
55 | 37628f11 | Stefan Hajnoczi | # Greeting seems ok, negotiate capabilities
|
56 | 37628f11 | Stefan Hajnoczi | resp = self.cmd('qmp_capabilities') |
57 | 37628f11 | Stefan Hajnoczi | if "return" in resp: |
58 | 37628f11 | Stefan Hajnoczi | return greeting
|
59 | 37628f11 | Stefan Hajnoczi | raise QMPCapabilitiesError
|
60 | 37628f11 | Stefan Hajnoczi | |
61 | 91b8eddf | Stefan Hajnoczi | def __json_read(self, only_event=False): |
62 | 1d00a07d | Luiz Capitulino | while True: |
63 | 1d00a07d | Luiz Capitulino | data = self.__sockfile.readline()
|
64 | 1d00a07d | Luiz Capitulino | if not data: |
65 | 1d00a07d | Luiz Capitulino | return
|
66 | 1d00a07d | Luiz Capitulino | resp = json.loads(data) |
67 | 1d00a07d | Luiz Capitulino | if 'event' in resp: |
68 | 1d00a07d | Luiz Capitulino | self.__events.append(resp)
|
69 | 91b8eddf | Stefan Hajnoczi | if not only_event: |
70 | 91b8eddf | Stefan Hajnoczi | continue
|
71 | 1d00a07d | Luiz Capitulino | return resp
|
72 | 1d00a07d | Luiz Capitulino | |
73 | 1d00a07d | Luiz Capitulino | error = socket.error |
74 | 1d00a07d | Luiz Capitulino | |
75 | e9d17b68 | Ryota Ozaki | def connect(self, negotiate=True): |
76 | 1d00a07d | Luiz Capitulino | """
|
77 | 1d00a07d | Luiz Capitulino | Connect to the QMP Monitor and perform capabilities negotiation.
|
78 | 1d00a07d | Luiz Capitulino |
|
79 | 1d00a07d | Luiz Capitulino | @return QMP greeting dict
|
80 | 1d00a07d | Luiz Capitulino | @raise socket.error on socket connection errors
|
81 | 1d00a07d | Luiz Capitulino | @raise QMPConnectError if the greeting is not received
|
82 | 1d00a07d | Luiz Capitulino | @raise QMPCapabilitiesError if fails to negotiate capabilities
|
83 | 1d00a07d | Luiz Capitulino | """
|
84 | 1d00a07d | Luiz Capitulino | self.__sock.connect(self.__address) |
85 | e9d17b68 | Ryota Ozaki | self.__sockfile = self.__sock.makefile() |
86 | e9d17b68 | Ryota Ozaki | if negotiate:
|
87 | e9d17b68 | Ryota Ozaki | return self.__negotiate_capabilities() |
88 | 37628f11 | Stefan Hajnoczi | |
89 | 37628f11 | Stefan Hajnoczi | def accept(self): |
90 | 37628f11 | Stefan Hajnoczi | """
|
91 | 37628f11 | Stefan Hajnoczi | Await connection from QMP Monitor and perform capabilities negotiation.
|
92 | 37628f11 | Stefan Hajnoczi |
|
93 | 37628f11 | Stefan Hajnoczi | @return QMP greeting dict
|
94 | 37628f11 | Stefan Hajnoczi | @raise socket.error on socket connection errors
|
95 | 37628f11 | Stefan Hajnoczi | @raise QMPConnectError if the greeting is not received
|
96 | 37628f11 | Stefan Hajnoczi | @raise QMPCapabilitiesError if fails to negotiate capabilities
|
97 | 37628f11 | Stefan Hajnoczi | """
|
98 | 37628f11 | Stefan Hajnoczi | self.__sock, _ = self.__sock.accept() |
99 | b3d0380e | Jeff Cody | self.__sockfile = self.__sock.makefile() |
100 | 37628f11 | Stefan Hajnoczi | return self.__negotiate_capabilities() |
101 | cedebdac | Luiz Capitulino | |
102 | 1d00a07d | Luiz Capitulino | def cmd_obj(self, qmp_cmd): |
103 | 1d00a07d | Luiz Capitulino | """
|
104 | 1d00a07d | Luiz Capitulino | Send a QMP command to the QMP Monitor.
|
105 | cedebdac | Luiz Capitulino |
|
106 | 1d00a07d | Luiz Capitulino | @param qmp_cmd: QMP command to be sent as a Python dict
|
107 | 1d00a07d | Luiz Capitulino | @return QMP response as a Python dict or None if the connection has
|
108 | 1d00a07d | Luiz Capitulino | been closed
|
109 | 1d00a07d | Luiz Capitulino | """
|
110 | 1d00a07d | Luiz Capitulino | try:
|
111 | 1d00a07d | Luiz Capitulino | self.__sock.sendall(json.dumps(qmp_cmd))
|
112 | 1d00a07d | Luiz Capitulino | except socket.error, err:
|
113 | 1d00a07d | Luiz Capitulino | if err[0] == errno.EPIPE: |
114 | 1d00a07d | Luiz Capitulino | return
|
115 | 1d00a07d | Luiz Capitulino | raise socket.error(err)
|
116 | cedebdac | Luiz Capitulino | return self.__json_read() |
117 | cedebdac | Luiz Capitulino | |
118 | 1d00a07d | Luiz Capitulino | def cmd(self, name, args=None, id=None): |
119 | 1d00a07d | Luiz Capitulino | """
|
120 | 1d00a07d | Luiz Capitulino | Build a QMP command and send it to the QMP Monitor.
|
121 | cedebdac | Luiz Capitulino |
|
122 | 1d00a07d | Luiz Capitulino | @param name: command name (string)
|
123 | 1d00a07d | Luiz Capitulino | @param args: command arguments (dict)
|
124 | 1d00a07d | Luiz Capitulino | @param id: command id (dict, list, string or int)
|
125 | 1d00a07d | Luiz Capitulino | """
|
126 | 1d00a07d | Luiz Capitulino | qmp_cmd = { 'execute': name }
|
127 | 1d00a07d | Luiz Capitulino | if args:
|
128 | 1d00a07d | Luiz Capitulino | qmp_cmd['arguments'] = args
|
129 | 1d00a07d | Luiz Capitulino | if id: |
130 | 1d00a07d | Luiz Capitulino | qmp_cmd['id'] = id |
131 | 1d00a07d | Luiz Capitulino | return self.cmd_obj(qmp_cmd) |
132 | 1d00a07d | Luiz Capitulino | |
133 | 9f68f7fb | Anthony Liguori | def command(self, cmd, **kwds): |
134 | 9f68f7fb | Anthony Liguori | ret = self.cmd(cmd, kwds)
|
135 | 9f68f7fb | Anthony Liguori | if ret.has_key('error'): |
136 | 9f68f7fb | Anthony Liguori | raise Exception(ret['error']['desc']) |
137 | 9f68f7fb | Anthony Liguori | return ret['return'] |
138 | 9f68f7fb | Anthony Liguori | |
139 | 9eb80ead | Paolo Bonzini | def pull_event(self, wait=False): |
140 | 9eb80ead | Paolo Bonzini | """
|
141 | 9eb80ead | Paolo Bonzini | Get and delete the first available QMP event.
|
142 | 9eb80ead | Paolo Bonzini |
|
143 | 9eb80ead | Paolo Bonzini | @param wait: block until an event is available (bool)
|
144 | 9eb80ead | Paolo Bonzini | """
|
145 | 9eb80ead | Paolo Bonzini | self.__sock.setblocking(0) |
146 | 9eb80ead | Paolo Bonzini | try:
|
147 | 9eb80ead | Paolo Bonzini | self.__json_read()
|
148 | 9eb80ead | Paolo Bonzini | except socket.error, err:
|
149 | 9eb80ead | Paolo Bonzini | if err[0] == errno.EAGAIN: |
150 | 9eb80ead | Paolo Bonzini | # No data available
|
151 | 9eb80ead | Paolo Bonzini | pass
|
152 | 9eb80ead | Paolo Bonzini | self.__sock.setblocking(1) |
153 | 9eb80ead | Paolo Bonzini | if not self.__events and wait: |
154 | 9eb80ead | Paolo Bonzini | self.__json_read(only_event=True) |
155 | 9eb80ead | Paolo Bonzini | event = self.__events[0] |
156 | 9eb80ead | Paolo Bonzini | del self.__events[0] |
157 | 9eb80ead | Paolo Bonzini | return event
|
158 | 9eb80ead | Paolo Bonzini | |
159 | 91b8eddf | Stefan Hajnoczi | def get_events(self, wait=False): |
160 | 1d00a07d | Luiz Capitulino | """
|
161 | 1d00a07d | Luiz Capitulino | Get a list of available QMP events.
|
162 | 91b8eddf | Stefan Hajnoczi |
|
163 | 91b8eddf | Stefan Hajnoczi | @param wait: block until an event is available (bool)
|
164 | 1d00a07d | Luiz Capitulino | """
|
165 | 1d00a07d | Luiz Capitulino | self.__sock.setblocking(0) |
166 | cedebdac | Luiz Capitulino | try:
|
167 | 1d00a07d | Luiz Capitulino | self.__json_read()
|
168 | 1d00a07d | Luiz Capitulino | except socket.error, err:
|
169 | 1d00a07d | Luiz Capitulino | if err[0] == errno.EAGAIN: |
170 | 1d00a07d | Luiz Capitulino | # No data available
|
171 | 1d00a07d | Luiz Capitulino | pass
|
172 | 1d00a07d | Luiz Capitulino | self.__sock.setblocking(1) |
173 | 91b8eddf | Stefan Hajnoczi | if not self.__events and wait: |
174 | 48645123 | Fam Zheng | ret = self.__json_read(only_event=True) |
175 | 48645123 | Fam Zheng | if ret == None: |
176 | 48645123 | Fam Zheng | # We are in blocking mode, if don't get anything, something
|
177 | 48645123 | Fam Zheng | # went wrong
|
178 | 48645123 | Fam Zheng | raise QMPConnectError("Error while reading from socket") |
179 | 48645123 | Fam Zheng | |
180 | 1d00a07d | Luiz Capitulino | return self.__events |
181 | 1d00a07d | Luiz Capitulino | |
182 | 1d00a07d | Luiz Capitulino | def clear_events(self): |
183 | 1d00a07d | Luiz Capitulino | """
|
184 | 1d00a07d | Luiz Capitulino | Clear current list of pending events.
|
185 | 1d00a07d | Luiz Capitulino | """
|
186 | 1d00a07d | Luiz Capitulino | self.__events = []
|
187 | 1d00a07d | Luiz Capitulino | |
188 | 1d00a07d | Luiz Capitulino | def close(self): |
189 | 1d00a07d | Luiz Capitulino | self.__sock.close()
|
190 | 1d00a07d | Luiz Capitulino | self.__sockfile.close()
|
191 | e37b350a | Ryota Ozaki | |
192 | e37b350a | Ryota Ozaki | timeout = socket.timeout |
193 | e37b350a | Ryota Ozaki | |
194 | e37b350a | Ryota Ozaki | def settimeout(self, timeout): |
195 | e37b350a | Ryota Ozaki | self.__sock.settimeout(timeout)
|
196 | 30b005d9 | Wenchao Xia | |
197 | 30b005d9 | Wenchao Xia | def get_sock_fd(self): |
198 | 30b005d9 | Wenchao Xia | return self.__sock.fileno() |
199 | 30b005d9 | Wenchao Xia | |
200 | 30b005d9 | Wenchao Xia | def is_scm_available(self): |
201 | 30b005d9 | Wenchao Xia | return self.__sock.family == socket.AF_UNIX |