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