import source from 0.14.1
[external/qemu.git] / QMP / qmp.py
1 # QEMU Monitor Protocol Python class
2
3 # Copyright (C) 2009, 2010 Red Hat Inc.
4 #
5 # Authors:
6 #  Luiz Capitulino <lcapitulino@redhat.com>
7 #
8 # This work is licensed under the terms of the GNU GPL, version 2.  See
9 # the COPYING file in the top-level directory.
10
11 import json
12 import errno
13 import socket
14
15 class QMPError(Exception):
16     pass
17
18 class QMPConnectError(QMPError):
19     pass
20
21 class QMPCapabilitiesError(QMPError):
22     pass
23
24 class QEMUMonitorProtocol:
25     def __init__(self, address):
26         """
27         Create a QEMUMonitorProtocol class.
28
29         @param address: QEMU address, can be either a unix socket path (string)
30                         or a tuple in the form ( address, port ) for a TCP
31                         connection
32         @note No connection is established, this is done by the connect() method
33         """
34         self.__events = []
35         self.__address = address
36         self.__sock = self.__get_sock()
37         self.__sockfile = self.__sock.makefile()
38
39     def __get_sock(self):
40         if isinstance(self.__address, tuple):
41             family = socket.AF_INET
42         else:
43             family = socket.AF_UNIX
44         return socket.socket(family, socket.SOCK_STREAM)
45
46     def __json_read(self):
47         while True:
48             data = self.__sockfile.readline()
49             if not data:
50                 return
51             resp = json.loads(data)
52             if 'event' in resp:
53                 self.__events.append(resp)
54                 continue
55             return resp
56
57     error = socket.error
58
59     def connect(self):
60         """
61         Connect to the QMP Monitor and perform capabilities negotiation.
62
63         @return QMP greeting dict
64         @raise socket.error on socket connection errors
65         @raise QMPConnectError if the greeting is not received
66         @raise QMPCapabilitiesError if fails to negotiate capabilities
67         """
68         self.__sock.connect(self.__address)
69         greeting = self.__json_read()
70         if greeting is None or not greeting.has_key('QMP'):
71             raise QMPConnectError
72         # Greeting seems ok, negotiate capabilities
73         resp = self.cmd('qmp_capabilities')
74         if "return" in resp:
75             return greeting
76         raise QMPCapabilitiesError
77
78     def cmd_obj(self, qmp_cmd):
79         """
80         Send a QMP command to the QMP Monitor.
81
82         @param qmp_cmd: QMP command to be sent as a Python dict
83         @return QMP response as a Python dict or None if the connection has
84                 been closed
85         """
86         try:
87             self.__sock.sendall(json.dumps(qmp_cmd))
88         except socket.error, err:
89             if err[0] == errno.EPIPE:
90                 return
91             raise socket.error(err)
92         return self.__json_read()
93
94     def cmd(self, name, args=None, id=None):
95         """
96         Build a QMP command and send it to the QMP Monitor.
97
98         @param name: command name (string)
99         @param args: command arguments (dict)
100         @param id: command id (dict, list, string or int)
101         """
102         qmp_cmd = { 'execute': name }
103         if args:
104             qmp_cmd['arguments'] = args
105         if id:
106             qmp_cmd['id'] = id
107         return self.cmd_obj(qmp_cmd)
108
109     def get_events(self):
110         """
111         Get a list of available QMP events.
112         """
113         self.__sock.setblocking(0)
114         try:
115             self.__json_read()
116         except socket.error, err:
117             if err[0] == errno.EAGAIN:
118                 # No data available
119                 pass
120         self.__sock.setblocking(1)
121         return self.__events
122
123     def clear_events(self):
124         """
125         Clear current list of pending events.
126         """
127         self.__events = []
128
129     def close(self):
130         self.__sock.close()
131         self.__sockfile.close()