|
|
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.3 ! root 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)
1.1 root 45:
1.1.1.3 ! root 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
1.1 root 56:
1.1.1.3 ! root 57: error = socket.error
1.1 root 58:
1.1.1.3 ! root 59: def connect(self):
! 60: """
! 61: Connect to the QMP Monitor and perform capabilities negotiation.
1.1 root 62:
1.1.1.3 ! root 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()
1.1 root 93:
1.1.1.3 ! root 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)
1.1 root 114: try:
1.1.1.3 ! root 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()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.