OLD | NEW |
1 """ | 1 """ |
2 Interfaces to the QEMU monitor. | 2 Interfaces to the QEMU monitor. |
3 | 3 |
4 @copyright: 2008-2010 Red Hat Inc. | 4 @copyright: 2008-2010 Red Hat Inc. |
5 """ | 5 """ |
6 | 6 |
7 import socket, time, threading, logging, select | 7 import socket, time, threading, logging, select |
8 import kvm_utils | 8 import kvm_utils |
9 try: | 9 try: |
10 import json | 10 import json |
11 except ImportError: | 11 except ImportError: |
12 logging.warning("Could not import json module. " | 12 logging.warning("Could not import json module. " |
13 "QMP monitor functionality disabled.") | 13 "QMP monitor functionality disabled.") |
14 | 14 |
15 | 15 |
16 class MonitorError(Exception): | 16 class MonitorError(Exception): |
17 pass | 17 pass |
18 | 18 |
19 | 19 |
20 class MonitorConnectError(MonitorError): | 20 class MonitorConnectError(MonitorError): |
21 pass | 21 pass |
22 | 22 |
23 | 23 |
24 class MonitorSocketError(MonitorError): | 24 class MonitorSocketError(MonitorError): |
25 pass | 25 def __init__(self, msg, e): |
| 26 Exception.__init__(self, msg, e) |
| 27 self.msg = msg |
| 28 self.e = e |
| 29 |
| 30 def __str__(self): |
| 31 return "%s (%s)" % (self.msg, self.e) |
26 | 32 |
27 | 33 |
28 class MonitorLockError(MonitorError): | 34 class MonitorLockError(MonitorError): |
29 pass | 35 pass |
30 | 36 |
31 | 37 |
32 class MonitorProtocolError(MonitorError): | 38 class MonitorProtocolError(MonitorError): |
33 pass | 39 pass |
34 | 40 |
35 | 41 |
36 class MonitorNotSupportedError(MonitorError): | 42 class MonitorNotSupportedError(MonitorError): |
37 pass | 43 pass |
38 | 44 |
39 | 45 |
40 class QMPCmdError(MonitorError): | 46 class QMPCmdError(MonitorError): |
41 def __init__(self, cmd, qmp_args, data): | 47 def __init__(self, cmd, qmp_args, data): |
42 MonitorError.__init__(self, cmd, qmp_args, data) | 48 MonitorError.__init__(self, cmd, qmp_args, data) |
43 self.cmd = cmd | 49 self.cmd = cmd |
44 self.qmp_args = qmp_args | 50 self.qmp_args = qmp_args |
45 self.data = data | 51 self.data = data |
46 | 52 |
47 def __str__(self): | 53 def __str__(self): |
48 return ("QMP command %r failed (arguments: %r, error message: %r)" % | 54 return ("QMP command %r failed (arguments: %r, " |
49 (self.cmd, self.qmp_args, self.data)) | 55 "error message: %r)" % (self.cmd, self.qmp_args, self.data)) |
50 | 56 |
51 | 57 |
52 class Monitor: | 58 class Monitor: |
53 """ | 59 """ |
54 Common code for monitor classes. | 60 Common code for monitor classes. |
55 """ | 61 """ |
56 | 62 |
57 def __init__(self, name, filename): | 63 def __init__(self, name, filename): |
58 """ | 64 """ |
59 Initialize the instance. | 65 Initialize the instance. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 def _data_available(self, timeout=0): | 118 def _data_available(self, timeout=0): |
113 timeout = max(0, timeout) | 119 timeout = max(0, timeout) |
114 return bool(select.select([self._socket], [], [], timeout)[0]) | 120 return bool(select.select([self._socket], [], [], timeout)[0]) |
115 | 121 |
116 | 122 |
117 def _recvall(self): | 123 def _recvall(self): |
118 s = "" | 124 s = "" |
119 while self._data_available(): | 125 while self._data_available(): |
120 try: | 126 try: |
121 data = self._socket.recv(1024) | 127 data = self._socket.recv(1024) |
122 except socket.error, (errno, msg): | 128 except socket.error, e: |
123 raise MonitorSocketError("Could not receive data from monitor " | 129 raise MonitorSocketError("Could not receive data from monitor", |
124 "(%s)" % msg) | 130 e) |
125 if not data: | 131 if not data: |
126 break | 132 break |
127 s += data | 133 s += data |
128 return s | 134 return s |
129 | 135 |
130 | 136 |
| 137 def is_responsive(self): |
| 138 """ |
| 139 Return True iff the monitor is responsive. |
| 140 """ |
| 141 try: |
| 142 self.verify_responsive() |
| 143 return True |
| 144 except MonitorError: |
| 145 return False |
| 146 |
| 147 |
131 class HumanMonitor(Monitor): | 148 class HumanMonitor(Monitor): |
132 """ | 149 """ |
133 Wraps "human monitor" commands. | 150 Wraps "human monitor" commands. |
134 """ | 151 """ |
135 | 152 |
136 def __init__(self, name, filename, suppress_exceptions=False): | 153 def __init__(self, name, filename, suppress_exceptions=False): |
137 """ | 154 """ |
138 Connect to the monitor socket and find the (qemu) prompt. | 155 Connect to the monitor socket and find the (qemu) prompt. |
139 | 156 |
140 @param name: Monitor identifier (a string) | 157 @param name: Monitor identifier (a string) |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 @raise MonitorLockError: Raised if the lock cannot be acquired | 211 @raise MonitorLockError: Raised if the lock cannot be acquired |
195 @raise MonitorSocketError: Raised if a socket error occurs | 212 @raise MonitorSocketError: Raised if a socket error occurs |
196 """ | 213 """ |
197 if not self._acquire_lock(20): | 214 if not self._acquire_lock(20): |
198 raise MonitorLockError("Could not acquire exclusive lock to send " | 215 raise MonitorLockError("Could not acquire exclusive lock to send " |
199 "monitor command '%s'" % cmd) | 216 "monitor command '%s'" % cmd) |
200 | 217 |
201 try: | 218 try: |
202 try: | 219 try: |
203 self._socket.sendall(cmd + "\n") | 220 self._socket.sendall(cmd + "\n") |
204 except socket.error, (errno, msg): | 221 except socket.error, e: |
205 raise MonitorSocketError("Could not send monitor command '%s' " | 222 raise MonitorSocketError("Could not send monitor command %r" % |
206 "(%s)" % (cmd, msg)) | 223 cmd, e) |
207 | 224 |
208 finally: | 225 finally: |
209 self._lock.release() | 226 self._lock.release() |
210 | 227 |
211 | 228 |
212 # Public methods | 229 # Public methods |
213 | 230 |
214 def cmd(self, command, timeout=20): | 231 def cmd(self, command, timeout=20): |
215 """ | 232 """ |
216 Send command to the monitor. | 233 Send command to the monitor. |
(...skipping 24 matching lines...) Expand all Loading... |
241 return o | 258 return o |
242 else: | 259 else: |
243 msg = ("Could not find (qemu) prompt after command '%s'. " | 260 msg = ("Could not find (qemu) prompt after command '%s'. " |
244 "Output so far: %r" % (command, o)) | 261 "Output so far: %r" % (command, o)) |
245 raise MonitorProtocolError(msg) | 262 raise MonitorProtocolError(msg) |
246 | 263 |
247 finally: | 264 finally: |
248 self._lock.release() | 265 self._lock.release() |
249 | 266 |
250 | 267 |
251 def is_responsive(self): | 268 def verify_responsive(self): |
252 """ | 269 """ |
253 Make sure the monitor is responsive by sending a command. | 270 Make sure the monitor is responsive by sending a command. |
254 | |
255 @return: True if responsive, False otherwise | |
256 """ | 271 """ |
257 try: | 272 self.cmd("info status") |
258 self.cmd("info status") | |
259 return True | |
260 except MonitorError: | |
261 return False | |
262 | 273 |
263 | 274 |
264 # Command wrappers | 275 # Command wrappers |
265 # Notes: | 276 # Notes: |
266 # - All of the following commands raise exceptions in a similar manner to | 277 # - All of the following commands raise exceptions in a similar manner to |
267 # cmd(). | 278 # cmd(). |
268 # - A command wrapper should use self._help_str if it requires information | 279 # - A command wrapper should use self._help_str if it requires information |
269 # about the monitor's capabilities. | 280 # about the monitor's capabilities. |
270 | 281 |
271 def quit(self): | 282 def quit(self): |
(...skipping 30 matching lines...) Expand all Loading... |
302 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): | 313 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): |
303 """ | 314 """ |
304 Migrate. | 315 Migrate. |
305 | 316 |
306 @param uri: destination URI | 317 @param uri: destination URI |
307 @param full_copy: If true, migrate with full disk copy | 318 @param full_copy: If true, migrate with full disk copy |
308 @param incremental_copy: If true, migrate with incremental disk copy | 319 @param incremental_copy: If true, migrate with incremental disk copy |
309 @param wait: If true, wait for completion | 320 @param wait: If true, wait for completion |
310 @return: The command's output | 321 @return: The command's output |
311 """ | 322 """ |
312 logging.debug("Migrating to: %s" % uri) | |
313 cmd = "migrate" | 323 cmd = "migrate" |
314 if not wait: | 324 if not wait: |
315 cmd += " -d" | 325 cmd += " -d" |
316 if full_copy: | 326 if full_copy: |
317 cmd += " -b" | 327 cmd += " -b" |
318 if incremental_copy: | 328 if incremental_copy: |
319 cmd += " -i" | 329 cmd += " -i" |
320 cmd += " %s" % uri | 330 cmd += " %s" % uri |
321 return self.cmd(cmd) | 331 return self.cmd(cmd) |
322 | 332 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
473 | 483 |
474 def _send(self, data): | 484 def _send(self, data): |
475 """ | 485 """ |
476 Send raw data without waiting for response. | 486 Send raw data without waiting for response. |
477 | 487 |
478 @param data: Data to send | 488 @param data: Data to send |
479 @raise MonitorSocketError: Raised if a socket error occurs | 489 @raise MonitorSocketError: Raised if a socket error occurs |
480 """ | 490 """ |
481 try: | 491 try: |
482 self._socket.sendall(data) | 492 self._socket.sendall(data) |
483 except socket.error, (errno, msg): | 493 except socket.error, e: |
484 raise MonitorSocketError("Could not send data: %r (%s)" % | 494 raise MonitorSocketError("Could not send data: %r" % data, e) |
485 (data, msg)) | |
486 | 495 |
487 | 496 |
488 def _get_response(self, id=None, timeout=20): | 497 def _get_response(self, id=None, timeout=20): |
489 """ | 498 """ |
490 Read a response from the QMP monitor. | 499 Read a response from the QMP monitor. |
491 | 500 |
492 @param id: If not None, look for a response with this id | 501 @param id: If not None, look for a response with this id |
493 @param timeout: Time duration to wait for response | 502 @param timeout: Time duration to wait for response |
494 @return: The response dict, or None if none was found | 503 @return: The response dict, or None if none was found |
495 """ | 504 """ |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
608 @param id: An id for the command, or None | 617 @param id: An id for the command, or None |
609 @param timeout: Time duration to wait for response | 618 @param timeout: Time duration to wait for response |
610 @return: The response received | 619 @return: The response received |
611 @raise MonitorLockError: Raised if the lock cannot be acquired | 620 @raise MonitorLockError: Raised if the lock cannot be acquired |
612 @raise MonitorSocketError: Raised if a socket error occurs | 621 @raise MonitorSocketError: Raised if a socket error occurs |
613 @raise MonitorProtocolError: Raised if no response is received | 622 @raise MonitorProtocolError: Raised if no response is received |
614 """ | 623 """ |
615 return self.cmd_obj(self._build_cmd(cmd, args, id), timeout) | 624 return self.cmd_obj(self._build_cmd(cmd, args, id), timeout) |
616 | 625 |
617 | 626 |
618 def is_responsive(self): | 627 def verify_responsive(self): |
619 """ | 628 """ |
620 Make sure the monitor is responsive by sending a command. | 629 Make sure the monitor is responsive by sending a command. |
621 | |
622 @return: True if responsive, False otherwise | |
623 """ | 630 """ |
624 try: | 631 self.cmd("query-status") |
625 self.cmd("query-status") | |
626 return True | |
627 except MonitorError: | |
628 return False | |
629 | 632 |
630 | 633 |
631 def get_events(self): | 634 def get_events(self): |
632 """ | 635 """ |
633 Return a list of the asynchronous events received since the last | 636 Return a list of the asynchronous events received since the last |
634 clear_events() call. | 637 clear_events() call. |
635 | 638 |
636 @return: A list of events (the objects returned have an "event" key) | 639 @return: A list of events (the objects returned have an "event" key) |
637 @raise MonitorLockError: Raised if the lock cannot be acquired | 640 @raise MonitorLockError: Raised if the lock cannot be acquired |
638 """ | 641 """ |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
732 | 735 |
733 def migrate_set_speed(self, value): | 736 def migrate_set_speed(self, value): |
734 """ | 737 """ |
735 Set maximum speed (in bytes/sec) for migrations. | 738 Set maximum speed (in bytes/sec) for migrations. |
736 | 739 |
737 @param value: Speed in bytes/sec | 740 @param value: Speed in bytes/sec |
738 @return: The response to the command | 741 @return: The response to the command |
739 """ | 742 """ |
740 args = {"value": value} | 743 args = {"value": value} |
741 return self.cmd("migrate_set_speed", args) | 744 return self.cmd("migrate_set_speed", args) |
OLD | NEW |