Statistics
| Branch: | Revision:

root / QMP / qmp.py @ 91b8eddf

History | View | Annotate | Download (3.9 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 91b8eddf Stefan Hajnoczi
    def __json_read(self, only_event=False):
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 91b8eddf Stefan Hajnoczi
                if not only_event:
55 91b8eddf Stefan Hajnoczi
                    continue
56 1d00a07d Luiz Capitulino
            return resp
57 1d00a07d Luiz Capitulino
58 1d00a07d Luiz Capitulino
    error = socket.error
59 1d00a07d Luiz Capitulino
60 cedebdac Luiz Capitulino
    def connect(self):
61 1d00a07d Luiz Capitulino
        """
62 1d00a07d Luiz Capitulino
        Connect to the QMP Monitor and perform capabilities negotiation.
63 1d00a07d Luiz Capitulino

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

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

99 1d00a07d Luiz Capitulino
        @param name: command name (string)
100 1d00a07d Luiz Capitulino
        @param args: command arguments (dict)
101 1d00a07d Luiz Capitulino
        @param id: command id (dict, list, string or int)
102 1d00a07d Luiz Capitulino
        """
103 1d00a07d Luiz Capitulino
        qmp_cmd = { 'execute': name }
104 1d00a07d Luiz Capitulino
        if args:
105 1d00a07d Luiz Capitulino
            qmp_cmd['arguments'] = args
106 1d00a07d Luiz Capitulino
        if id:
107 1d00a07d Luiz Capitulino
            qmp_cmd['id'] = id
108 1d00a07d Luiz Capitulino
        return self.cmd_obj(qmp_cmd)
109 1d00a07d Luiz Capitulino
110 91b8eddf Stefan Hajnoczi
    def get_events(self, wait=False):
111 1d00a07d Luiz Capitulino
        """
112 1d00a07d Luiz Capitulino
        Get a list of available QMP events.
113 91b8eddf Stefan Hajnoczi

114 91b8eddf Stefan Hajnoczi
        @param wait: block until an event is available (bool)
115 1d00a07d Luiz Capitulino
        """
116 1d00a07d Luiz Capitulino
        self.__sock.setblocking(0)
117 cedebdac Luiz Capitulino
        try:
118 1d00a07d Luiz Capitulino
            self.__json_read()
119 1d00a07d Luiz Capitulino
        except socket.error, err:
120 1d00a07d Luiz Capitulino
            if err[0] == errno.EAGAIN:
121 1d00a07d Luiz Capitulino
                # No data available
122 1d00a07d Luiz Capitulino
                pass
123 1d00a07d Luiz Capitulino
        self.__sock.setblocking(1)
124 91b8eddf Stefan Hajnoczi
        if not self.__events and wait:
125 91b8eddf Stefan Hajnoczi
            self.__json_read(only_event=True)
126 1d00a07d Luiz Capitulino
        return self.__events
127 1d00a07d Luiz Capitulino
128 1d00a07d Luiz Capitulino
    def clear_events(self):
129 1d00a07d Luiz Capitulino
        """
130 1d00a07d Luiz Capitulino
        Clear current list of pending events.
131 1d00a07d Luiz Capitulino
        """
132 1d00a07d Luiz Capitulino
        self.__events = []
133 1d00a07d Luiz Capitulino
134 1d00a07d Luiz Capitulino
    def close(self):
135 1d00a07d Luiz Capitulino
        self.__sock.close()
136 1d00a07d Luiz Capitulino
        self.__sockfile.close()