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 "#" > + 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
