On Fri, Dec 20, 2013 at 10:47 AM, Helga Velroyen <[email protected]> wrote:

>
>
>
> On Fri, Dec 20, 2013 at 10:09 AM, Hrvoje Ribicic <[email protected]> wrote:
>
>> The RAPI workload script supplies work for the RAPI compatibility
>> tests. The initial version does very little, but can be expanded
>> as needed.
>>
>> Signed-off-by: Hrvoje Ribicic <[email protected]>
>> ---
>>  Makefile.am         |   3 +-
>>  qa/rapi-workload.py | 158
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 160 insertions(+), 1 deletion(-)
>>  create mode 100755 qa/rapi-workload.py
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index e74f58b..14cb774 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -970,7 +970,8 @@ qa_scripts = \
>>         qa/qa_os.py \
>>         qa/qa_rapi.py \
>>         qa/qa_tags.py \
>> -       qa/qa_utils.py
>> +       qa/qa_utils.py \
>> +        qa/rapi-workload.py
>>
>>  bin_SCRIPTS =
>>  if WANT_HTOOLS
>> diff --git a/qa/rapi-workload.py b/qa/rapi-workload.py
>> new file mode 100755
>> index 0000000..f936d95
>> --- /dev/null
>> +++ b/qa/rapi-workload.py
>> @@ -0,0 +1,158 @@
>> +#!/usr/bin/python -u
>> +#
>> +
>> +# Copyright (C) 2013 Google Inc.
>> +#
>> +# This program is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 2 of the License, or
>> +# (at your option) any later version.
>> +#
>> +# This program is distributed in the hope that it will be useful, but
>> +# WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +# General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with this program; if not, write to the Free Software
>> +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
>> +# 02110-1301, USA.
>> +
>> +
>> +"""Script for providing a large amount of RAPI calls to Ganeti.
>> +
>> +"""
>> +
>> +# pylint: disable=C0103
>> +# due to invalid name
>> +
>> +
>> +import sys
>> +
>> +from ganeti.rapi.client import GanetiApiError
>> +
>> +import qa_config
>> +import qa_node
>> +import qa_rapi
>> +
>> +
>> +# The purpose of this file is to provide a stable and extensive RAPI
>> workload
>> +# that manipulates the cluster only using RAPI commands, with the
>> assumption
>> +# that an empty cluster was set up beforehand. All the nodes that can be
>> added
>> +# to the cluster should be a part of it, and no instances should be
>> present.
>> +#
>> +# Its intended use is in RAPI compatibility tests, where different
>> versions with
>> +# possibly vastly different QAs must be compared. Running the QA on both
>> +# versions of the cluster will produce RAPI calls, but there is no
>> guarantee
>> +# that they will match, or that functions invoked in between will not
>> change the
>> +# results.
>> +#
>> +# By using only RAPI functions, we are sure to be able to capture and
>> log all
>> +# the changes in cluster state, and be able to compare them afterwards.
>> +#
>> +# The functionality of the QA is still used to generate a functioning,
>> +# RAPI-enabled cluster, and to set up a C{GanetiRapiClient} capable of
>> issuing
>> +# commands to the cluster.
>> +#
>> +# Due to the fact that not all calls issued as a part of the workload
>> might be
>> +# implemented in the different versions of Ganeti, the client does not
>> halt or
>> +# produce a non-zero exit code upon encountering a RAPI error. Instead,
>> it
>> +# reports it and moves on. Any utility comparing the requests should
>> account for
>> +# this.
>> +
>> +
>> +def MockMethod(*_args, **_kwargs):
>> +  """ Absorbs all arguments, does nothing, returns None.
>> +
>> +  """
>> +  return None
>> +
>> +
>> +def InvokerCreator(fn, name):
>> +  """ Returns an invoker function that will invoke the given function
>> +  with any arguments passed to the invoker at a later time, while
>> +  catching any specific non-fatal errors we would like to know more
>> +  about.
>> +
>> +  @type fn arbitrary function
>> +  @param fn The function to invoke later.
>> +  @type name string
>> +  @param name The name of the function, for debugging purposes.
>> +  @rtype function
>> +
>> +  """
>> +  def decoratedFn(*args, **kwargs):
>> +    result = None
>> +    try:
>> +      print "Using method %s" % name
>> +      result = fn(*args, **kwargs)
>> +    except GanetiApiError as e:
>> +      print "RAPI error while performing function %s : %s" % \
>> +            (name, str(e))
>> +    return result
>> +
>> +  return decoratedFn
>> +
>> +
>> +RAPI_USERNAME = "ganeti-qa"
>> +
>> +
>> +class GanetiRapiClientWrapper(object):
>> +  """ Creates and initializes a GanetiRapiClient, and acts as a wrapper
>> invoking
>> +  only the methods that the version of the client actually uses.
>> +
>> +  """
>> +  def __init__(self):
>> +    self._client = qa_rapi.Setup(RAPI_USERNAME,
>> +                                 qa_rapi.LookupRapiSecret(RAPI_USERNAME))
>> +
>> +  def __getattr__(self, attr):
>> +    """ Fetches an attribute from the underlying client if necessary.
>> +
>> +    """
>> +    #Assuming that this method exposes no public methods of its own,
>> +    #and that any private methods are named according to the style
>> +    #guide, this will stop infinite loops in attribute fetches.
>>
>
> super-nit: I think it more consistent with the ganeti code to have a
> whitespace after "#"
>
>

Yup, and that is my usual style - don't know how this slipped by.

Minor interdiff FYI:

diff --git a/qa/rapi-workload.py b/qa/rapi-workload.py
index f936d95..72eedce 100755
--- a/qa/rapi-workload.py
+++ b/qa/rapi-workload.py
@@ -110,9 +110,9 @@ class GanetiRapiClientWrapper(object):
     """ Fetches an attribute from the underlying client if necessary.

     """
-    #Assuming that this method exposes no public methods of its own,
-    #and that any private methods are named according to the style
-    #guide, this will stop infinite loops in attribute fetches.
+    # Assuming that this method exposes no public methods of its own,
+    # and that any private methods are named according to the style
+    # guide, this will stop infinite loops in attribute fetches.
     if attr.startswith("_"):
       return self.__getattribute__(attr)



> +    if attr.startswith("_"):
>> +      return self.__getattribute__(attr)
>> +
>> +    try:
>> +      return InvokerCreator(self._client.__getattribute__(attr), attr)
>> +    except AttributeError:
>> +      print "Missing method %s; supplying mock method" % attr
>> +      return MockMethod
>> +
>> +
>> +def Workload(client):
>> +  """ The actual RAPI workload used for tests.
>> +
>> +  @type client C{GanetiRapiClientWrapper}
>> +  @param client A wrapped RAPI client.
>> +
>> +  """
>> +  print client.GetVersion()
>> +
>> +
>> +def Usage():
>> +  sys.stderr.write("Usage:\n\trapi-workload.py qa-config-file")
>> +
>> +
>> +def Main():
>> +  if len(sys.argv) < 2:
>> +    Usage()
>> +
>> +  qa_config.Load(sys.argv[1])
>> +
>> +  # Only the master will be present after a fresh QA cluster setup, so
>> we have
>> +  # to invoke this to get all the other nodes.
>> +  qa_node.TestNodeAddAll()
>> +
>> +  client = GanetiRapiClientWrapper()
>> +
>> +  Workload(client)
>> +
>> +  qa_node.TestNodeRemoveAll()
>> +
>> +
>> +if __name__ == "__main__":
>> +  Main()
>> --
>> 1.8.5.1
>>
>>
> LGTM, thanks
>
>
> --
> --
> Helga Velroyen | Software Engineer | [email protected] |
>
> Google Germany GmbH
> Dienerstr. 12
> 80331 München
>
> Registergericht und -nummer: Hamburg, HRB 86891
> Sitz der Gesellschaft: Hamburg
> Geschäftsführer: Graham Law, Christine Elizabeth Flores
>

Reply via email to