]> git.proxmox.com Git - qemu.git/blame - QMP/qmp.py
QMP: add get_events(wait=True) option
[qemu.git] / QMP / qmp.py
CommitLineData
cedebdac
LC
1# QEMU Monitor Protocol Python class
2#
1d00a07d 3# Copyright (C) 2009, 2010 Red Hat Inc.
cedebdac
LC
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
1d00a07d
LC
11import json
12import errno
13import socket
cedebdac
LC
14
15class QMPError(Exception):
16 pass
17
18class QMPConnectError(QMPError):
19 pass
20
1d00a07d
LC
21class QMPCapabilitiesError(QMPError):
22 pass
23
cedebdac 24class QEMUMonitorProtocol:
1d00a07d
LC
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
91b8eddf 46 def __json_read(self, only_event=False):
1d00a07d
LC
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)
91b8eddf
SH
54 if not only_event:
55 continue
1d00a07d
LC
56 return resp
57
58 error = socket.error
59
cedebdac 60 def connect(self):
1d00a07d
LC
61 """
62 Connect to the QMP Monitor and perform capabilities negotiation.
63
64 @return QMP greeting dict
65 @raise socket.error on socket connection errors
66 @raise QMPConnectError if the greeting is not received
67 @raise QMPCapabilitiesError if fails to negotiate capabilities
68 """
69 self.__sock.connect(self.__address)
70 greeting = self.__json_read()
71 if greeting is None or not greeting.has_key('QMP'):
cedebdac 72 raise QMPConnectError
1d00a07d
LC
73 # Greeting seems ok, negotiate capabilities
74 resp = self.cmd('qmp_capabilities')
75 if "return" in resp:
76 return greeting
77 raise QMPCapabilitiesError
cedebdac 78
1d00a07d
LC
79 def cmd_obj(self, qmp_cmd):
80 """
81 Send a QMP command to the QMP Monitor.
cedebdac 82
1d00a07d
LC
83 @param qmp_cmd: QMP command to be sent as a Python dict
84 @return QMP response as a Python dict or None if the connection has
85 been closed
86 """
87 try:
88 self.__sock.sendall(json.dumps(qmp_cmd))
89 except socket.error, err:
90 if err[0] == errno.EPIPE:
91 return
92 raise socket.error(err)
cedebdac
LC
93 return self.__json_read()
94
1d00a07d
LC
95 def cmd(self, name, args=None, id=None):
96 """
97 Build a QMP command and send it to the QMP Monitor.
cedebdac 98
1d00a07d
LC
99 @param name: command name (string)
100 @param args: command arguments (dict)
101 @param id: command id (dict, list, string or int)
102 """
103 qmp_cmd = { 'execute': name }
104 if args:
105 qmp_cmd['arguments'] = args
106 if id:
107 qmp_cmd['id'] = id
108 return self.cmd_obj(qmp_cmd)
109
91b8eddf 110 def get_events(self, wait=False):
1d00a07d
LC
111 """
112 Get a list of available QMP events.
91b8eddf
SH
113
114 @param wait: block until an event is available (bool)
1d00a07d
LC
115 """
116 self.__sock.setblocking(0)
cedebdac 117 try:
1d00a07d
LC
118 self.__json_read()
119 except socket.error, err:
120 if err[0] == errno.EAGAIN:
121 # No data available
122 pass
123 self.__sock.setblocking(1)
91b8eddf
SH
124 if not self.__events and wait:
125 self.__json_read(only_event=True)
1d00a07d
LC
126 return self.__events
127
128 def clear_events(self):
129 """
130 Clear current list of pending events.
131 """
132 self.__events = []
133
134 def close(self):
135 self.__sock.close()
136 self.__sockfile.close()