QMP: add server mode to QEMUMonitorProtocol
QEMU supports socket chardevs that establish connections like a server or a client. The QEMUMonitorProtocol class only supports connecting as a client. It is not possible to connect race-free when launching QEMU since trying to connect before QEMU has bound and is listening on the socket results in failure. Add the QEMUMonitorProtocol(server=True) argument to bind and listen on the socket. The QEMU process can then be launched and connects to the already existing QMP socket without a race condition: qmp = qmp.QEMUMonitorProtocol(monitor_path, server=True) popen = subprocess.Popen(args) qmp.accept() Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
This commit is contained in:
parent
91b8eddf41
commit
37628f11c6
43
QMP/qmp.py
43
QMP/qmp.py
@ -22,19 +22,24 @@ class QMPCapabilitiesError(QMPError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class QEMUMonitorProtocol:
|
class QEMUMonitorProtocol:
|
||||||
def __init__(self, address):
|
def __init__(self, address, server=False):
|
||||||
"""
|
"""
|
||||||
Create a QEMUMonitorProtocol class.
|
Create a QEMUMonitorProtocol class.
|
||||||
|
|
||||||
@param address: QEMU address, can be either a unix socket path (string)
|
@param address: QEMU address, can be either a unix socket path (string)
|
||||||
or a tuple in the form ( address, port ) for a TCP
|
or a tuple in the form ( address, port ) for a TCP
|
||||||
connection
|
connection
|
||||||
@note No connection is established, this is done by the connect() method
|
@param server: server mode listens on the socket (bool)
|
||||||
|
@raise socket.error on socket connection errors
|
||||||
|
@note No connection is established, this is done by the connect() or
|
||||||
|
accept() methods
|
||||||
"""
|
"""
|
||||||
self.__events = []
|
self.__events = []
|
||||||
self.__address = address
|
self.__address = address
|
||||||
self.__sock = self.__get_sock()
|
self.__sock = self.__get_sock()
|
||||||
self.__sockfile = self.__sock.makefile()
|
if server:
|
||||||
|
self.__sock.bind(self.__address)
|
||||||
|
self.__sock.listen(1)
|
||||||
|
|
||||||
def __get_sock(self):
|
def __get_sock(self):
|
||||||
if isinstance(self.__address, tuple):
|
if isinstance(self.__address, tuple):
|
||||||
@ -43,6 +48,17 @@ class QEMUMonitorProtocol:
|
|||||||
family = socket.AF_UNIX
|
family = socket.AF_UNIX
|
||||||
return socket.socket(family, socket.SOCK_STREAM)
|
return socket.socket(family, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
def __negotiate_capabilities(self):
|
||||||
|
self.__sockfile = self.__sock.makefile()
|
||||||
|
greeting = self.__json_read()
|
||||||
|
if greeting is None or not greeting.has_key('QMP'):
|
||||||
|
raise QMPConnectError
|
||||||
|
# Greeting seems ok, negotiate capabilities
|
||||||
|
resp = self.cmd('qmp_capabilities')
|
||||||
|
if "return" in resp:
|
||||||
|
return greeting
|
||||||
|
raise QMPCapabilitiesError
|
||||||
|
|
||||||
def __json_read(self, only_event=False):
|
def __json_read(self, only_event=False):
|
||||||
while True:
|
while True:
|
||||||
data = self.__sockfile.readline()
|
data = self.__sockfile.readline()
|
||||||
@ -67,14 +83,19 @@ class QEMUMonitorProtocol:
|
|||||||
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
||||||
"""
|
"""
|
||||||
self.__sock.connect(self.__address)
|
self.__sock.connect(self.__address)
|
||||||
greeting = self.__json_read()
|
return self.__negotiate_capabilities()
|
||||||
if greeting is None or not greeting.has_key('QMP'):
|
|
||||||
raise QMPConnectError
|
def accept(self):
|
||||||
# Greeting seems ok, negotiate capabilities
|
"""
|
||||||
resp = self.cmd('qmp_capabilities')
|
Await connection from QMP Monitor and perform capabilities negotiation.
|
||||||
if "return" in resp:
|
|
||||||
return greeting
|
@return QMP greeting dict
|
||||||
raise QMPCapabilitiesError
|
@raise socket.error on socket connection errors
|
||||||
|
@raise QMPConnectError if the greeting is not received
|
||||||
|
@raise QMPCapabilitiesError if fails to negotiate capabilities
|
||||||
|
"""
|
||||||
|
self.__sock, _ = self.__sock.accept()
|
||||||
|
return self.__negotiate_capabilities()
|
||||||
|
|
||||||
def cmd_obj(self, qmp_cmd):
|
def cmd_obj(self, qmp_cmd):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user