root / QMP / qmp.py @ 9bed0d0d
History | View | Annotate | Download (3.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 | 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 | 1d00a07d | Luiz Capitulino | def __json_read(self): |
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 | 1d00a07d | Luiz Capitulino | continue
|
55 | 1d00a07d | Luiz Capitulino | return resp
|
56 | 1d00a07d | Luiz Capitulino | |
57 | 1d00a07d | Luiz Capitulino | error = socket.error |
58 | 1d00a07d | Luiz Capitulino | |
59 | cedebdac | Luiz Capitulino | def connect(self): |
60 | 1d00a07d | Luiz Capitulino | """
|
61 | 1d00a07d | Luiz Capitulino | Connect to the QMP Monitor and perform capabilities negotiation.
|
62 | 1d00a07d | Luiz Capitulino |
|
63 | 1d00a07d | Luiz Capitulino | @return QMP greeting dict
|
64 | 1d00a07d | Luiz Capitulino | @raise socket.error on socket connection errors
|
65 | 1d00a07d | Luiz Capitulino | @raise QMPConnectError if the greeting is not received
|
66 | 1d00a07d | Luiz Capitulino | @raise QMPCapabilitiesError if fails to negotiate capabilities
|
67 | 1d00a07d | Luiz Capitulino | """
|
68 | 1d00a07d | Luiz Capitulino | self.__sock.connect(self.__address) |
69 | 1d00a07d | Luiz Capitulino | greeting = self.__json_read()
|
70 | 1d00a07d | Luiz Capitulino | if greeting is None or not greeting.has_key('QMP'): |
71 | cedebdac | Luiz Capitulino | raise QMPConnectError
|
72 | 1d00a07d | Luiz Capitulino | # Greeting seems ok, negotiate capabilities
|
73 | 1d00a07d | Luiz Capitulino | resp = self.cmd('qmp_capabilities') |
74 | 1d00a07d | Luiz Capitulino | if "return" in resp: |
75 | 1d00a07d | Luiz Capitulino | return greeting
|
76 | 1d00a07d | Luiz Capitulino | raise QMPCapabilitiesError
|
77 | cedebdac | Luiz Capitulino | |
78 | 1d00a07d | Luiz Capitulino | def cmd_obj(self, qmp_cmd): |
79 | 1d00a07d | Luiz Capitulino | """
|
80 | 1d00a07d | Luiz Capitulino | Send a QMP command to the QMP Monitor.
|
81 | cedebdac | Luiz Capitulino |
|
82 | 1d00a07d | Luiz Capitulino | @param qmp_cmd: QMP command to be sent as a Python dict
|
83 | 1d00a07d | Luiz Capitulino | @return QMP response as a Python dict or None if the connection has
|
84 | 1d00a07d | Luiz Capitulino | been closed
|
85 | 1d00a07d | Luiz Capitulino | """
|
86 | 1d00a07d | Luiz Capitulino | try:
|
87 | 1d00a07d | Luiz Capitulino | self.__sock.sendall(json.dumps(qmp_cmd))
|
88 | 1d00a07d | Luiz Capitulino | except socket.error, err:
|
89 | 1d00a07d | Luiz Capitulino | if err[0] == errno.EPIPE: |
90 | 1d00a07d | Luiz Capitulino | return
|
91 | 1d00a07d | Luiz Capitulino | raise socket.error(err)
|
92 | cedebdac | Luiz Capitulino | return self.__json_read() |
93 | cedebdac | Luiz Capitulino | |
94 | 1d00a07d | Luiz Capitulino | def cmd(self, name, args=None, id=None): |
95 | 1d00a07d | Luiz Capitulino | """
|
96 | 1d00a07d | Luiz Capitulino | Build a QMP command and send it to the QMP Monitor.
|
97 | cedebdac | Luiz Capitulino |
|
98 | 1d00a07d | Luiz Capitulino | @param name: command name (string)
|
99 | 1d00a07d | Luiz Capitulino | @param args: command arguments (dict)
|
100 | 1d00a07d | Luiz Capitulino | @param id: command id (dict, list, string or int)
|
101 | 1d00a07d | Luiz Capitulino | """
|
102 | 1d00a07d | Luiz Capitulino | qmp_cmd = { 'execute': name }
|
103 | 1d00a07d | Luiz Capitulino | if args:
|
104 | 1d00a07d | Luiz Capitulino | qmp_cmd['arguments'] = args
|
105 | 1d00a07d | Luiz Capitulino | if id: |
106 | 1d00a07d | Luiz Capitulino | qmp_cmd['id'] = id |
107 | 1d00a07d | Luiz Capitulino | return self.cmd_obj(qmp_cmd) |
108 | 1d00a07d | Luiz Capitulino | |
109 | 1d00a07d | Luiz Capitulino | def get_events(self): |
110 | 1d00a07d | Luiz Capitulino | """
|
111 | 1d00a07d | Luiz Capitulino | Get a list of available QMP events.
|
112 | 1d00a07d | Luiz Capitulino | """
|
113 | 1d00a07d | Luiz Capitulino | self.__sock.setblocking(0) |
114 | cedebdac | Luiz Capitulino | try:
|
115 | 1d00a07d | Luiz Capitulino | self.__json_read()
|
116 | 1d00a07d | Luiz Capitulino | except socket.error, err:
|
117 | 1d00a07d | Luiz Capitulino | if err[0] == errno.EAGAIN: |
118 | 1d00a07d | Luiz Capitulino | # No data available
|
119 | 1d00a07d | Luiz Capitulino | pass
|
120 | 1d00a07d | Luiz Capitulino | self.__sock.setblocking(1) |
121 | 1d00a07d | Luiz Capitulino | return self.__events |
122 | 1d00a07d | Luiz Capitulino | |
123 | 1d00a07d | Luiz Capitulino | def clear_events(self): |
124 | 1d00a07d | Luiz Capitulino | """
|
125 | 1d00a07d | Luiz Capitulino | Clear current list of pending events.
|
126 | 1d00a07d | Luiz Capitulino | """
|
127 | 1d00a07d | Luiz Capitulino | self.__events = []
|
128 | 1d00a07d | Luiz Capitulino | |
129 | 1d00a07d | Luiz Capitulino | def close(self): |
130 | 1d00a07d | Luiz Capitulino | self.__sock.close()
|
131 | 1d00a07d | Luiz Capitulino | self.__sockfile.close() |