LGTM, thanks On Thu, Nov 26, 2015 at 1:08 PM, 'Oleg Ponomarev' via ganeti-devel < [email protected]> wrote:
> Test 3 main cases of global post hooks usage: > - successful LU execution; > - LU with the prerequisites failed; > - disappeared LU process. > All the tests are performed on the master node. > > Signed-off-by: Oleg Ponomarev <[email protected]> > --- > Makefile.am | 1 + > qa/ganeti-qa.py | 3 + > qa/qa-sample.json | 2 + > qa/qa_global_hooks.py | 167 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > qa/qa_utils.py | 13 +++- > 5 files changed, 185 insertions(+), 1 deletion(-) > create mode 100644 qa/qa_global_hooks.py > > diff --git a/Makefile.am b/Makefile.am > index 8ba84a5..0080f00 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -1347,6 +1347,7 @@ qa_scripts = \ > qa/qa_error.py \ > qa/qa_filters.py \ > qa/qa_group.py \ > + qa/qa_global_hooks.py \ > qa/qa_instance.py \ > qa/qa_instance_utils.py \ > qa/qa_iptables.py \ > diff --git a/qa/ganeti-qa.py b/qa/ganeti-qa.py > index 9b475e2..36a9263 100755 > --- a/qa/ganeti-qa.py > +++ b/qa/ganeti-qa.py > @@ -48,6 +48,7 @@ import qa_env > import qa_error > import qa_filters > import qa_group > +import qa_global_hooks > import qa_instance > import qa_iptables > import qa_maintd > @@ -965,6 +966,8 @@ def RunQa(): > RunTestBlock(RunNetworkTests) > RunTestBlock(RunFilterTests) > > + RunTestIf("global-hooks", qa_global_hooks.RunGlobalHooksTests) > + > # The master shouldn't be readded or put offline; "delay" needs a > non-master > # node to test > pnode = qa_config.AcquireNode(exclude=qa_config.GetMasterNode()) > diff --git a/qa/qa-sample.json b/qa/qa-sample.json > index ac10a05..9b0a1a1 100644 > --- a/qa/qa-sample.json > +++ b/qa/qa-sample.json > @@ -253,6 +253,8 @@ > > "job-list": true, > > + "global-hooks": true, > + > "jobqueue-performance": true, > "parallel-performance": true, > > diff --git a/qa/qa_global_hooks.py b/qa/qa_global_hooks.py > new file mode 100644 > index 0000000..8e5457a > --- /dev/null > +++ b/qa/qa_global_hooks.py > @@ -0,0 +1,167 @@ > +# > +# > + > +# Copyright (C) 2015 Google Inc. > +# All rights reserved. > +# > +# Redistribution and use in source and binary forms, with or without > +# modification, are permitted provided that the following conditions are > +# met: > +# > +# 1. Redistributions of source code must retain the above copyright > notice, > +# this list of conditions and the following disclaimer. > +# > +# 2. Redistributions in binary form must reproduce the above copyright > +# notice, this list of conditions and the following disclaimer in the > +# documentation and/or other materials provided with the distribution. > +# > +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED > +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A > PARTICULAR > +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, > +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, > +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR > +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF > +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING > +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS > +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + > + > +"""QA tests for the universal job hooks. > + > +""" > + > +import time > + > +from ganeti import constants > +from ganeti import pathutils > +from qa_config import GetMasterNode > +from qa_job_utils import ExecuteJobProducingCommand > +from qa_utils import AssertEqual, GetCommandOutput, IsFileExists > + > +PRE_PATH = "%s/global-pre.d" % pathutils.HOOKS_BASE_DIR > +POST_PATH = "%s/global-post.d" % pathutils.HOOKS_BASE_DIR > +H_DIR = "/var/log/ganeti/qa_global_hooks" > + > + > +def _GetHookFilePath(job_id, phase, status=None): > + """Returns the path to the qa hooks temporary files. > + > + """ > + h_fname = H_DIR + "/%d_OP_TEST_DELAY_%s" % (job_id, phase) > + if phase == "pre": > + return h_fname > + return h_fname + "_" + status > + > + > +def TestHooksInitialize(): > + """Creates global hooks on the master node > + > + """ > + master = GetMasterNode().primary > + GetCommandOutput(master, "mkdir -p %s" % pathutils.HOOKS_BASE_DIR) > + GetCommandOutput(master, "mkdir -p %s" % PRE_PATH) > + GetCommandOutput(master, "mkdir -p %s" % POST_PATH) > + GetCommandOutput(master, "mkdir -p %s" % H_DIR) > + h_name = "/qa_test_hook" > + create_hook_common = """ > +FOUT=%s > +echo '#!/bin/sh' > $FOUT > +echo 'touch %s/$GANETI_JOB_ID"_"$GANETI_OP_CODE%s' >> $FOUT > +chmod +x $FOUT > +""" > + create_pre = create_hook_common % (PRE_PATH + h_name, H_DIR, '"_pre"') > + create_post = create_hook_common % (POST_PATH + h_name, H_DIR, > + '"_post_"$GANETI_POST_STATUS') > + GetCommandOutput(master, create_pre) > + GetCommandOutput(master, create_post) > + > + > +def TestHookSucceeded(): > + """Checks whether the global hooks have been executed (status succes). > + > + - Global pre hook should has been executed. > + - Global post hook should with status *success* should has been > executed. > + - Global post hooks with failed statuses shouldn't have been executed. > + """ > + master = GetMasterNode().primary > + job_id = ExecuteJobProducingCommand("gnt-debug delay --submit 1") > + time.sleep(3) > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "pre")), True, > + "Global pre hook hasn't been executed.") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_SUCCESS)), True, > + "Global post hook hasn't been executed with status > *success*") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_ERROR)), False, > + "Global post hook has been executed with status *error*") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_DISAPPEARED)), > False, > + "Global post hook has been executed with status > *disappeared*") > + > + > +def TestHookFailed(): > + """Checks whether the global hooks have been executed (status error). > + > + - Global post hook should with status *error* should has been executed. > + - Global post hook with other statuses shouldn't have been executed. > + """ > + master = GetMasterNode().primary > + job_id = ExecuteJobProducingCommand("gnt-debug delay --submit 0") > + time.sleep(1) > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_SUCCESS)), False, > + "Global post hook has been executed with status *success*") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_ERROR)), True, > + "Global post hook hasn't been executed with status *error*") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_DISAPPEARED)), > False, > + "Global post hook has been executed with status > *disappeared*") > + > + > +def TestHookDisappeared(): > + """Checks whether the global hooks have been executed (status > disappeared). > + > + - Global pre hook should has been executed. > + - Global post hook should with status *disappeared* should has been > executed. > + - Global post hook with other statuses shouldn't have been executed. > + """ > + master = GetMasterNode().primary > + job_id = ExecuteJobProducingCommand("gnt-debug delay --submit 10") > + time.sleep(1) > + GetCommandOutput(master, "gnt-job cancel --kill --yes-do-it %d" % > job_id) > + time.sleep(10) > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "pre")), True, > + "Global pre hook hasn't been executed.") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_SUCCESS)), False, > + "Global post hook has been executed with status *success*") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_ERROR)), False, > + "Global post hook has been executed with status *error*") > + AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post", > + constants.POST_HOOKS_STATUS_DISAPPEARED)), > True, > + "Global post hook hasn't been executed with status > *disappeared*") > + > + > +def TestHooksCleanup(): > + """Remove the directories created by the tests > + > + """ > + master = GetMasterNode().primary > + GetCommandOutput(master, "rm %s/*" % PRE_PATH) > + GetCommandOutput(master, "rm %s/*" % POST_PATH) > + GetCommandOutput(master, "rm -rf %s" % H_DIR) > + > + > +def RunGlobalHooksTests(): > + """Runs tests for global hooks considering different job execution > cases. > + > + """ > + TestHooksInitialize() > + TestHookSucceeded() > + TestHookFailed() > + TestHookDisappeared() > + TestHooksCleanup() > diff --git a/qa/qa_utils.py b/qa/qa_utils.py > index f2b2c2e..94e1dce 100644 > --- a/qa/qa_utils.py > +++ b/qa/qa_utils.py > @@ -1,7 +1,7 @@ > # > # > > -# Copyright (C) 2007, 2011, 2012, 2013 Google Inc. > +# Copyright (C) 2007, 2011, 2012, 2013, 2015 Google Inc. > # All rights reserved. > # > # Redistribution and use in source and binary forms, with or without > @@ -523,6 +523,17 @@ def BackupFile(node, path): > return result > > > +def IsFileExists(node, path): > + """Checks if a file on the node exists. > + > + """ > + cmd = ("[[ -f \"%s\" ]] && echo yes || echo no" % path) > + > + # Return temporary filename > + result = GetCommandOutput(node, cmd).strip() > + return True if result == "yes" else False > + > + > @contextlib.contextmanager > def CheckFileUnmodified(node, filename): > """Checks that the content of a given file remains the same after > running a > -- > 2.6.0.rc2.230.g3dd15c0 > > Hrvoje Ribicic Ganeti Engineering Google Germany GmbH Dienerstr. 12, 80331, München Geschäftsführer: Matthew Scott Sucherman, Paul Terence Manicle Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Diese E-Mail ist vertraulich. Wenn Sie nicht der richtige Adressat sind, leiten Sie diese bitte nicht weiter, informieren Sie den Absender und löschen Sie die E-Mail und alle Anhänge. Vielen Dank. This e-mail is confidential. If you are not the right addressee please do not forward it, please inform the sender, and please erase this e-mail including any attachments. Thanks.
