qmp.py 5.6 KB

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