Re: [Autotest] [KVM-AUTOTEST PATCH 13/14] KVM test: kvm_monitor.py: add QMP interface
On 06/14/2010 05:39 AM, Amos Kong wrote: > On Sun, Jun 13, 2010 at 05:33:44PM +0300, Michael Goldish wrote: >> An initial QMP client implementation. >> Should be fully functional and supports asynchronous events. >> However, most tests must be modified to support it, because it returns output >> in a different format from the human monitor (the human monitor returns >> strings >> and the QMP one returns dicts or lists). >> >> To enable QMP, set main_monitor to a monitor whose monitor_type is "qmp". >> >> For example (a single QMP monitor): >> >> monitors = monitor1 >> monitor_type_monitor1 = qmp >> main_monitor = monitor1 >> >> Another example (multiple monitors, both human and QMP): >> >> monitors = MyMonitor SomeOtherMonitor YetAnotherMonitor # defines 3 >> monitors >> monitor_type = human# default for all monitors >> monitor_type_SomeOtherMonitor = qmp # applies only to >> SomeOtherMonitor >> monitor_type_YetAnotherMonitor = qmp# applies only to >> YetAnotherMonitor >> main_monitor = SomeOtherMonitor # the main monitor is a QMP one, >> so >> # the test will use QMP >> >> Note: >> Monitor methods now raise exceptions such as MonitorLockError and >> QMPCmdError. >> If this turns out to be a bad idea, it shouldn't be hard to revert to the old >> convention of returning a (status, output) tuple. >> >> Signed-off-by: Michael Goldish >> --- >> client/tests/kvm/kvm_monitor.py | 275 >> +++ >> client/tests/kvm/kvm_vm.py |6 +- >> 2 files changed, 279 insertions(+), 2 deletions(-) >> >> diff --git a/client/tests/kvm/kvm_monitor.py >> b/client/tests/kvm/kvm_monitor.py >> index c5cf9c3..76a1a83 100644 >> --- a/client/tests/kvm/kvm_monitor.py >> +++ b/client/tests/kvm/kvm_monitor.py >> @@ -6,6 +6,11 @@ Interfaces to the QEMU monitor. >> >> import socket, time, threading, logging >> import kvm_utils >> +try: >> +import json >> +except ImportError: >> +logging.warning("Could not import json module. " >> +"QMP monitor functionality disabled.") >> >> >> class MonitorError(Exception): >> @@ -28,6 +33,10 @@ class MonitorProtocolError(MonitorError): >> pass >> >> >> +class QMPCmdError(MonitorError): >> +pass >> + >> + >> class Monitor: >> """ >> Common code for monitor classes. >> @@ -114,6 +123,8 @@ class HumanMonitor(Monitor): >> suppress_exceptions is False >> @raise MonitorProtocolError: Raised if the initial (qemu) prompt >> isn't >> found and suppress_exceptions is False >> +@note: Other exceptions may be raised. See _get_command_output's >> +docstring. >> """ >> try: >> Monitor.__init__(self, filename) >> @@ -354,3 +365,267 @@ class HumanMonitor(Monitor): >> @return: The command's output >> """ >> return self._get_command_output("mouse_button %d" % state) >> + >> + >> +class QMPMonitor(Monitor): >> +""" >> +Wraps QMP monitor commands. >> +""" >> + >> +def __init__(self, filename, suppress_exceptions=False): >> +""" >> +Connect to the monitor socket and issue the qmp_capabilities command >> + >> +@param filename: Monitor socket filename >> +@raise MonitorConnectError: Raised if the connection fails and >> +suppress_exceptions is False >> +@note: Other exceptions may be raised if the qmp_capabilities >> command >> +fails. See _get_command_output's docstring. >> +""" >> +try: >> +Monitor.__init__(self, filename) >> + >> +self.protocol = "qmp" >> +self.events = [] >> + >> +# Issue qmp_capabilities >> +self._get_command_output("qmp_capabilities") >> + >> +except MonitorError, e: >> +if suppress_exceptions: >> +logging.warn(e) >> +else: >> +raise >> + >> + >> +# Private methods >> + >> +def _build_cmd(self, cmd, args=None): >> +obj = {"execute": cmd} >> +if args: >> +obj["arguments"] = args >> +return obj >> + >> + >> +def _read_objects(self, timeout=5): >> +""" >> +Read lines from monitor and try to decode them. >> +Stop when all available lines have been successfully decoded, or >> when >> +timeout expires. If any decoded objects are asynchronous events, >> store >> +them in self.events. Return all decoded objects. >> + >> +@param timeout: Time to wait for all lines to decode successfully >> +@return: A list of objects >> +""" >> +s = "" >> +objs = [] >> +end_time = time.time() + timeout >> +while time.time() < end_time: >> +s += self._recvall() >> +for line in s.splitlines
Re: [Autotest] [KVM-AUTOTEST PATCH 13/14] KVM test: kvm_monitor.py: add QMP interface
On Sun, Jun 13, 2010 at 05:33:44PM +0300, Michael Goldish wrote: > An initial QMP client implementation. > Should be fully functional and supports asynchronous events. > However, most tests must be modified to support it, because it returns output > in a different format from the human monitor (the human monitor returns > strings > and the QMP one returns dicts or lists). > > To enable QMP, set main_monitor to a monitor whose monitor_type is "qmp". > > For example (a single QMP monitor): > > monitors = monitor1 > monitor_type_monitor1 = qmp > main_monitor = monitor1 > > Another example (multiple monitors, both human and QMP): > > monitors = MyMonitor SomeOtherMonitor YetAnotherMonitor # defines 3 > monitors > monitor_type = human# default for all monitors > monitor_type_SomeOtherMonitor = qmp # applies only to SomeOtherMonitor > monitor_type_YetAnotherMonitor = qmp# applies only to > YetAnotherMonitor > main_monitor = SomeOtherMonitor # the main monitor is a QMP one, > so > # the test will use QMP > > Note: > Monitor methods now raise exceptions such as MonitorLockError and QMPCmdError. > If this turns out to be a bad idea, it shouldn't be hard to revert to the old > convention of returning a (status, output) tuple. > > Signed-off-by: Michael Goldish > --- > client/tests/kvm/kvm_monitor.py | 275 > +++ > client/tests/kvm/kvm_vm.py |6 +- > 2 files changed, 279 insertions(+), 2 deletions(-) > > diff --git a/client/tests/kvm/kvm_monitor.py b/client/tests/kvm/kvm_monitor.py > index c5cf9c3..76a1a83 100644 > --- a/client/tests/kvm/kvm_monitor.py > +++ b/client/tests/kvm/kvm_monitor.py > @@ -6,6 +6,11 @@ Interfaces to the QEMU monitor. > > import socket, time, threading, logging > import kvm_utils > +try: > +import json > +except ImportError: > +logging.warning("Could not import json module. " > +"QMP monitor functionality disabled.") > > > class MonitorError(Exception): > @@ -28,6 +33,10 @@ class MonitorProtocolError(MonitorError): > pass > > > +class QMPCmdError(MonitorError): > +pass > + > + > class Monitor: > """ > Common code for monitor classes. > @@ -114,6 +123,8 @@ class HumanMonitor(Monitor): > suppress_exceptions is False > @raise MonitorProtocolError: Raised if the initial (qemu) prompt > isn't > found and suppress_exceptions is False > +@note: Other exceptions may be raised. See _get_command_output's > +docstring. > """ > try: > Monitor.__init__(self, filename) > @@ -354,3 +365,267 @@ class HumanMonitor(Monitor): > @return: The command's output > """ > return self._get_command_output("mouse_button %d" % state) > + > + > +class QMPMonitor(Monitor): > +""" > +Wraps QMP monitor commands. > +""" > + > +def __init__(self, filename, suppress_exceptions=False): > +""" > +Connect to the monitor socket and issue the qmp_capabilities command > + > +@param filename: Monitor socket filename > +@raise MonitorConnectError: Raised if the connection fails and > +suppress_exceptions is False > +@note: Other exceptions may be raised if the qmp_capabilities command > +fails. See _get_command_output's docstring. > +""" > +try: > +Monitor.__init__(self, filename) > + > +self.protocol = "qmp" > +self.events = [] > + > +# Issue qmp_capabilities > +self._get_command_output("qmp_capabilities") > + > +except MonitorError, e: > +if suppress_exceptions: > +logging.warn(e) > +else: > +raise > + > + > +# Private methods > + > +def _build_cmd(self, cmd, args=None): > +obj = {"execute": cmd} > +if args: > +obj["arguments"] = args > +return obj > + > + > +def _read_objects(self, timeout=5): > +""" > +Read lines from monitor and try to decode them. > +Stop when all available lines have been successfully decoded, or when > +timeout expires. If any decoded objects are asynchronous events, > store > +them in self.events. Return all decoded objects. > + > +@param timeout: Time to wait for all lines to decode successfully > +@return: A list of objects > +""" > +s = "" > +objs = [] > +end_time = time.time() + timeout > +while time.time() < end_time: > +s += self._recvall() > +for line in s.splitlines(): > +if not line: > +continue > +try: > +obj = json.loads(line) > +except: > +# Foun