You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

qmp.py 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. import logging
  14. class QMPError(Exception):
  15. pass
  16. class QMPConnectError(QMPError):
  17. pass
  18. class QMPCapabilitiesError(QMPError):
  19. pass
  20. class QMPTimeoutError(QMPError):
  21. pass
  22. class QEMUMonitorProtocol(object):
  23. #: Logger object for debugging messages
  24. logger = logging.getLogger('QMP')
  25. #: Socket's error class
  26. error = socket.error
  27. #: Socket's timeout
  28. timeout = socket.timeout
  29. def __init__(self, address, server=False):
  30. """
  31. Create a QEMUMonitorProtocol class.
  32. @param address: QEMU address, can be either a unix socket path (string)
  33. or a tuple in the form ( address, port ) for a TCP
  34. connection
  35. @param server: server mode listens on the socket (bool)
  36. @raise socket.error on socket connection errors
  37. @note No connection is established, this is done by the connect() or
  38. accept() methods
  39. """
  40. self.__events = []
  41. self.__address = address
  42. self.__sock = self.__get_sock()
  43. self.__sockfile = None
  44. if server:
  45. self.__sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  46. self.__sock.bind(self.__address)
  47. self.__sock.listen(1)
  48. def __get_sock(self):
  49. if isinstance(self.__address, tuple):
  50. family = socket.AF_INET
  51. else:
  52. family = socket.AF_UNIX
  53. return socket.socket(family, socket.SOCK_STREAM)
  54. def __negotiate_capabilities(self):
  55. greeting = self.__json_read()
  56. if greeting is None or "QMP" not in greeting:
  57. raise QMPConnectError
  58. # Greeting seems ok, negotiate capabilities
  59. resp = self.cmd('qmp_capabilities')
  60. if "return" in resp:
  61. return greeting
  62. raise QMPCapabilitiesError
  63. def __json_read(self, only_event=False):
  64. while True:
  65. data = self.__sockfile.readline()
  66. if not data:
  67. return
  68. resp = json.loads(data)
  69. if 'event' in resp:
  70. self.logger.debug("<<< %s", resp)
  71. self.__events.append(resp)
  72. if not only_event:
  73. continue
  74. return resp
  75. def __get_events(self, wait=False):
  76. """
  77. Check for new events in the stream and cache them in __events.
  78. @param wait (bool): block until an event is available.
  79. @param wait (float): If wait is a float, treat it as a timeout value.
  80. @raise QMPTimeoutError: If a timeout float is provided and the timeout
  81. period elapses.
  82. @raise QMPConnectError: If wait is True but no events could be
  83. retrieved or if some other error occurred.
  84. """
  85. # Check for new events regardless and pull them into the cache:
  86. self.__sock.setblocking(0)
  87. try:
  88. self.__json_read()
  89. except socket.error as err:
  90. if err[0] == errno.EAGAIN:
  91. # No data available
  92. pass
  93. self.__sock.setblocking(1)
  94. # Wait for new events, if needed.
  95. # if wait is 0.0, this means "no wait" and is also implicitly false.
  96. if not self.__events and wait:
  97. if isinstance(wait, float):
  98. self.__sock.settimeout(wait)
  99. try:
  100. ret = self.__json_read(only_event=True)
  101. except socket.timeout:
  102. raise QMPTimeoutError("Timeout waiting for event")
  103. except:
  104. raise QMPConnectError("Error while reading from socket")
  105. if ret is None:
  106. raise QMPConnectError("Error while reading from socket")
  107. self.__sock.settimeout(None)
  108. def connect(self, negotiate=True):
  109. """
  110. Connect to the QMP Monitor and perform capabilities negotiation.
  111. @return QMP greeting dict
  112. @raise socket.error on socket connection errors
  113. @raise QMPConnectError if the greeting is not received
  114. @raise QMPCapabilitiesError if fails to negotiate capabilities
  115. """
  116. self.__sock.connect(self.__address)
  117. self.__sockfile = self.__sock.makefile()
  118. if negotiate:
  119. return self.__negotiate_capabilities()
  120. def accept(self):
  121. """
  122. Await connection from QMP Monitor and perform capabilities negotiation.
  123. @return QMP greeting dict
  124. @raise socket.error on socket connection errors
  125. @raise QMPConnectError if the greeting is not received
  126. @raise QMPCapabilitiesError if fails to negotiate capabilities
  127. """
  128. self.__sock.settimeout(15)
  129. self.__sock, _ = self.__sock.accept()
  130. self.__sockfile = self.__sock.makefile()
  131. return self.__negotiate_capabilities()
  132. def cmd_obj(self, qmp_cmd):
  133. """
  134. Send a QMP command to the QMP Monitor.
  135. @param qmp_cmd: QMP command to be sent as a Python dict
  136. @return QMP response as a Python dict or None if the connection has
  137. been closed
  138. """
  139. self.logger.debug(">>> %s", qmp_cmd)
  140. try:
  141. self.__sock.sendall(json.dumps(qmp_cmd).encode('utf-8'))
  142. except socket.error as err:
  143. if err[0] == errno.EPIPE:
  144. return
  145. raise socket.error(err)
  146. resp = self.__json_read()
  147. self.logger.debug("<<< %s", resp)
  148. return resp
  149. def cmd(self, name, args=None, cmd_id=None):
  150. """
  151. Build a QMP command and send it to the QMP Monitor.
  152. @param name: command name (string)
  153. @param args: command arguments (dict)
  154. @param cmd_id: command id (dict, list, string or int)
  155. """
  156. qmp_cmd = {'execute': name}
  157. if args:
  158. qmp_cmd['arguments'] = args
  159. if cmd_id:
  160. qmp_cmd['id'] = cmd_id
  161. return self.cmd_obj(qmp_cmd)
  162. def command(self, cmd, **kwds):
  163. """
  164. Build and send a QMP command to the monitor, report errors if any
  165. """
  166. ret = self.cmd(cmd, kwds)
  167. if "error" in ret:
  168. raise Exception(ret['error']['desc'])
  169. return ret['return']
  170. def pull_event(self, wait=False):
  171. """
  172. Pulls a single event.
  173. @param wait (bool): block until an event is available.
  174. @param wait (float): If wait is a float, treat it as a timeout value.
  175. @raise QMPTimeoutError: If a timeout float is provided and the timeout
  176. period elapses.
  177. @raise QMPConnectError: If wait is True but no events could be
  178. retrieved or if some other error occurred.
  179. @return The first available QMP event, or None.
  180. """
  181. self.__get_events(wait)
  182. if self.__events:
  183. return self.__events.pop(0)
  184. return None
  185. def get_events(self, wait=False):
  186. """
  187. Get a list of available QMP events.
  188. @param wait (bool): block until an event is available.
  189. @param wait (float): If wait is a float, treat it as a timeout value.
  190. @raise QMPTimeoutError: If a timeout float is provided and the timeout
  191. period elapses.
  192. @raise QMPConnectError: If wait is True but no events could be
  193. retrieved or if some other error occurred.
  194. @return The list of available QMP events.
  195. """
  196. self.__get_events(wait)
  197. return self.__events
  198. def clear_events(self):
  199. """
  200. Clear current list of pending events.
  201. """
  202. self.__events = []
  203. def close(self):
  204. self.__sock.close()
  205. self.__sockfile.close()
  206. def settimeout(self, timeout):
  207. self.__sock.settimeout(timeout)
  208. def get_sock_fd(self):
  209. return self.__sock.fileno()
  210. def is_scm_available(self):
  211. return self.__sock.family == socket.AF_UNIX