Statistics
| Branch: | Revision:

root / QMP / qmp.py @ 9bed0d0d

History | View | Annotate | Download (3.7 kB)

1 cedebdac Luiz Capitulino
# QEMU Monitor Protocol Python class
2 cedebdac Luiz Capitulino
# 
3 1d00a07d Luiz Capitulino
# Copyright (C) 2009, 2010 Red Hat Inc.
4 cedebdac Luiz Capitulino
#
5 cedebdac Luiz Capitulino
# Authors:
6 cedebdac Luiz Capitulino
#  Luiz Capitulino <lcapitulino@redhat.com>
7 cedebdac Luiz Capitulino
#
8 cedebdac Luiz Capitulino
# This work is licensed under the terms of the GNU GPL, version 2.  See
9 cedebdac Luiz Capitulino
# the COPYING file in the top-level directory.
10 cedebdac Luiz Capitulino
11 1d00a07d Luiz Capitulino
import json
12 1d00a07d Luiz Capitulino
import errno
13 1d00a07d Luiz Capitulino
import socket
14 cedebdac Luiz Capitulino
15 cedebdac Luiz Capitulino
class QMPError(Exception):
16 cedebdac Luiz Capitulino
    pass
17 cedebdac Luiz Capitulino
18 cedebdac Luiz Capitulino
class QMPConnectError(QMPError):
19 cedebdac Luiz Capitulino
    pass
20 cedebdac Luiz Capitulino
21 1d00a07d Luiz Capitulino
class QMPCapabilitiesError(QMPError):
22 1d00a07d Luiz Capitulino
    pass
23 1d00a07d Luiz Capitulino
24 cedebdac Luiz Capitulino
class QEMUMonitorProtocol:
25 1d00a07d Luiz Capitulino
    def __init__(self, address):
26 1d00a07d Luiz Capitulino
        """
27 1d00a07d Luiz Capitulino
        Create a QEMUMonitorProtocol class.
28 1d00a07d Luiz Capitulino

29 1d00a07d Luiz Capitulino
        @param address: QEMU address, can be either a unix socket path (string)
30 1d00a07d Luiz Capitulino
                        or a tuple in the form ( address, port ) for a TCP
31 1d00a07d Luiz Capitulino
                        connection
32 1d00a07d Luiz Capitulino
        @note No connection is established, this is done by the connect() method
33 1d00a07d Luiz Capitulino
        """
34 1d00a07d Luiz Capitulino
        self.__events = []
35 1d00a07d Luiz Capitulino
        self.__address = address
36 1d00a07d Luiz Capitulino
        self.__sock = self.__get_sock()
37 1d00a07d Luiz Capitulino
        self.__sockfile = self.__sock.makefile()
38 1d00a07d Luiz Capitulino
39 1d00a07d Luiz Capitulino
    def __get_sock(self):
40 1d00a07d Luiz Capitulino
        if isinstance(self.__address, tuple):
41 1d00a07d Luiz Capitulino
            family = socket.AF_INET
42 1d00a07d Luiz Capitulino
        else:
43 1d00a07d Luiz Capitulino
            family = socket.AF_UNIX
44 1d00a07d Luiz Capitulino
        return socket.socket(family, socket.SOCK_STREAM)
45 1d00a07d Luiz Capitulino
46 1d00a07d Luiz Capitulino
    def __json_read(self):
47 1d00a07d Luiz Capitulino
        while True:
48 1d00a07d Luiz Capitulino
            data = self.__sockfile.readline()
49 1d00a07d Luiz Capitulino
            if not data:
50 1d00a07d Luiz Capitulino
                return
51 1d00a07d Luiz Capitulino
            resp = json.loads(data)
52 1d00a07d Luiz Capitulino
            if 'event' in resp:
53 1d00a07d Luiz Capitulino
                self.__events.append(resp)
54 1d00a07d Luiz Capitulino
                continue
55 1d00a07d Luiz Capitulino
            return resp
56 1d00a07d Luiz Capitulino
57 1d00a07d Luiz Capitulino
    error = socket.error
58 1d00a07d Luiz Capitulino
59 cedebdac Luiz Capitulino
    def connect(self):
60 1d00a07d Luiz Capitulino
        """
61 1d00a07d Luiz Capitulino
        Connect to the QMP Monitor and perform capabilities negotiation.
62 1d00a07d Luiz Capitulino

63 1d00a07d Luiz Capitulino
        @return QMP greeting dict
64 1d00a07d Luiz Capitulino
        @raise socket.error on socket connection errors
65 1d00a07d Luiz Capitulino
        @raise QMPConnectError if the greeting is not received
66 1d00a07d Luiz Capitulino
        @raise QMPCapabilitiesError if fails to negotiate capabilities
67 1d00a07d Luiz Capitulino
        """
68 1d00a07d Luiz Capitulino
        self.__sock.connect(self.__address)
69 1d00a07d Luiz Capitulino
        greeting = self.__json_read()
70 1d00a07d Luiz Capitulino
        if greeting is None or not greeting.has_key('QMP'):
71 cedebdac Luiz Capitulino
            raise QMPConnectError
72 1d00a07d Luiz Capitulino
        # Greeting seems ok, negotiate capabilities
73 1d00a07d Luiz Capitulino
        resp = self.cmd('qmp_capabilities')
74 1d00a07d Luiz Capitulino
        if "return" in resp:
75 1d00a07d Luiz Capitulino
            return greeting
76 1d00a07d Luiz Capitulino
        raise QMPCapabilitiesError
77 cedebdac Luiz Capitulino
78 1d00a07d Luiz Capitulino
    def cmd_obj(self, qmp_cmd):
79 1d00a07d Luiz Capitulino
        """
80 1d00a07d Luiz Capitulino
        Send a QMP command to the QMP Monitor.
81 cedebdac Luiz Capitulino

82 1d00a07d Luiz Capitulino
        @param qmp_cmd: QMP command to be sent as a Python dict
83 1d00a07d Luiz Capitulino
        @return QMP response as a Python dict or None if the connection has
84 1d00a07d Luiz Capitulino
                been closed
85 1d00a07d Luiz Capitulino
        """
86 1d00a07d Luiz Capitulino
        try:
87 1d00a07d Luiz Capitulino
            self.__sock.sendall(json.dumps(qmp_cmd))
88 1d00a07d Luiz Capitulino
        except socket.error, err:
89 1d00a07d Luiz Capitulino
            if err[0] == errno.EPIPE:
90 1d00a07d Luiz Capitulino
                return
91 1d00a07d Luiz Capitulino
            raise socket.error(err)
92 cedebdac Luiz Capitulino
        return self.__json_read()
93 cedebdac Luiz Capitulino
94 1d00a07d Luiz Capitulino
    def cmd(self, name, args=None, id=None):
95 1d00a07d Luiz Capitulino
        """
96 1d00a07d Luiz Capitulino
        Build a QMP command and send it to the QMP Monitor.
97 cedebdac Luiz Capitulino

98 1d00a07d Luiz Capitulino
        @param name: command name (string)
99 1d00a07d Luiz Capitulino
        @param args: command arguments (dict)
100 1d00a07d Luiz Capitulino
        @param id: command id (dict, list, string or int)
101 1d00a07d Luiz Capitulino
        """
102 1d00a07d Luiz Capitulino
        qmp_cmd = { 'execute': name }
103 1d00a07d Luiz Capitulino
        if args:
104 1d00a07d Luiz Capitulino
            qmp_cmd['arguments'] = args
105 1d00a07d Luiz Capitulino
        if id:
106 1d00a07d Luiz Capitulino
            qmp_cmd['id'] = id
107 1d00a07d Luiz Capitulino
        return self.cmd_obj(qmp_cmd)
108 1d00a07d Luiz Capitulino
109 1d00a07d Luiz Capitulino
    def get_events(self):
110 1d00a07d Luiz Capitulino
        """
111 1d00a07d Luiz Capitulino
        Get a list of available QMP events.
112 1d00a07d Luiz Capitulino
        """
113 1d00a07d Luiz Capitulino
        self.__sock.setblocking(0)
114 cedebdac Luiz Capitulino
        try:
115 1d00a07d Luiz Capitulino
            self.__json_read()
116 1d00a07d Luiz Capitulino
        except socket.error, err:
117 1d00a07d Luiz Capitulino
            if err[0] == errno.EAGAIN:
118 1d00a07d Luiz Capitulino
                # No data available
119 1d00a07d Luiz Capitulino
                pass
120 1d00a07d Luiz Capitulino
        self.__sock.setblocking(1)
121 1d00a07d Luiz Capitulino
        return self.__events
122 1d00a07d Luiz Capitulino
123 1d00a07d Luiz Capitulino
    def clear_events(self):
124 1d00a07d Luiz Capitulino
        """
125 1d00a07d Luiz Capitulino
        Clear current list of pending events.
126 1d00a07d Luiz Capitulino
        """
127 1d00a07d Luiz Capitulino
        self.__events = []
128 1d00a07d Luiz Capitulino
129 1d00a07d Luiz Capitulino
    def close(self):
130 1d00a07d Luiz Capitulino
        self.__sock.close()
131 1d00a07d Luiz Capitulino
        self.__sockfile.close()