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       |  13 ++++++
 qa/qa-sample.json     |   2 +
 qa/qa_global_hooks.py | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++
 qa/qa_utils.py        |  11 +++++
 5 files changed, 147 insertions(+)
 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..2798a69 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
@@ -947,6 +948,16 @@ def RunPerformanceTests():
       qa_config.ReleaseManyNodes(inodes)
 
 
+def RunGlobalHooksTests():
+  if not qa_config.TestEnabled("global-hooks"):
+    return
+  qa_global_hooks.TestHooksInitialize()
+  qa_global_hooks.TestHookSucceeded()
+  qa_global_hooks.TestHookFailed()
+  qa_global_hooks.TestHookDisappeared()
+  qa_global_hooks.TestHooksDeinitialize()
+
+
 def RunQa():
   """Main QA body.
 
@@ -965,6 +976,8 @@ def RunQa():
   RunTestBlock(RunNetworkTests)
   RunTestBlock(RunFilterTests)
 
+  RunTestBlock(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..4db151b
--- /dev/null
+++ b/qa/qa_global_hooks.py
@@ -0,0 +1,120 @@
+#
+#
+
+# Copyright (C) 2012, 2014 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):
+  h_fname = H_DIR + "/%d_OP_TEST_DELAY_" % job_id
+  if phase == "pre":
+    return h_fname + phase
+  return h_fname + phase + "_" + 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_common = "CMD=$'#!/bin/sh\\ntouch %s/" % H_DIR + \
+             "$GANETI_JOB_ID\"_\"$GANETI_OP_CODE"
+  h_pre = h_common + "\"_pre\"'"
+  h_post = h_common + "\"_post_\"$GANETI_POST_STATUS'"
+  h_name = "/qa_test_hook"
+  h_echo = ";echo \"$CMD\" > %s" + h_name
+  GetCommandOutput(master, h_pre + h_echo % PRE_PATH)
+  GetCommandOutput(master, h_post + h_echo % POST_PATH)
+  h_chmod = "chmod +x "
+  GetCommandOutput(master, h_chmod + PRE_PATH + h_name)
+  GetCommandOutput(master, h_chmod + POST_PATH + h_name)
+
+
+def TestHookSucceeded():
+  master = GetMasterNode().primary
+  job_id = ExecuteJobProducingCommand("gnt-debug delay --submit 1")
+  time.sleep(3)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "pre")), True)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_SUCCESS)), True)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_ERROR)), False)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_DISAPPEAR)), False)
+
+
+def TestHookFailed():
+  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)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_ERROR)), True)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_DISAPPEAR)), False)
+
+
+def TestHookDisappeared():
+  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)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_SUCCESS)), False)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_ERROR)), False)
+  AssertEqual(IsFileExists(master, _GetHookFilePath(job_id, "post",
+                           constants.POST_HOOKS_STATUS_DISAPPEAR)), True)
+
+
+def TestHooksDeinitialize():
+  master = GetMasterNode().primary
+  rm = "rm "
+  GetCommandOutput(master, rm + PRE_PATH + "/*")
+  GetCommandOutput(master, rm + POST_PATH + "/*")
+  GetCommandOutput(master, rm + "-rf " + H_DIR)
diff --git a/qa/qa_utils.py b/qa/qa_utils.py
index f2b2c2e..b90e944 100644
--- a/qa/qa_utils.py
+++ b/qa/qa_utils.py
@@ -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

Reply via email to