|
|
1.1 root 1: # QEMU Monitor Protocol Python class
2: #
1.1.1.3 root 3: # Copyright (C) 2009, 2010 Red Hat Inc.
1.1 root 4: #
5: # Authors:
6: # Luiz Capitulino <[email protected]>
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:
1.1.1.3 root 11: import json
12: import errno
13: import socket
1.1 root 14:
15: class QMPError(Exception):
16: pass
17:
18: class QMPConnectError(QMPError):
19: pass
20:
1.1.1.3 root 21: class QMPCapabilitiesError(QMPError):
22: pass
23:
1.1 root 24: class QEMUMonitorProtocol:
1.1.1.4 ! root 25: def __init__(self, address, server=False):
1.1.1.3 root 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
1.1.1.4 ! root 32: @param server: server mode listens on the socket (bool)
! 33: @raise socket.error on socket connection errors
! 34: @note No connection is established, this is done by the connect() or
! 35: accept() methods
1.1.1.3 root 36: """
37: self.__events = []
38: self.__address = address
39: self.__sock = self.__get_sock()
1.1.1.4 ! root 40: if server:
! 41: self.__sock.bind(self.__address)
! 42: self.__sock.listen(1)
1.1.1.3 root 43:
44: def __get_sock(self):
45: if isinstance(self.__address, tuple):
46: family = socket.AF_INET
47: else:
48: family = socket.AF_UNIX
49: return socket.socket(family, socket.SOCK_STREAM)
1.1 root 50:
1.1.1.4 ! root 51: def __negotiate_capabilities(self):
! 52: self.__sockfile = self.__sock.makefile()
! 53: greeting = self.__json_read()
! 54: if greeting is None or not greeting.has_key('QMP'):
! 55: raise QMPConnectError
! 56: # Greeting seems ok, negotiate capabilities
! 57: resp = self.cmd('qmp_capabilities')
! 58: if "return" in resp:
! 59: return greeting
! 60: raise QMPCapabilitiesError
! 61:
! 62: def __json_read(self, only_event=False):
1.1.1.3 root 63: while True:
64: data = self.__sockfile.readline()
65: if not data:
66: return
67: resp = json.loads(data)
68: if 'event' in resp:
69: self.__events.append(resp)
1.1.1.4 ! root 70: if not only_event:
! 71: continue
1.1.1.3 root 72: return resp
1.1 root 73:
1.1.1.3 root 74: error = socket.error
1.1 root 75:
1.1.1.3 root 76: def connect(self):
77: """
78: Connect to the QMP Monitor and perform capabilities negotiation.
1.1 root 79:
1.1.1.3 root 80: @return QMP greeting dict
81: @raise socket.error on socket connection errors
82: @raise QMPConnectError if the greeting is not received
83: @raise QMPCapabilitiesError if fails to negotiate capabilities
84: """
85: self.__sock.connect(self.__address)
1.1.1.4 ! root 86: return self.__negotiate_capabilities()
! 87:
! 88: def accept(self):
! 89: """
! 90: Await connection from QMP Monitor and perform capabilities negotiation.
! 91:
! 92: @return QMP greeting dict
! 93: @raise socket.error on socket connection errors
! 94: @raise QMPConnectError if the greeting is not received
! 95: @raise QMPCapabilitiesError if fails to negotiate capabilities
! 96: """
! 97: self.__sock, _ = self.__sock.accept()
! 98: return self.__negotiate_capabilities()
1.1.1.3 root 99:
100: def cmd_obj(self, qmp_cmd):
101: """
102: Send a QMP command to the QMP Monitor.
103:
104: @param qmp_cmd: QMP command to be sent as a Python dict
105: @return QMP response as a Python dict or None if the connection has
106: been closed
107: """
108: try:
109: self.__sock.sendall(json.dumps(qmp_cmd))
110: except socket.error, err:
111: if err[0] == errno.EPIPE:
112: return
113: raise socket.error(err)
114: return self.__json_read()
1.1 root 115:
1.1.1.3 root 116: def cmd(self, name, args=None, id=None):
117: """
118: Build a QMP command and send it to the QMP Monitor.
119:
120: @param name: command name (string)
121: @param args: command arguments (dict)
122: @param id: command id (dict, list, string or int)
123: """
124: qmp_cmd = { 'execute': name }
125: if args:
126: qmp_cmd['arguments'] = args
127: if id:
128: qmp_cmd['id'] = id
129: return self.cmd_obj(qmp_cmd)
130:
1.1.1.4 ! root 131: def get_events(self, wait=False):
1.1.1.3 root 132: """
133: Get a list of available QMP events.
1.1.1.4 ! root 134:
! 135: @param wait: block until an event is available (bool)
1.1.1.3 root 136: """
137: self.__sock.setblocking(0)
1.1 root 138: try:
1.1.1.3 root 139: self.__json_read()
140: except socket.error, err:
141: if err[0] == errno.EAGAIN:
142: # No data available
143: pass
144: self.__sock.setblocking(1)
1.1.1.4 ! root 145: if not self.__events and wait:
! 146: self.__json_read(only_event=True)
1.1.1.3 root 147: return self.__events
148:
149: def clear_events(self):
150: """
151: Clear current list of pending events.
152: """
153: self.__events = []
154:
155: def close(self):
156: self.__sock.close()
157: self.__sockfile.close()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.