Re: [Autotest] [KVM-AUTOTEST PATCH 13/14] KVM test: kvm_monitor.py: add QMP interface

2010-06-13 Thread Michael Goldish
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

2010-06-13 Thread Amos Kong
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