Statistics
| Branch: | Revision:

root / scripts / qmp / qmp.py @ 48645123

History | View | Annotate | Download (6 kB)

1 cedebdac Luiz Capitulino
# QEMU Monitor Protocol Python class
2 22f3946b 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 37628f11 Stefan Hajnoczi
    def __init__(self, address, server=False):
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 37628f11 Stefan Hajnoczi
        @param server: server mode listens on the socket (bool)
33 37628f11 Stefan Hajnoczi
        @raise socket.error on socket connection errors
34 37628f11 Stefan Hajnoczi
        @note No connection is established, this is done by the connect() or
35 37628f11 Stefan Hajnoczi
              accept() methods
36 1d00a07d Luiz Capitulino
        """
37 1d00a07d Luiz Capitulino
        self.__events = []
38 1d00a07d Luiz Capitulino
        self.__address = address
39 1d00a07d Luiz Capitulino
        self.__sock = self.__get_sock()
40 37628f11 Stefan Hajnoczi
        if server:
41 37628f11 Stefan Hajnoczi
            self.__sock.bind(self.__address)
42 37628f11 Stefan Hajnoczi
            self.__sock.listen(1)
43 1d00a07d Luiz Capitulino
44 1d00a07d Luiz Capitulino
    def __get_sock(self):
45 1d00a07d Luiz Capitulino
        if isinstance(self.__address, tuple):
46 1d00a07d Luiz Capitulino
            family = socket.AF_INET
47 1d00a07d Luiz Capitulino
        else:
48 1d00a07d Luiz Capitulino
            family = socket.AF_UNIX
49 1d00a07d Luiz Capitulino
        return socket.socket(family, socket.SOCK_STREAM)
50 1d00a07d Luiz Capitulino
51 37628f11 Stefan Hajnoczi
    def __negotiate_capabilities(self):
52 37628f11 Stefan Hajnoczi
        greeting = self.__json_read()
53 37628f11 Stefan Hajnoczi
        if greeting is None or not greeting.has_key('QMP'):
54 37628f11 Stefan Hajnoczi
            raise QMPConnectError
55 37628f11 Stefan Hajnoczi
        # Greeting seems ok, negotiate capabilities
56 37628f11 Stefan Hajnoczi
        resp = self.cmd('qmp_capabilities')
57 37628f11 Stefan Hajnoczi
        if "return" in resp:
58 37628f11 Stefan Hajnoczi
            return greeting
59 37628f11 Stefan Hajnoczi
        raise QMPCapabilitiesError
60 37628f11 Stefan Hajnoczi
61 91b8eddf Stefan Hajnoczi
    def __json_read(self, only_event=False):
62 1d00a07d Luiz Capitulino
        while True:
63 1d00a07d Luiz Capitulino
            data = self.__sockfile.readline()
64 1d00a07d Luiz Capitulino
            if not data:
65 1d00a07d Luiz Capitulino
                return
66 1d00a07d Luiz Capitulino
            resp = json.loads(data)
67 1d00a07d Luiz Capitulino
            if 'event' in resp:
68 1d00a07d Luiz Capitulino
                self.__events.append(resp)
69 91b8eddf Stefan Hajnoczi
                if not only_event:
70 91b8eddf Stefan Hajnoczi
                    continue
71 1d00a07d Luiz Capitulino
            return resp
72 1d00a07d Luiz Capitulino
73 1d00a07d Luiz Capitulino
    error = socket.error
74 1d00a07d Luiz Capitulino
75 e9d17b68 Ryota Ozaki
    def connect(self, negotiate=True):
76 1d00a07d Luiz Capitulino
        """
77 1d00a07d Luiz Capitulino
        Connect to the QMP Monitor and perform capabilities negotiation.
78 1d00a07d Luiz Capitulino

79 1d00a07d Luiz Capitulino
        @return QMP greeting dict
80 1d00a07d Luiz Capitulino
        @raise socket.error on socket connection errors
81 1d00a07d Luiz Capitulino
        @raise QMPConnectError if the greeting is not received
82 1d00a07d Luiz Capitulino
        @raise QMPCapabilitiesError if fails to negotiate capabilities
83 1d00a07d Luiz Capitulino
        """
84 1d00a07d Luiz Capitulino
        self.__sock.connect(self.__address)
85 e9d17b68 Ryota Ozaki
        self.__sockfile = self.__sock.makefile()
86 e9d17b68 Ryota Ozaki
        if negotiate:
87 e9d17b68 Ryota Ozaki
            return self.__negotiate_capabilities()
88 37628f11 Stefan Hajnoczi
89 37628f11 Stefan Hajnoczi
    def accept(self):
90 37628f11 Stefan Hajnoczi
        """
91 37628f11 Stefan Hajnoczi
        Await connection from QMP Monitor and perform capabilities negotiation.
92 37628f11 Stefan Hajnoczi

93 37628f11 Stefan Hajnoczi
        @return QMP greeting dict
94 37628f11 Stefan Hajnoczi
        @raise socket.error on socket connection errors
95 37628f11 Stefan Hajnoczi
        @raise QMPConnectError if the greeting is not received
96 37628f11 Stefan Hajnoczi
        @raise QMPCapabilitiesError if fails to negotiate capabilities
97 37628f11 Stefan Hajnoczi
        """
98 37628f11 Stefan Hajnoczi
        self.__sock, _ = self.__sock.accept()
99 b3d0380e Jeff Cody
        self.__sockfile = self.__sock.makefile()
100 37628f11 Stefan Hajnoczi
        return self.__negotiate_capabilities()
101 cedebdac Luiz Capitulino
102 1d00a07d Luiz Capitulino
    def cmd_obj(self, qmp_cmd):
103 1d00a07d Luiz Capitulino
        """
104 1d00a07d Luiz Capitulino
        Send a QMP command to the QMP Monitor.
105 cedebdac Luiz Capitulino

106 1d00a07d Luiz Capitulino
        @param qmp_cmd: QMP command to be sent as a Python dict
107 1d00a07d Luiz Capitulino
        @return QMP response as a Python dict or None if the connection has
108 1d00a07d Luiz Capitulino
                been closed
109 1d00a07d Luiz Capitulino
        """
110 1d00a07d Luiz Capitulino
        try:
111 1d00a07d Luiz Capitulino
            self.__sock.sendall(json.dumps(qmp_cmd))
112 1d00a07d Luiz Capitulino
        except socket.error, err:
113 1d00a07d Luiz Capitulino
            if err[0] == errno.EPIPE:
114 1d00a07d Luiz Capitulino
                return
115 1d00a07d Luiz Capitulino
            raise socket.error(err)
116 cedebdac Luiz Capitulino
        return self.__json_read()
117 cedebdac Luiz Capitulino
118 1d00a07d Luiz Capitulino
    def cmd(self, name, args=None, id=None):
119 1d00a07d Luiz Capitulino
        """
120 1d00a07d Luiz Capitulino
        Build a QMP command and send it to the QMP Monitor.
121 cedebdac Luiz Capitulino

122 1d00a07d Luiz Capitulino
        @param name: command name (string)
123 1d00a07d Luiz Capitulino
        @param args: command arguments (dict)
124 1d00a07d Luiz Capitulino
        @param id: command id (dict, list, string or int)
125 1d00a07d Luiz Capitulino
        """
126 1d00a07d Luiz Capitulino
        qmp_cmd = { 'execute': name }
127 1d00a07d Luiz Capitulino
        if args:
128 1d00a07d Luiz Capitulino
            qmp_cmd['arguments'] = args
129 1d00a07d Luiz Capitulino
        if id:
130 1d00a07d Luiz Capitulino
            qmp_cmd['id'] = id
131 1d00a07d Luiz Capitulino
        return self.cmd_obj(qmp_cmd)
132 1d00a07d Luiz Capitulino
133 9f68f7fb Anthony Liguori
    def command(self, cmd, **kwds):
134 9f68f7fb Anthony Liguori
        ret = self.cmd(cmd, kwds)
135 9f68f7fb Anthony Liguori
        if ret.has_key('error'):
136 9f68f7fb Anthony Liguori
            raise Exception(ret['error']['desc'])
137 9f68f7fb Anthony Liguori
        return ret['return']
138 9f68f7fb Anthony Liguori
139 9eb80ead Paolo Bonzini
    def pull_event(self, wait=False):
140 9eb80ead Paolo Bonzini
        """
141 9eb80ead Paolo Bonzini
        Get and delete the first available QMP event.
142 9eb80ead Paolo Bonzini

143 9eb80ead Paolo Bonzini
        @param wait: block until an event is available (bool)
144 9eb80ead Paolo Bonzini
        """
145 9eb80ead Paolo Bonzini
        self.__sock.setblocking(0)
146 9eb80ead Paolo Bonzini
        try:
147 9eb80ead Paolo Bonzini
            self.__json_read()
148 9eb80ead Paolo Bonzini
        except socket.error, err:
149 9eb80ead Paolo Bonzini
            if err[0] == errno.EAGAIN:
150 9eb80ead Paolo Bonzini
                # No data available
151 9eb80ead Paolo Bonzini
                pass
152 9eb80ead Paolo Bonzini
        self.__sock.setblocking(1)
153 9eb80ead Paolo Bonzini
        if not self.__events and wait:
154 9eb80ead Paolo Bonzini
            self.__json_read(only_event=True)
155 9eb80ead Paolo Bonzini
        event = self.__events[0]
156 9eb80ead Paolo Bonzini
        del self.__events[0]
157 9eb80ead Paolo Bonzini
        return event
158 9eb80ead Paolo Bonzini
159 91b8eddf Stefan Hajnoczi
    def get_events(self, wait=False):
160 1d00a07d Luiz Capitulino
        """
161 1d00a07d Luiz Capitulino
        Get a list of available QMP events.
162 91b8eddf Stefan Hajnoczi

163 91b8eddf Stefan Hajnoczi
        @param wait: block until an event is available (bool)
164 1d00a07d Luiz Capitulino
        """
165 1d00a07d Luiz Capitulino
        self.__sock.setblocking(0)
166 cedebdac Luiz Capitulino
        try:
167 1d00a07d Luiz Capitulino
            self.__json_read()
168 1d00a07d Luiz Capitulino
        except socket.error, err:
169 1d00a07d Luiz Capitulino
            if err[0] == errno.EAGAIN:
170 1d00a07d Luiz Capitulino
                # No data available
171 1d00a07d Luiz Capitulino
                pass
172 1d00a07d Luiz Capitulino
        self.__sock.setblocking(1)
173 91b8eddf Stefan Hajnoczi
        if not self.__events and wait:
174 48645123 Fam Zheng
            ret = self.__json_read(only_event=True)
175 48645123 Fam Zheng
            if ret == None:
176 48645123 Fam Zheng
                # We are in blocking mode, if don't get anything, something
177 48645123 Fam Zheng
                # went wrong
178 48645123 Fam Zheng
                raise QMPConnectError("Error while reading from socket")
179 48645123 Fam Zheng
180 1d00a07d Luiz Capitulino
        return self.__events
181 1d00a07d Luiz Capitulino
182 1d00a07d Luiz Capitulino
    def clear_events(self):
183 1d00a07d Luiz Capitulino
        """
184 1d00a07d Luiz Capitulino
        Clear current list of pending events.
185 1d00a07d Luiz Capitulino
        """
186 1d00a07d Luiz Capitulino
        self.__events = []
187 1d00a07d Luiz Capitulino
188 1d00a07d Luiz Capitulino
    def close(self):
189 1d00a07d Luiz Capitulino
        self.__sock.close()
190 1d00a07d Luiz Capitulino
        self.__sockfile.close()
191 e37b350a Ryota Ozaki
192 e37b350a Ryota Ozaki
    timeout = socket.timeout
193 e37b350a Ryota Ozaki
194 e37b350a Ryota Ozaki
    def settimeout(self, timeout):
195 e37b350a Ryota Ozaki
        self.__sock.settimeout(timeout)
196 30b005d9 Wenchao Xia
197 30b005d9 Wenchao Xia
    def get_sock_fd(self):
198 30b005d9 Wenchao Xia
        return self.__sock.fileno()
199 30b005d9 Wenchao Xia
200 30b005d9 Wenchao Xia
    def is_scm_available(self):
201 30b005d9 Wenchao Xia
        return self.__sock.family == socket.AF_UNIX