2 Interfaces to the QEMU monitor.
4 @copyright: 2008-2010 Red Hat Inc.
7 import socket
, time
, threading
, logging
, select
12 logging
.warning("Could not import json module. "
13 "QMP monitor functionality disabled.")
16 class MonitorError(Exception):
20 class MonitorConnectError(MonitorError
):
24 class MonitorSocketError(MonitorError
):
25 def __init__(self
, msg
, e
):
26 Exception.__init
__(self
, msg
, e
)
31 return "%s (%s)" % (self
.msg
, self
.e
)
34 class MonitorLockError(MonitorError
):
38 class MonitorProtocolError(MonitorError
):
42 class MonitorNotSupportedError(MonitorError
):
46 class QMPCmdError(MonitorError
):
47 def __init__(self
, cmd
, qmp_args
, data
):
48 MonitorError
.__init
__(self
, cmd
, qmp_args
, data
)
50 self
.qmp_args
= qmp_args
54 return ("QMP command %r failed (arguments: %r, "
55 "error message: %r)" % (self
.cmd
, self
.qmp_args
, self
.data
))
60 Common code for monitor classes.
63 def __init__(self
, name
, filename
):
65 Initialize the instance.
67 @param name: Monitor identifier (a string)
68 @param filename: Monitor socket filename
69 @raise MonitorConnectError: Raised if the connection fails
72 self
.filename
= filename
73 self
._lock
= threading
.RLock()
74 self
._socket
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_STREAM
)
77 self
._socket
.connect(filename
)
79 raise MonitorConnectError("Could not connect to monitor socket")
83 # Automatically close the connection when the instance is garbage
86 self
._socket
.shutdown(socket
.SHUT_RDWR
)
92 # The following two functions are defined to make sure the state is set
93 # exclusively by the constructor call as specified in __getinitargs__().
95 def __getstate__(self
):
99 def __setstate__(self
, state
):
103 def __getinitargs__(self
):
104 # Save some information when pickling -- will be passed to the
105 # constructor upon unpickling
106 return self
.name
, self
.filename
, True
109 def _acquire_lock(self
, timeout
=20):
110 end_time
= time
.time() + timeout
111 while time
.time() < end_time
:
112 if self
._lock
.acquire(False):
118 def _data_available(self
, timeout
=0):
119 timeout
= max(0, timeout
)
120 return bool(select
.select([self
._socket
], [], [], timeout
)[0])
125 while self
._data
_available
():
127 data
= self
._socket
.recv(1024)
128 except socket
.error
, e
:
129 raise MonitorSocketError("Could not receive data from monitor",
137 def is_responsive(self
):
139 Return True iff the monitor is responsive.
142 self
.verify_responsive()
148 class HumanMonitor(Monitor
):
150 Wraps "human monitor" commands.
153 def __init__(self
, name
, filename
, suppress_exceptions
=False):
155 Connect to the monitor socket and find the (qemu) prompt.
157 @param name: Monitor identifier (a string)
158 @param filename: Monitor socket filename
159 @raise MonitorConnectError: Raised if the connection fails and
160 suppress_exceptions is False
161 @raise MonitorProtocolError: Raised if the initial (qemu) prompt isn't
162 found and suppress_exceptions is False
163 @note: Other exceptions may be raised. See cmd()'s
167 Monitor
.__init
__(self
, name
, filename
)
169 self
.protocol
= "human"
171 # Find the initial (qemu) prompt
172 s
, o
= self
._read
_up
_to
_qemu
_prompt
(20)
174 raise MonitorProtocolError("Could not find (qemu) prompt "
175 "after connecting to monitor. "
176 "Output so far: %r" % o
)
178 # Save the output of 'help' for future use
179 self
._help
_str
= self
.cmd("help", debug
=False)
181 except MonitorError
, e
:
182 if suppress_exceptions
:
190 def _read_up_to_qemu_prompt(self
, timeout
=20):
192 end_time
= time
.time() + timeout
193 while self
._data
_available
(end_time
- time
.time()):
194 data
= self
._recvall
()
199 if s
.splitlines()[-1].split()[-1] == "(qemu)":
200 return True, "\n".join(s
.splitlines()[:-1])
203 return False, "\n".join(s
.splitlines())
206 def _send(self
, cmd
):
208 Send a command without waiting for output.
210 @param cmd: Command to send
211 @raise MonitorLockError: Raised if the lock cannot be acquired
212 @raise MonitorSocketError: Raised if a socket error occurs
214 if not self
._acquire
_lock
(20):
215 raise MonitorLockError("Could not acquire exclusive lock to send "
216 "monitor command '%s'" % cmd
)
220 self
._socket
.sendall(cmd
+ "\n")
221 except socket
.error
, e
:
222 raise MonitorSocketError("Could not send monitor command %r" %
231 def cmd(self
, command
, timeout
=20, debug
=True):
233 Send command 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
237 @param debug: Whether to print the commands being sent and responses
238 @return: Output received from the monitor
239 @raise MonitorLockError: Raised if the lock cannot be acquired
240 @raise MonitorSocketError: Raised if a socket error occurs
241 @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be
242 found after sending the command
245 logging
.debug("(monitor %s) Sending command '%s'",
247 if not self
._acquire
_lock
(20):
248 raise MonitorLockError("Could not acquire exclusive lock to send "
249 "monitor command '%s'" % command
)
252 # Read any data that might be available
257 s
, o
= self
._read
_up
_to
_qemu
_prompt
(timeout
)
258 # Remove command echo from output
259 o
= "\n".join(o
.splitlines()[1:])
260 # Report success/failure
263 logging
.debug("(monitor %s) "
264 "Response to '%s'", self
.name
,
266 for l
in o
.splitlines():
267 logging
.debug("(monitor %s) %s", self
.name
, l
)
270 msg
= ("Could not find (qemu) prompt after command '%s'. "
271 "Output so far: %r" % (command
, o
))
272 raise MonitorProtocolError(msg
)
278 def verify_responsive(self
):
280 Make sure the monitor is responsive by sending a command.
282 self
.cmd("info status", debug
=False)
285 def verify_status(self
, status
):
289 @param status: Optional VM status, 'running' or 'paused'
290 @return: return True if VM status is same as we expected
292 o
= self
.cmd("info status", debug
=False)
293 if status
=='paused' or status
=='running':
299 # - All of the following commands raise exceptions in a similar manner to
301 # - A command wrapper should use self._help_str if it requires information
302 # about the monitor's capabilities.
306 Send "quit" without waiting for output.
311 def info(self
, what
):
313 Request info about something and return the output.
315 return self
.cmd("info %s" % what
)
318 def query(self
, what
):
322 return self
.info(what
)
325 def screendump(self
, filename
, debug
=True):
327 Request a screendump.
329 @param filename: Location for the screendump
330 @return: The command's output
332 return self
.cmd(command
="screendump %s" % filename
, debug
=debug
)
335 def migrate(self
, uri
, full_copy
=False, incremental_copy
=False, wait
=False):
339 @param uri: destination URI
340 @param full_copy: If true, migrate with full disk copy
341 @param incremental_copy: If true, migrate with incremental disk copy
342 @param wait: If true, wait for completion
343 @return: The command's output
356 def migrate_set_speed(self
, value
):
358 Set maximum speed (in bytes/sec) for migrations.
360 @param value: Speed in bytes/sec
361 @return: The command's output
363 return self
.cmd("migrate_set_speed %s" % value
)
366 def sendkey(self
, keystr
, hold_time
=1):
368 Send key combination to VM.
370 @param keystr: Key combination string
371 @param hold_time: Hold time in ms (should normally stay 1 ms)
372 @return: The command's output
374 return self
.cmd("sendkey %s %s" % (keystr
, hold_time
))
377 def mouse_move(self
, dx
, dy
):
383 @return: The command's output
385 return self
.cmd("mouse_move %d %d" % (dx
, dy
))
388 def mouse_button(self
, state
):
390 Set mouse button state.
392 @param state: Button state (1=L, 2=M, 4=R)
393 @return: The command's output
395 return self
.cmd("mouse_button %d" % state
)
398 class QMPMonitor(Monitor
):
400 Wraps QMP monitor commands.
403 def __init__(self
, name
, filename
, suppress_exceptions
=False):
405 Connect to the monitor socket, read the greeting message and issue the
406 qmp_capabilities command. Also make sure the json module is available.
408 @param name: Monitor identifier (a string)
409 @param filename: Monitor socket filename
410 @raise MonitorConnectError: Raised if the connection fails and
411 suppress_exceptions is False
412 @raise MonitorProtocolError: Raised if the no QMP greeting message is
413 received and suppress_exceptions is False
414 @raise MonitorNotSupportedError: Raised if json isn't available and
415 suppress_exceptions is False
416 @note: Other exceptions may be raised if the qmp_capabilities command
417 fails. See cmd()'s docstring.
420 Monitor
.__init
__(self
, name
, filename
)
422 self
.protocol
= "qmp"
423 self
._greeting
= None
426 # Make sure json is available
430 raise MonitorNotSupportedError("QMP requires the json module "
431 "(Python 2.6 and up)")
433 # Read greeting message
434 end_time
= time
.time() + 20
435 while time
.time() < end_time
:
436 for obj
in self
._read
_objects
():
444 raise MonitorProtocolError("No QMP greeting message received")
446 # Issue qmp_capabilities
447 self
.cmd("qmp_capabilities")
449 except MonitorError
, e
:
450 if suppress_exceptions
:
458 def _build_cmd(self
, cmd
, args
=None, id=None):
459 obj
= {"execute": cmd
}
461 obj
["arguments"] = args
467 def _read_objects(self
, timeout
=5):
469 Read lines from the monitor and try to decode them.
470 Stop when all available lines have been successfully decoded, or when
471 timeout expires. If any decoded objects are asynchronous events, store
472 them in self._events. Return all decoded objects.
474 @param timeout: Time to wait for all lines to decode successfully
475 @return: A list of objects
477 if not self
._data
_available
():
480 end_time
= time
.time() + timeout
481 while self
._data
_available
(end_time
- time
.time()):
483 # Make sure all lines are decodable
484 for line
in s
.splitlines():
489 # Found an incomplete or broken line -- keep reading
492 # All lines are OK -- stop reading
494 # Decode all decodable lines
496 for line
in s
.splitlines():
498 objs
+= [json
.loads(line
)]
501 # Keep track of asynchronous events
502 self
._events
+= [obj
for obj
in objs
if "event" in obj
]
506 def _send(self
, data
):
508 Send raw data without waiting for response.
510 @param data: Data to send
511 @raise MonitorSocketError: Raised if a socket error occurs
514 self
._socket
.sendall(data
)
515 except socket
.error
, e
:
516 raise MonitorSocketError("Could not send data: %r" % data
, e
)
519 def _get_response(self
, id=None, timeout
=20):
521 Read a response from the QMP monitor.
523 @param id: If not None, look for a response with this id
524 @param timeout: Time duration to wait for response
525 @return: The response dict, or None if none was found
527 end_time
= time
.time() + timeout
528 while self
._data
_available
(end_time
- time
.time()):
529 for obj
in self
._read
_objects
():
530 if isinstance(obj
, dict):
531 if id is not None and obj
.get("id") != id:
533 if "return" in obj
or "error" in obj
:
539 def cmd(self
, cmd
, args
=None, timeout
=20, debug
=True):
541 Send a QMP monitor command and return the response.
543 Note: an id is automatically assigned to the command and the response
544 is checked for the presence of the same id.
546 @param cmd: Command to send
547 @param args: A dict containing command arguments, or None
548 @param timeout: Time duration to wait for response
549 @return: The response received
550 @raise MonitorLockError: Raised if the lock cannot be acquired
551 @raise MonitorSocketError: Raised if a socket error occurs
552 @raise MonitorProtocolError: Raised if no response is received
553 @raise QMPCmdError: Raised if the response is an error message
554 (the exception's args are (cmd, args, data) where data is the
558 logging
.debug("(monitor %s) Sending command '%s'",
560 if not self
._acquire
_lock
(20):
561 raise MonitorLockError("Could not acquire exclusive lock to send "
562 "QMP command '%s'" % cmd
)
565 # Read any data that might be available
568 id = virt_utils
.generate_random_string(8)
569 self
._send
(json
.dumps(self
._build
_cmd
(cmd
, args
, id)) + "\n")
571 r
= self
._get
_response
(id, timeout
)
573 raise MonitorProtocolError("Received no response to QMP "
574 "command '%s', or received a "
575 "response with an incorrect id"
578 if debug
and r
["return"]:
579 logging
.debug("(monitor %s) "
580 "Response to '%s'", self
.name
, cmd
)
582 for l
in o
.splitlines():
583 logging
.debug("(monitor %s) %s", self
.name
, l
)
586 raise QMPCmdError(cmd
, args
, r
["error"])
592 def cmd_raw(self
, data
, timeout
=20):
594 Send a raw string to the QMP monitor and return the response.
595 Unlike cmd(), return the raw response dict without performing any
598 @param data: The data to send
599 @param timeout: Time duration to wait for response
600 @return: The response received
601 @raise MonitorLockError: Raised if the lock cannot be acquired
602 @raise MonitorSocketError: Raised if a socket error occurs
603 @raise MonitorProtocolError: Raised if no response is received
605 if not self
._acquire
_lock
(20):
606 raise MonitorLockError("Could not acquire exclusive lock to send "
612 r
= self
._get
_response
(None, timeout
)
614 raise MonitorProtocolError("Received no response to data: %r" %
622 def cmd_obj(self
, obj
, timeout
=20):
624 Transform a Python object to JSON, send the resulting string to the QMP
625 monitor, and return the response.
626 Unlike cmd(), return the raw response dict without performing any
629 @param obj: The object to send
630 @param timeout: Time duration to wait for response
631 @return: The response received
632 @raise MonitorLockError: Raised if the lock cannot be acquired
633 @raise MonitorSocketError: Raised if a socket error occurs
634 @raise MonitorProtocolError: Raised if no response is received
636 return self
.cmd_raw(json
.dumps(obj
) + "\n")
639 def cmd_qmp(self
, cmd
, args
=None, id=None, timeout
=20):
641 Build a QMP command from the passed arguments, send it to the monitor
642 and return the response.
643 Unlike cmd(), return the raw response dict without performing any
646 @param cmd: Command to send
647 @param args: A dict containing command arguments, or None
648 @param id: An id for the command, or None
649 @param timeout: Time duration to wait for response
650 @return: The response received
651 @raise MonitorLockError: Raised if the lock cannot be acquired
652 @raise MonitorSocketError: Raised if a socket error occurs
653 @raise MonitorProtocolError: Raised if no response is received
655 return self
.cmd_obj(self
._build
_cmd
(cmd
, args
, id), timeout
)
658 def verify_responsive(self
):
660 Make sure the monitor is responsive by sending a command.
662 self
.cmd(cmd
="query-status", debug
=False)
665 def verify_status(self
, status
):
669 @param status: Optional VM status, 'running' or 'paused'
670 @return: return True if VM status is same as we expected
672 o
= str(self
.cmd(cmd
="query-status", debug
=False))
673 if (status
=='paused' and "u'running': False" in o
):
675 if (status
=='running' and "u'running': True" in o
):
679 def get_events(self
):
681 Return a list of the asynchronous events received since the last
684 @return: A list of events (the objects returned have an "event" key)
685 @raise MonitorLockError: Raised if the lock cannot be acquired
687 if not self
._acquire
_lock
(20):
688 raise MonitorLockError("Could not acquire exclusive lock to read "
692 return self
._events
[:]
697 def get_event(self
, name
):
699 Look for an event with the given name in the list of events.
701 @param name: The name of the event to look for (e.g. 'RESET')
702 @return: An event object or None if none is found
704 for e
in self
.get_events():
705 if e
.get("event") == name
:
709 def clear_events(self
):
711 Clear the list of asynchronous events.
713 @raise MonitorLockError: Raised if the lock cannot be acquired
715 if not self
._acquire
_lock
(20):
716 raise MonitorLockError("Could not acquire exclusive lock to clear "
722 def get_greeting(self
):
724 Return QMP greeting message.
726 return self
._greeting
730 # Note: all of the following functions raise exceptions in a similar manner
735 Send "quit" and return the response.
737 return self
.cmd("quit")
740 def info(self
, what
):
742 Request info about something and return the response.
744 return self
.cmd("query-%s" % what
)
747 def query(self
, what
):
751 return self
.info(what
)
754 def screendump(self
, filename
, debug
=True):
756 Request a screendump.
758 @param filename: Location for the screendump
759 @return: The response to the command
761 args
= {"filename": filename
}
762 return self
.cmd(cmd
="screendump", args
=args
, debug
=debug
)
765 def migrate(self
, uri
, full_copy
=False, incremental_copy
=False, wait
=False):
769 @param uri: destination URI
770 @param full_copy: If true, migrate with full disk copy
771 @param incremental_copy: If true, migrate with incremental disk copy
772 @param wait: If true, wait for completion
773 @return: The response to the command
777 "inc": incremental_copy
}
778 return self
.cmd("migrate", args
)
781 def migrate_set_speed(self
, value
):
783 Set maximum speed (in bytes/sec) for migrations.
785 @param value: Speed in bytes/sec
786 @return: The response to the command
788 args
= {"value": value
}
789 return self
.cmd("migrate_set_speed", args
)