Statistics
| Branch: | Revision:

root / QMP / qmp.py @ 37628f11

History | View | Annotate | Download (4.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 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
        self.__sockfile = self.__sock.makefile()
53 37628f11 Stefan Hajnoczi
        greeting = self.__json_read()
54 37628f11 Stefan Hajnoczi
        if greeting is None or not greeting.has_key('QMP'):
55 37628f11 Stefan Hajnoczi
            raise QMPConnectError
56 37628f11 Stefan Hajnoczi
        # Greeting seems ok, negotiate capabilities
57 37628f11 Stefan Hajnoczi
        resp = self.cmd('qmp_capabilities')
58 37628f11 Stefan Hajnoczi
        if "return" in resp:
59 37628f11 Stefan Hajnoczi
            return greeting
60 37628f11 Stefan Hajnoczi
        raise QMPCapabilitiesError
61 37628f11 Stefan Hajnoczi
62 91b8eddf Stefan Hajnoczi
    def __json_read(self, only_event=False):
63 1d00a07d Luiz Capitulino
        while True:
64 1d00a07d Luiz Capitulino
            data = self.__sockfile.readline()
65 1d00a07d Luiz Capitulino
            if not data:
66 1d00a07d Luiz Capitulino
                return
67 1d00a07d Luiz Capitulino
            resp = json.loads(data)
68 1d00a07d Luiz Capitulino
            if 'event' in resp:
69 1d00a07d Luiz Capitulino
                self.__events.append(resp)
70 91b8eddf Stefan Hajnoczi
                if not only_event:
71 91b8eddf Stefan Hajnoczi
                    continue
72 1d00a07d Luiz Capitulino
            return resp
73 1d00a07d Luiz Capitulino
74 1d00a07d Luiz Capitulino
    error = socket.error
75 1d00a07d Luiz Capitulino
76 cedebdac Luiz Capitulino
    def connect(self):
77 1d00a07d Luiz Capitulino
        """
78 1d00a07d Luiz Capitulino
        Connect to the QMP Monitor and perform capabilities negotiation.
79 1d00a07d Luiz Capitulino

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

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

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

120 1d00a07d Luiz Capitulino
        @param name: command name (string)
121 1d00a07d Luiz Capitulino
        @param args: command arguments (dict)
122 1d00a07d Luiz Capitulino
        @param id: command id (dict, list, string or int)
123 1d00a07d Luiz Capitulino
        """
124 1d00a07d Luiz Capitulino
        qmp_cmd = { 'execute': name }
125 1d00a07d Luiz Capitulino
        if args:
126 1d00a07d Luiz Capitulino
            qmp_cmd['arguments'] = args
127 1d00a07d Luiz Capitulino
        if id:
128 1d00a07d Luiz Capitulino
            qmp_cmd['id'] = id
129 1d00a07d Luiz Capitulino
        return self.cmd_obj(qmp_cmd)
130 1d00a07d Luiz Capitulino
131 91b8eddf Stefan Hajnoczi
    def get_events(self, wait=False):
132 1d00a07d Luiz Capitulino
        """
133 1d00a07d Luiz Capitulino
        Get a list of available QMP events.
134 91b8eddf Stefan Hajnoczi

135 91b8eddf Stefan Hajnoczi
        @param wait: block until an event is available (bool)
136 1d00a07d Luiz Capitulino
        """
137 1d00a07d Luiz Capitulino
        self.__sock.setblocking(0)
138 cedebdac Luiz Capitulino
        try:
139 1d00a07d Luiz Capitulino
            self.__json_read()
140 1d00a07d Luiz Capitulino
        except socket.error, err:
141 1d00a07d Luiz Capitulino
            if err[0] == errno.EAGAIN:
142 1d00a07d Luiz Capitulino
                # No data available
143 1d00a07d Luiz Capitulino
                pass
144 1d00a07d Luiz Capitulino
        self.__sock.setblocking(1)
145 91b8eddf Stefan Hajnoczi
        if not self.__events and wait:
146 91b8eddf Stefan Hajnoczi
            self.__json_read(only_event=True)
147 1d00a07d Luiz Capitulino
        return self.__events
148 1d00a07d Luiz Capitulino
149 1d00a07d Luiz Capitulino
    def clear_events(self):
150 1d00a07d Luiz Capitulino
        """
151 1d00a07d Luiz Capitulino
        Clear current list of pending events.
152 1d00a07d Luiz Capitulino
        """
153 1d00a07d Luiz Capitulino
        self.__events = []
154 1d00a07d Luiz Capitulino
155 1d00a07d Luiz Capitulino
    def close(self):
156 1d00a07d Luiz Capitulino
        self.__sock.close()
157 1d00a07d Luiz Capitulino
        self.__sockfile.close()