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 |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 self.protocol = "human" | 169 self.protocol = "human" |
170 | 170 |
171 # Find the initial (qemu) prompt | 171 # Find the initial (qemu) prompt |
172 s, o = self._read_up_to_qemu_prompt(20) | 172 s, o = self._read_up_to_qemu_prompt(20) |
173 if not s: | 173 if not s: |
174 raise MonitorProtocolError("Could not find (qemu) prompt " | 174 raise MonitorProtocolError("Could not find (qemu) prompt " |
175 "after connecting to monitor. " | 175 "after connecting to monitor. " |
176 "Output so far: %r" % o) | 176 "Output so far: %r" % o) |
177 | 177 |
178 # Save the output of 'help' for future use | 178 # Save the output of 'help' for future use |
179 self._help_str = self.cmd("help") | 179 self._help_str = self.cmd("help", debug=False) |
180 | 180 |
181 except MonitorError, e: | 181 except MonitorError, e: |
182 if suppress_exceptions: | 182 if suppress_exceptions: |
183 logging.warn(e) | 183 logging.warn(e) |
184 else: | 184 else: |
185 raise | 185 raise |
186 | 186 |
187 | 187 |
188 # Private methods | 188 # Private methods |
189 | 189 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 except socket.error, e: | 221 except socket.error, e: |
222 raise MonitorSocketError("Could not send monitor command %r" % | 222 raise MonitorSocketError("Could not send monitor command %r" % |
223 cmd, e) | 223 cmd, e) |
224 | 224 |
225 finally: | 225 finally: |
226 self._lock.release() | 226 self._lock.release() |
227 | 227 |
228 | 228 |
229 # Public methods | 229 # Public methods |
230 | 230 |
231 def cmd(self, command, timeout=20): | 231 def cmd(self, command, timeout=20, debug=True): |
232 """ | 232 """ |
233 Send command to the monitor. | 233 Send command to the monitor. |
234 | 234 |
235 @param command: Command to send to the monitor | 235 @param command: Command to send to the monitor |
236 @param timeout: Time duration to wait for the (qemu) prompt to return | 236 @param timeout: Time duration to wait for the (qemu) prompt to return |
| 237 @param debug: Whether to print the commands being sent and responses |
237 @return: Output received from the monitor | 238 @return: Output received from the monitor |
238 @raise MonitorLockError: Raised if the lock cannot be acquired | 239 @raise MonitorLockError: Raised if the lock cannot be acquired |
239 @raise MonitorSocketError: Raised if a socket error occurs | 240 @raise MonitorSocketError: Raised if a socket error occurs |
240 @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be | 241 @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be |
241 found after sending the command | 242 found after sending the command |
242 """ | 243 """ |
| 244 if debug: |
| 245 logging.debug("(monitor %s) Sending command '%s'", |
| 246 self.name, command) |
243 if not self._acquire_lock(20): | 247 if not self._acquire_lock(20): |
244 raise MonitorLockError("Could not acquire exclusive lock to send " | 248 raise MonitorLockError("Could not acquire exclusive lock to send " |
245 "monitor command '%s'" % command) | 249 "monitor command '%s'" % command) |
246 | 250 |
247 try: | 251 try: |
248 # Read any data that might be available | 252 # Read any data that might be available |
249 self._recvall() | 253 self._recvall() |
250 # Send command | 254 # Send command |
251 self._send(command) | 255 self._send(command) |
252 # Read output | 256 # Read output |
253 s, o = self._read_up_to_qemu_prompt(timeout) | 257 s, o = self._read_up_to_qemu_prompt(timeout) |
254 # Remove command echo from output | 258 # Remove command echo from output |
255 o = "\n".join(o.splitlines()[1:]) | 259 o = "\n".join(o.splitlines()[1:]) |
256 # Report success/failure | 260 # Report success/failure |
257 if s: | 261 if s: |
| 262 if debug and o: |
| 263 logging.debug("(monitor %s) " |
| 264 "Response to '%s'", self.name, |
| 265 command) |
| 266 for l in o.splitlines(): |
| 267 logging.debug("(monitor %s) %s", self.name, l) |
258 return o | 268 return o |
259 else: | 269 else: |
260 msg = ("Could not find (qemu) prompt after command '%s'. " | 270 msg = ("Could not find (qemu) prompt after command '%s'. " |
261 "Output so far: %r" % (command, o)) | 271 "Output so far: %r" % (command, o)) |
262 raise MonitorProtocolError(msg) | 272 raise MonitorProtocolError(msg) |
263 | 273 |
264 finally: | 274 finally: |
265 self._lock.release() | 275 self._lock.release() |
266 | 276 |
267 | 277 |
268 def verify_responsive(self): | 278 def verify_responsive(self): |
269 """ | 279 """ |
270 Make sure the monitor is responsive by sending a command. | 280 Make sure the monitor is responsive by sending a command. |
271 """ | 281 """ |
272 self.cmd("info status") | 282 self.cmd("info status", debug=False) |
273 | 283 |
274 | 284 |
275 # Command wrappers | 285 # Command wrappers |
276 # Notes: | 286 # Notes: |
277 # - All of the following commands raise exceptions in a similar manner to | 287 # - All of the following commands raise exceptions in a similar manner to |
278 # cmd(). | 288 # cmd(). |
279 # - A command wrapper should use self._help_str if it requires information | 289 # - A command wrapper should use self._help_str if it requires information |
280 # about the monitor's capabilities. | 290 # about the monitor's capabilities. |
281 | 291 |
282 def quit(self): | 292 def quit(self): |
(...skipping 10 matching lines...) Expand all Loading... |
293 return self.cmd("info %s" % what) | 303 return self.cmd("info %s" % what) |
294 | 304 |
295 | 305 |
296 def query(self, what): | 306 def query(self, what): |
297 """ | 307 """ |
298 Alias for info. | 308 Alias for info. |
299 """ | 309 """ |
300 return self.info(what) | 310 return self.info(what) |
301 | 311 |
302 | 312 |
303 def screendump(self, filename): | 313 def screendump(self, filename, debug=True): |
304 """ | 314 """ |
305 Request a screendump. | 315 Request a screendump. |
306 | 316 |
307 @param filename: Location for the screendump | 317 @param filename: Location for the screendump |
308 @return: The command's output | 318 @return: The command's output |
309 """ | 319 """ |
310 return self.cmd("screendump %s" % filename) | 320 return self.cmd(command="screendump %s" % filename, debug=debug) |
311 | 321 |
312 | 322 |
313 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): | 323 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): |
314 """ | 324 """ |
315 Migrate. | 325 Migrate. |
316 | 326 |
317 @param uri: destination URI | 327 @param uri: destination URI |
318 @param full_copy: If true, migrate with full disk copy | 328 @param full_copy: If true, migrate with full disk copy |
319 @param incremental_copy: If true, migrate with incremental disk copy | 329 @param incremental_copy: If true, migrate with incremental disk copy |
320 @param wait: If true, wait for completion | 330 @param wait: If true, wait for completion |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 for obj in self._read_objects(): | 517 for obj in self._read_objects(): |
508 if isinstance(obj, dict): | 518 if isinstance(obj, dict): |
509 if id is not None and obj.get("id") != id: | 519 if id is not None and obj.get("id") != id: |
510 continue | 520 continue |
511 if "return" in obj or "error" in obj: | 521 if "return" in obj or "error" in obj: |
512 return obj | 522 return obj |
513 | 523 |
514 | 524 |
515 # Public methods | 525 # Public methods |
516 | 526 |
517 def cmd(self, cmd, args=None, timeout=20): | 527 def cmd(self, cmd, args=None, timeout=20, debug=True): |
518 """ | 528 """ |
519 Send a QMP monitor command and return the response. | 529 Send a QMP monitor command and return the response. |
520 | 530 |
521 Note: an id is automatically assigned to the command and the response | 531 Note: an id is automatically assigned to the command and the response |
522 is checked for the presence of the same id. | 532 is checked for the presence of the same id. |
523 | 533 |
524 @param cmd: Command to send | 534 @param cmd: Command to send |
525 @param args: A dict containing command arguments, or None | 535 @param args: A dict containing command arguments, or None |
526 @param timeout: Time duration to wait for response | 536 @param timeout: Time duration to wait for response |
527 @return: The response received | 537 @return: The response received |
528 @raise MonitorLockError: Raised if the lock cannot be acquired | 538 @raise MonitorLockError: Raised if the lock cannot be acquired |
529 @raise MonitorSocketError: Raised if a socket error occurs | 539 @raise MonitorSocketError: Raised if a socket error occurs |
530 @raise MonitorProtocolError: Raised if no response is received | 540 @raise MonitorProtocolError: Raised if no response is received |
531 @raise QMPCmdError: Raised if the response is an error message | 541 @raise QMPCmdError: Raised if the response is an error message |
532 (the exception's args are (cmd, args, data) where data is the | 542 (the exception's args are (cmd, args, data) where data is the |
533 error data) | 543 error data) |
534 """ | 544 """ |
| 545 if debug: |
| 546 logging.debug("(monitor %s) Sending command '%s'", |
| 547 self.name, cmd) |
535 if not self._acquire_lock(20): | 548 if not self._acquire_lock(20): |
536 raise MonitorLockError("Could not acquire exclusive lock to send " | 549 raise MonitorLockError("Could not acquire exclusive lock to send " |
537 "QMP command '%s'" % cmd) | 550 "QMP command '%s'" % cmd) |
538 | 551 |
539 try: | 552 try: |
540 # Read any data that might be available | 553 # Read any data that might be available |
541 self._read_objects() | 554 self._read_objects() |
542 # Send command | 555 # Send command |
543 id = kvm_utils.generate_random_string(8) | 556 id = kvm_utils.generate_random_string(8) |
544 self._send(json.dumps(self._build_cmd(cmd, args, id)) + "\n") | 557 self._send(json.dumps(self._build_cmd(cmd, args, id)) + "\n") |
545 # Read response | 558 # Read response |
546 r = self._get_response(id, timeout) | 559 r = self._get_response(id, timeout) |
547 if r is None: | 560 if r is None: |
548 raise MonitorProtocolError("Received no response to QMP " | 561 raise MonitorProtocolError("Received no response to QMP " |
549 "command '%s', or received a " | 562 "command '%s', or received a " |
550 "response with an incorrect id" | 563 "response with an incorrect id" |
551 % cmd) | 564 % cmd) |
552 if "return" in r: | 565 if "return" in r: |
| 566 if debug and r["return"]: |
| 567 logging.debug("(monitor %s) " |
| 568 "Response to '%s'", self.name, cmd) |
| 569 o = str(r["return"]) |
| 570 for l in o.splitlines(): |
| 571 logging.debug("(monitor %s) %s", self.name, l) |
553 return r["return"] | 572 return r["return"] |
554 if "error" in r: | 573 if "error" in r: |
555 raise QMPCmdError(cmd, args, r["error"]) | 574 raise QMPCmdError(cmd, args, r["error"]) |
556 | 575 |
557 finally: | 576 finally: |
558 self._lock.release() | 577 self._lock.release() |
559 | 578 |
560 | 579 |
561 def cmd_raw(self, data, timeout=20): | 580 def cmd_raw(self, data, timeout=20): |
562 """ | 581 """ |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 @raise MonitorSocketError: Raised if a socket error occurs | 640 @raise MonitorSocketError: Raised if a socket error occurs |
622 @raise MonitorProtocolError: Raised if no response is received | 641 @raise MonitorProtocolError: Raised if no response is received |
623 """ | 642 """ |
624 return self.cmd_obj(self._build_cmd(cmd, args, id), timeout) | 643 return self.cmd_obj(self._build_cmd(cmd, args, id), timeout) |
625 | 644 |
626 | 645 |
627 def verify_responsive(self): | 646 def verify_responsive(self): |
628 """ | 647 """ |
629 Make sure the monitor is responsive by sending a command. | 648 Make sure the monitor is responsive by sending a command. |
630 """ | 649 """ |
631 self.cmd("query-status") | 650 self.cmd(cmd="query-status", debug=False) |
632 | 651 |
633 | 652 |
634 def get_events(self): | 653 def get_events(self): |
635 """ | 654 """ |
636 Return a list of the asynchronous events received since the last | 655 Return a list of the asynchronous events received since the last |
637 clear_events() call. | 656 clear_events() call. |
638 | 657 |
639 @return: A list of events (the objects returned have an "event" key) | 658 @return: A list of events (the objects returned have an "event" key) |
640 @raise MonitorLockError: Raised if the lock cannot be acquired | 659 @raise MonitorLockError: Raised if the lock cannot be acquired |
641 """ | 660 """ |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 return self.cmd("query-%s" % what) | 718 return self.cmd("query-%s" % what) |
700 | 719 |
701 | 720 |
702 def query(self, what): | 721 def query(self, what): |
703 """ | 722 """ |
704 Alias for info. | 723 Alias for info. |
705 """ | 724 """ |
706 return self.info(what) | 725 return self.info(what) |
707 | 726 |
708 | 727 |
709 def screendump(self, filename): | 728 def screendump(self, filename, debug=True): |
710 """ | 729 """ |
711 Request a screendump. | 730 Request a screendump. |
712 | 731 |
713 @param filename: Location for the screendump | 732 @param filename: Location for the screendump |
714 @return: The response to the command | 733 @return: The response to the command |
715 """ | 734 """ |
716 args = {"filename": filename} | 735 args = {"filename": filename} |
717 return self.cmd("screendump", args) | 736 return self.cmd(cmd="screendump", args=args, debug=debug) |
718 | 737 |
719 | 738 |
720 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): | 739 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): |
721 """ | 740 """ |
722 Migrate. | 741 Migrate. |
723 | 742 |
724 @param uri: destination URI | 743 @param uri: destination URI |
725 @param full_copy: If true, migrate with full disk copy | 744 @param full_copy: If true, migrate with full disk copy |
726 @param incremental_copy: If true, migrate with incremental disk copy | 745 @param incremental_copy: If true, migrate with incremental disk copy |
727 @param wait: If true, wait for completion | 746 @param wait: If true, wait for completion |
728 @return: The response to the command | 747 @return: The response to the command |
729 """ | 748 """ |
730 args = {"uri": uri, | 749 args = {"uri": uri, |
731 "blk": full_copy, | 750 "blk": full_copy, |
732 "inc": incremental_copy} | 751 "inc": incremental_copy} |
733 return self.cmd("migrate", args) | 752 return self.cmd("migrate", args) |
734 | 753 |
735 | 754 |
736 def migrate_set_speed(self, value): | 755 def migrate_set_speed(self, value): |
737 """ | 756 """ |
738 Set maximum speed (in bytes/sec) for migrations. | 757 Set maximum speed (in bytes/sec) for migrations. |
739 | 758 |
740 @param value: Speed in bytes/sec | 759 @param value: Speed in bytes/sec |
741 @return: The response to the command | 760 @return: The response to the command |
742 """ | 761 """ |
743 args = {"value": value} | 762 args = {"value": value} |
744 return self.cmd("migrate_set_speed", args) | 763 return self.cmd("migrate_set_speed", args) |
OLD | NEW |