1""" 2Interfaces to the QEMU monitor. 3 4@copyright: 2008-2010 Red Hat Inc. 5""" 6 7import socket, time, threading, logging, select 8import virt_utils 9try: 10 import json 11except ImportError: 12 logging.warning("Could not import json module. " 13 "QMP monitor functionality disabled.") 14 15 16class MonitorError(Exception): 17 pass 18 19 20class MonitorConnectError(MonitorError): 21 pass 22 23 24class MonitorSocketError(MonitorError): 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) 32 33 34class MonitorLockError(MonitorError): 35 pass 36 37 38class MonitorProtocolError(MonitorError): 39 pass 40 41 42class MonitorNotSupportedError(MonitorError): 43 pass 44 45 46class QMPCmdError(MonitorError): 47 def __init__(self, cmd, qmp_args, data): 48 MonitorError.__init__(self, cmd, qmp_args, data) 49 self.cmd = cmd 50 self.qmp_args = qmp_args 51 self.data = data 52 53 def __str__(self): 54 return ("QMP command %r failed (arguments: %r, " 55 "error message: %r)" % (self.cmd, self.qmp_args, self.data)) 56 57 58class Monitor: 59 """ 60 Common code for monitor classes. 61 """ 62 63 def __init__(self, name, filename): 64 """ 65 Initialize the instance. 66 67 @param name: Monitor identifier (a string) 68 @param filename: Monitor socket filename 69 @raise MonitorConnectError: Raised if the connection fails 70 """ 71 self.name = name 72 self.filename = filename 73 self._lock = threading.RLock() 74 self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 75 76 try: 77 self._socket.connect(filename) 78 except socket.error: 79 raise MonitorConnectError("Could not connect to monitor socket") 80 81 82 def __del__(self): 83 # Automatically close the connection when the instance is garbage 84 # collected 85 self._close_sock() 86 87 88 # The following two functions are defined to make sure the state is set 89 # exclusively by the constructor call as specified in __getinitargs__(). 90 91 def __getstate__(self): 92 pass 93 94 95 def __setstate__(self, state): 96 pass 97 98 99 def __getinitargs__(self): 100 # Save some information when pickling -- will be passed to the 101 # constructor upon unpickling 102 return self.name, self.filename, True 103 104 105 def _close_sock(self): 106 try: 107 self._socket.shutdown(socket.SHUT_RDWR) 108 except socket.error: 109 pass 110 self._socket.close() 111 112 def _acquire_lock(self, timeout=20): 113 end_time = time.time() + timeout 114 while time.time() < end_time: 115 if self._lock.acquire(False): 116 return True 117 time.sleep(0.05) 118 return False 119 120 121 def _data_available(self, timeout=0): 122 timeout = max(0, timeout) 123 try: 124 return bool(select.select([self._socket], [], [], timeout)[0]) 125 except socket.error, e: 126 raise MonitorSocketError("Verifying data on monitor socket", e) 127 128 129 def _recvall(self): 130 s = "" 131 while self._data_available(): 132 try: 133 data = self._socket.recv(1024) 134 except socket.error, e: 135 raise MonitorSocketError("Could not receive data from monitor", 136 e) 137 if not data: 138 break 139 s += data 140 return s 141 142 143 def is_responsive(self): 144 """ 145 Return True iff the monitor is responsive. 146 """ 147 try: 148 self.verify_responsive() 149 return True 150 except MonitorError: 151 return False 152 153 154class HumanMonitor(Monitor): 155 """ 156 Wraps "human monitor" commands. 157 """ 158 159 def __init__(self, name, filename, suppress_exceptions=False): 160 """ 161 Connect to the monitor socket and find the (qemu) prompt. 162 163 @param name: Monitor identifier (a string) 164 @param filename: Monitor socket filename 165 @raise MonitorConnectError: Raised if the connection fails and 166 suppress_exceptions is False 167 @raise MonitorProtocolError: Raised if the initial (qemu) prompt isn't 168 found and suppress_exceptions is False 169 @note: Other exceptions may be raised. See cmd()'s 170 docstring. 171 """ 172 try: 173 Monitor.__init__(self, name, filename) 174 175 self.protocol = "human" 176 177 # Find the initial (qemu) prompt 178 s, o = self._read_up_to_qemu_prompt(20) 179 if not s: 180 raise MonitorProtocolError("Could not find (qemu) prompt " 181 "after connecting to monitor. " 182 "Output so far: %r" % o) 183 184 # Save the output of 'help' for future use 185 self._help_str = self.cmd("help", debug=False) 186 187 except MonitorError, e: 188 self._close_sock() 189 if suppress_exceptions: 190 logging.warning(e) 191 else: 192 raise 193 194 195 # Private methods 196 197 def _read_up_to_qemu_prompt(self, timeout=20): 198 s = "" 199 end_time = time.time() + timeout 200 while self._data_available(end_time - time.time()): 201 data = self._recvall() 202 if not data: 203 break 204 s += data 205 try: 206 if s.splitlines()[-1].split()[-1] == "(qemu)": 207 return True, "\n".join(s.splitlines()[:-1]) 208 except IndexError: 209 continue 210 return False, "\n".join(s.splitlines()) 211 212 213 def _send(self, cmd): 214 """ 215 Send a command without waiting for output. 216 217 @param cmd: Command to send 218 @raise MonitorLockError: Raised if the lock cannot be acquired 219 @raise MonitorSocketError: Raised if a socket error occurs 220 """ 221 if not self._acquire_lock(20): 222 raise MonitorLockError("Could not acquire exclusive lock to send " 223 "monitor command '%s'" % cmd) 224 225 try: 226 try: 227 self._socket.sendall(cmd + "\n") 228 except socket.error, e: 229 raise MonitorSocketError("Could not send monitor command %r" % 230 cmd, e) 231 232 finally: 233 self._lock.release() 234 235 236 # Public methods 237 238 def cmd(self, command, timeout=20, debug=True): 239 """ 240 Send command to the monitor. 241 242 @param command: Command to send to the monitor 243 @param timeout: Time duration to wait for the (qemu) prompt to return 244 @param debug: Whether to print the commands being sent and responses 245 @return: Output received from the monitor 246 @raise MonitorLockError: Raised if the lock cannot be acquired 247 @raise MonitorSocketError: Raised if a socket error occurs 248 @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be 249 found after sending the command 250 """ 251 if debug: 252 logging.debug("(monitor %s) Sending command '%s'", 253 self.name, command) 254 if not self._acquire_lock(20): 255 raise MonitorLockError("Could not acquire exclusive lock to send " 256 "monitor command '%s'" % command) 257 258 try: 259 # Read any data that might be available 260 self._recvall() 261 # Send command 262 self._send(command) 263 # Read output 264 s, o = self._read_up_to_qemu_prompt(timeout) 265 # Remove command echo from output 266 o = "\n".join(o.splitlines()[1:]) 267 # Report success/failure 268 if s: 269 if debug and o: 270 logging.debug("(monitor %s) " 271 "Response to '%s'", self.name, 272 command) 273 for l in o.splitlines(): 274 logging.debug("(monitor %s) %s", self.name, l) 275 return o 276 else: 277 msg = ("Could not find (qemu) prompt after command '%s'. " 278 "Output so far: %r" % (command, o)) 279 raise MonitorProtocolError(msg) 280 281 finally: 282 self._lock.release() 283 284 285 def verify_responsive(self): 286 """ 287 Make sure the monitor is responsive by sending a command. 288 """ 289 self.cmd("info status", debug=False) 290 291 292 def verify_status(self, status): 293 """ 294 Verify VM status 295 296 @param status: Optional VM status, 'running' or 'paused' 297 @return: return True if VM status is same as we expected 298 """ 299 o = self.cmd("info status", debug=False) 300 if status=='paused' or status=='running': 301 return (status in o) 302 303 304 # Command wrappers 305 # Notes: 306 # - All of the following commands raise exceptions in a similar manner to 307 # cmd(). 308 # - A command wrapper should use self._help_str if it requires information 309 # about the monitor's capabilities. 310 311 def quit(self): 312 """ 313 Send "quit" without waiting for output. 314 """ 315 self._send("quit") 316 317 318 def info(self, what): 319 """ 320 Request info about something and return the output. 321 """ 322 return self.cmd("info %s" % what) 323 324 325 def query(self, what): 326 """ 327 Alias for info. 328 """ 329 return self.info(what) 330 331 332 def screendump(self, filename, debug=True): 333 """ 334 Request a screendump. 335 336 @param filename: Location for the screendump 337 @return: The command's output 338 """ 339 return self.cmd(command="screendump %s" % filename, debug=debug) 340 341 342 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): 343 """ 344 Migrate. 345 346 @param uri: destination URI 347 @param full_copy: If true, migrate with full disk copy 348 @param incremental_copy: If true, migrate with incremental disk copy 349 @param wait: If true, wait for completion 350 @return: The command's output 351 """ 352 cmd = "migrate" 353 if not wait: 354 cmd += " -d" 355 if full_copy: 356 cmd += " -b" 357 if incremental_copy: 358 cmd += " -i" 359 cmd += " %s" % uri 360 return self.cmd(cmd) 361 362 363 def migrate_set_speed(self, value): 364 """ 365 Set maximum speed (in bytes/sec) for migrations. 366 367 @param value: Speed in bytes/sec 368 @return: The command's output 369 """ 370 return self.cmd("migrate_set_speed %s" % value) 371 372 373 def sendkey(self, keystr, hold_time=1): 374 """ 375 Send key combination to VM. 376 377 @param keystr: Key combination string 378 @param hold_time: Hold time in ms (should normally stay 1 ms) 379 @return: The command's output 380 """ 381 return self.cmd("sendkey %s %s" % (keystr, hold_time)) 382 383 384 def mouse_move(self, dx, dy): 385 """ 386 Move mouse. 387 388 @param dx: X amount 389 @param dy: Y amount 390 @return: The command's output 391 """ 392 return self.cmd("mouse_move %d %d" % (dx, dy)) 393 394 395 def mouse_button(self, state): 396 """ 397 Set mouse button state. 398 399 @param state: Button state (1=L, 2=M, 4=R) 400 @return: The command's output 401 """ 402 return self.cmd("mouse_button %d" % state) 403 404 405class QMPMonitor(Monitor): 406 """ 407 Wraps QMP monitor commands. 408 """ 409 410 def __init__(self, name, filename, suppress_exceptions=False): 411 """ 412 Connect to the monitor socket, read the greeting message and issue the 413 qmp_capabilities command. Also make sure the json module is available. 414 415 @param name: Monitor identifier (a string) 416 @param filename: Monitor socket filename 417 @raise MonitorConnectError: Raised if the connection fails and 418 suppress_exceptions is False 419 @raise MonitorProtocolError: Raised if the no QMP greeting message is 420 received and suppress_exceptions is False 421 @raise MonitorNotSupportedError: Raised if json isn't available and 422 suppress_exceptions is False 423 @note: Other exceptions may be raised if the qmp_capabilities command 424 fails. See cmd()'s docstring. 425 """ 426 try: 427 Monitor.__init__(self, name, filename) 428 429 self.protocol = "qmp" 430 self._greeting = None 431 self._events = [] 432 433 # Make sure json is available 434 try: 435 json 436 except NameError: 437 raise MonitorNotSupportedError("QMP requires the json module " 438 "(Python 2.6 and up)") 439 440 # Read greeting message 441 end_time = time.time() + 20 442 while time.time() < end_time: 443 for obj in self._read_objects(): 444 if "QMP" in obj: 445 self._greeting = obj 446 break 447 if self._greeting: 448 break 449 time.sleep(0.1) 450 else: 451 raise MonitorProtocolError("No QMP greeting message received") 452 453 # Issue qmp_capabilities 454 self.cmd("qmp_capabilities") 455 456 except MonitorError, e: 457 self._close_sock() 458 if suppress_exceptions: 459 logging.warning(e) 460 else: 461 raise 462 463 464 # Private methods 465 466 def _build_cmd(self, cmd, args=None, id=None): 467 obj = {"execute": cmd} 468 if args is not None: 469 obj["arguments"] = args 470 if id is not None: 471 obj["id"] = id 472 return obj 473 474 475 def _read_objects(self, timeout=5): 476 """ 477 Read lines from the monitor and try to decode them. 478 Stop when all available lines have been successfully decoded, or when 479 timeout expires. If any decoded objects are asynchronous events, store 480 them in self._events. Return all decoded objects. 481 482 @param timeout: Time to wait for all lines to decode successfully 483 @return: A list of objects 484 """ 485 if not self._data_available(): 486 return [] 487 s = "" 488 end_time = time.time() + timeout 489 while self._data_available(end_time - time.time()): 490 s += self._recvall() 491 # Make sure all lines are decodable 492 for line in s.splitlines(): 493 if line: 494 try: 495 json.loads(line) 496 except: 497 # Found an incomplete or broken line -- keep reading 498 break 499 else: 500 # All lines are OK -- stop reading 501 break 502 # Decode all decodable lines 503 objs = [] 504 for line in s.splitlines(): 505 try: 506 objs += [json.loads(line)] 507 except: 508 pass 509 # Keep track of asynchronous events 510 self._events += [obj for obj in objs if "event" in obj] 511 return objs 512 513 514 def _send(self, data): 515 """ 516 Send raw data without waiting for response. 517 518 @param data: Data to send 519 @raise MonitorSocketError: Raised if a socket error occurs 520 """ 521 try: 522 self._socket.sendall(data) 523 except socket.error, e: 524 raise MonitorSocketError("Could not send data: %r" % data, e) 525 526 527 def _get_response(self, id=None, timeout=20): 528 """ 529 Read a response from the QMP monitor. 530 531 @param id: If not None, look for a response with this id 532 @param timeout: Time duration to wait for response 533 @return: The response dict, or None if none was found 534 """ 535 end_time = time.time() + timeout 536 while self._data_available(end_time - time.time()): 537 for obj in self._read_objects(): 538 if isinstance(obj, dict): 539 if id is not None and obj.get("id") != id: 540 continue 541 if "return" in obj or "error" in obj: 542 return obj 543 544 545 # Public methods 546 547 def cmd(self, cmd, args=None, timeout=20, debug=True): 548 """ 549 Send a QMP monitor command and return the response. 550 551 Note: an id is automatically assigned to the command and the response 552 is checked for the presence of the same id. 553 554 @param cmd: Command to send 555 @param args: A dict containing command arguments, or None 556 @param timeout: Time duration to wait for response 557 @return: The response received 558 @raise MonitorLockError: Raised if the lock cannot be acquired 559 @raise MonitorSocketError: Raised if a socket error occurs 560 @raise MonitorProtocolError: Raised if no response is received 561 @raise QMPCmdError: Raised if the response is an error message 562 (the exception's args are (cmd, args, data) where data is the 563 error data) 564 """ 565 if debug: 566 logging.debug("(monitor %s) Sending command '%s'", 567 self.name, cmd) 568 if not self._acquire_lock(20): 569 raise MonitorLockError("Could not acquire exclusive lock to send " 570 "QMP command '%s'" % cmd) 571 572 try: 573 # Read any data that might be available 574 self._read_objects() 575 # Send command 576 id = virt_utils.generate_random_string(8) 577 self._send(json.dumps(self._build_cmd(cmd, args, id)) + "\n") 578 # Read response 579 r = self._get_response(id, timeout) 580 if r is None: 581 raise MonitorProtocolError("Received no response to QMP " 582 "command '%s', or received a " 583 "response with an incorrect id" 584 % cmd) 585 if "return" in r: 586 if debug and r["return"]: 587 logging.debug("(monitor %s) " 588 "Response to '%s'", self.name, cmd) 589 o = str(r["return"]) 590 for l in o.splitlines(): 591 logging.debug("(monitor %s) %s", self.name, l) 592 return r["return"] 593 if "error" in r: 594 raise QMPCmdError(cmd, args, r["error"]) 595 596 finally: 597 self._lock.release() 598 599 600 def cmd_raw(self, data, timeout=20): 601 """ 602 Send a raw string to the QMP monitor and return the response. 603 Unlike cmd(), return the raw response dict without performing any 604 checks on it. 605 606 @param data: The data to send 607 @param timeout: Time duration to wait for response 608 @return: The response received 609 @raise MonitorLockError: Raised if the lock cannot be acquired 610 @raise MonitorSocketError: Raised if a socket error occurs 611 @raise MonitorProtocolError: Raised if no response is received 612 """ 613 if not self._acquire_lock(20): 614 raise MonitorLockError("Could not acquire exclusive lock to send " 615 "data: %r" % data) 616 617 try: 618 self._read_objects() 619 self._send(data) 620 r = self._get_response(None, timeout) 621 if r is None: 622 raise MonitorProtocolError("Received no response to data: %r" % 623 data) 624 return r 625 626 finally: 627 self._lock.release() 628 629 630 def cmd_obj(self, obj, timeout=20): 631 """ 632 Transform a Python object to JSON, send the resulting string to the QMP 633 monitor, and return the response. 634 Unlike cmd(), return the raw response dict without performing any 635 checks on it. 636 637 @param obj: The object to send 638 @param timeout: Time duration to wait for response 639 @return: The response received 640 @raise MonitorLockError: Raised if the lock cannot be acquired 641 @raise MonitorSocketError: Raised if a socket error occurs 642 @raise MonitorProtocolError: Raised if no response is received 643 """ 644 return self.cmd_raw(json.dumps(obj) + "\n") 645 646 647 def cmd_qmp(self, cmd, args=None, id=None, timeout=20): 648 """ 649 Build a QMP command from the passed arguments, send it to the monitor 650 and return the response. 651 Unlike cmd(), return the raw response dict without performing any 652 checks on it. 653 654 @param cmd: Command to send 655 @param args: A dict containing command arguments, or None 656 @param id: An id for the command, or None 657 @param timeout: Time duration to wait for response 658 @return: The response received 659 @raise MonitorLockError: Raised if the lock cannot be acquired 660 @raise MonitorSocketError: Raised if a socket error occurs 661 @raise MonitorProtocolError: Raised if no response is received 662 """ 663 return self.cmd_obj(self._build_cmd(cmd, args, id), timeout) 664 665 666 def verify_responsive(self): 667 """ 668 Make sure the monitor is responsive by sending a command. 669 """ 670 self.cmd(cmd="query-status", debug=False) 671 672 673 def verify_status(self, status): 674 """ 675 Verify VM status 676 677 @param status: Optional VM status, 'running' or 'paused' 678 @return: return True if VM status is same as we expected 679 """ 680 o = str(self.cmd(cmd="query-status", debug=False)) 681 if (status=='paused' and "u'running': False" in o): 682 return True 683 if (status=='running' and "u'running': True" in o): 684 return True 685 686 687 def get_events(self): 688 """ 689 Return a list of the asynchronous events received since the last 690 clear_events() call. 691 692 @return: A list of events (the objects returned have an "event" key) 693 @raise MonitorLockError: Raised if the lock cannot be acquired 694 """ 695 if not self._acquire_lock(20): 696 raise MonitorLockError("Could not acquire exclusive lock to read " 697 "QMP events") 698 try: 699 self._read_objects() 700 return self._events[:] 701 finally: 702 self._lock.release() 703 704 705 def get_event(self, name): 706 """ 707 Look for an event with the given name in the list of events. 708 709 @param name: The name of the event to look for (e.g. 'RESET') 710 @return: An event object or None if none is found 711 """ 712 for e in self.get_events(): 713 if e.get("event") == name: 714 return e 715 716 717 def clear_events(self): 718 """ 719 Clear the list of asynchronous events. 720 721 @raise MonitorLockError: Raised if the lock cannot be acquired 722 """ 723 if not self._acquire_lock(20): 724 raise MonitorLockError("Could not acquire exclusive lock to clear " 725 "QMP event list") 726 self._events = [] 727 self._lock.release() 728 729 730 def get_greeting(self): 731 """ 732 Return QMP greeting message. 733 """ 734 return self._greeting 735 736 737 # Command wrappers 738 # Note: all of the following functions raise exceptions in a similar manner 739 # to cmd(). 740 741 def quit(self): 742 """ 743 Send "quit" and return the response. 744 """ 745 return self.cmd("quit") 746 747 748 def info(self, what): 749 """ 750 Request info about something and return the response. 751 """ 752 return self.cmd("query-%s" % what) 753 754 755 def query(self, what): 756 """ 757 Alias for info. 758 """ 759 return self.info(what) 760 761 762 def screendump(self, filename, debug=True): 763 """ 764 Request a screendump. 765 766 @param filename: Location for the screendump 767 @return: The response to the command 768 """ 769 args = {"filename": filename} 770 return self.cmd(cmd="screendump", args=args, debug=debug) 771 772 773 def migrate(self, uri, full_copy=False, incremental_copy=False, wait=False): 774 """ 775 Migrate. 776 777 @param uri: destination URI 778 @param full_copy: If true, migrate with full disk copy 779 @param incremental_copy: If true, migrate with incremental disk copy 780 @param wait: If true, wait for completion 781 @return: The response to the command 782 """ 783 args = {"uri": uri, 784 "blk": full_copy, 785 "inc": incremental_copy} 786 return self.cmd("migrate", args) 787 788 789 def migrate_set_speed(self, value): 790 """ 791 Set maximum speed (in bytes/sec) for migrations. 792 793 @param value: Speed in bytes/sec 794 @return: The response to the command 795 """ 796 args = {"value": value} 797 return self.cmd("migrate_set_speed", args) 798