Run PRE and POST global hooks in case of succesfull job execution.
POST hooks always always executed with status SUCCEEDED. On errors
POST hooks will not be executed because all the errors cause related
exeptions.

Also fix test which expects that hooks run only once. Now rpc called
twice: for usual hooks and for global hooks. Other test fix is that
currently the hooks path for the last hook is always 'global'.

Signed-off-by: Oleg Ponomarev <[email protected]>
---
 lib/cmdlib/common.py                          |  2 ++
 lib/mcpu.py                                   | 17 ++++++++++++-----
 src/Ganeti/Constants.hs                       |  9 +++++++++
 test/py/cmdlib/cluster_unittest.py            |  6 ++++--
 test/py/cmdlib/testsupport/cmdlib_testcase.py |  3 ++-
 5 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/lib/cmdlib/common.py b/lib/cmdlib/common.py
index 696a331..5b70e16 100644
--- a/lib/cmdlib/common.py
+++ b/lib/cmdlib/common.py
@@ -186,6 +186,8 @@ def RunPostHook(lu, node_name):
   hm = lu.proc.BuildHooksManager(lu)
   try:
     hm.RunPhase(constants.HOOKS_PHASE_POST, node_names=[node_name])
+    hm.RunPhase(constants.HOOKS_PHASE_POST, [node_name], True,
+                constants.POST_HOOKS_STATUS_SUCCEEDED)
   except Exception, err: # pylint: disable=W0703
     lu.LogWarning("Errors occurred running hooks on %s: %s",
                   node_name, err)
diff --git a/lib/mcpu.py b/lib/mcpu.py
index 209e859..9be8d46 100644
--- a/lib/mcpu.py
+++ b/lib/mcpu.py
@@ -305,6 +305,7 @@ class Processor(object):
     self.cfg = context.GetConfig(ec_id)
     self.rpc = context.GetRpc(self.cfg)
     self.hmclass = hooksmaster.HooksMaster
+    self._hm = None
     self._enable_locks = enable_locks
     self.wconfd = wconfd # Indirection to allow testing
     self._wconfdcontext = context.GetWConfdContext(ec_id)
@@ -483,8 +484,9 @@ class Processor(object):
     lu.cfg.OutDate()
     lu.CheckPrereq()
 
-    hm = self.BuildHooksManager(lu)
-    h_results = hm.RunPhase(constants.HOOKS_PHASE_PRE)
+    self._hm = self.BuildHooksManager(lu)
+    self._hm.RunPhase(constants.HOOKS_PHASE_PRE, None, True)
+    h_results = self._hm.RunPhase(constants.HOOKS_PHASE_PRE)
     lu.HooksCallBack(constants.HOOKS_PHASE_PRE, h_results,
                      self.Log, None)
 
@@ -504,19 +506,20 @@ class Processor(object):
     lusExecuting[0] += 1
     try:
       result = _ProcessResult(submit_mj_fn, lu.op, lu.Exec(self.Log))
-      h_results = hm.RunPhase(constants.HOOKS_PHASE_POST)
+      h_results = self._hm.RunPhase(constants.HOOKS_PHASE_POST)
       result = lu.HooksCallBack(constants.HOOKS_PHASE_POST, h_results,
                                 self.Log, result)
     finally:
       # FIXME: This needs locks if not lu_class.REQ_BGL
       lusExecuting[0] -= 1
       if write_count != self.cfg.write_count:
-        hm.RunConfigUpdate()
+        self._hm.RunConfigUpdate()
 
     return result
 
   def BuildHooksManager(self, lu):
-    return self.hmclass.BuildFromLu(lu.rpc.call_hooks_runner, lu)
+    return self.hmclass.BuildFromLu(lu.rpc.call_hooks_runner, lu,
+                                    self.GetECId())
 
   def _LockAndExecLU(self, lu, level, calc_timeout, pending=None):
     """Execute a Logical Unit, with the needed locks.
@@ -715,6 +718,10 @@ class Processor(object):
 
     self._CheckLUResult(op, result)
 
+    if self._hm is not None:
+      self._hm.RunPhase(constants.HOOKS_PHASE_POST, None, True,
+                        constants.POST_HOOKS_STATUS_SUCCEEDED)
+
     return result
 
   def Log(self, *args):
diff --git a/src/Ganeti/Constants.hs b/src/Ganeti/Constants.hs
index 180ff4d..93b817a 100644
--- a/src/Ganeti/Constants.hs
+++ b/src/Ganeti/Constants.hs
@@ -729,6 +729,15 @@ hooksVersion = 2
 globalHooksDir :: String
 globalHooksDir = "global"
 
+postHooksStatusSucceeded :: String
+postHooksStatusSucceeded = "succeeded"
+
+postHooksStatusFailed :: String
+postHooksStatusFailed = "failed"
+
+postHooksStatusDisappeared :: String
+postHooksStatusDisappeared = "disappeared"
+
 -- * Hooks subject type (what object type does the LU deal with)
 
 htypeCluster :: String
diff --git a/test/py/cmdlib/cluster_unittest.py 
b/test/py/cmdlib/cluster_unittest.py
index 24c1ca9..31772e0 100644
--- a/test/py/cmdlib/cluster_unittest.py
+++ b/test/py/cmdlib/cluster_unittest.py
@@ -232,8 +232,9 @@ class TestLUClusterDestroy(CmdlibTestCase):
 
     self.ExecOpCode(op)
 
+    # The hooksdir name should be "global" because of global hooks
     self.assertSingleHooksCall([self.master.name],
-                               "cluster-destroy",
+                               constants.GLOBAL_HOOKS_DIR,
                                constants.HOOKS_PHASE_POST)
 
 
@@ -244,8 +245,9 @@ class TestLUClusterPostInit(CmdlibTestCase):
 
     self.ExecOpCode(op)
 
+    # The hooksdir name should be "global" because of global hooks
     self.assertSingleHooksCall([self.master.uuid],
-                               "cluster-init",
+                               constants.GLOBAL_HOOKS_DIR,
                                constants.HOOKS_PHASE_POST)
 
 
diff --git a/test/py/cmdlib/testsupport/cmdlib_testcase.py 
b/test/py/cmdlib/testsupport/cmdlib_testcase.py
index 4e459f3..bd96418 100644
--- a/test/py/cmdlib/testsupport/cmdlib_testcase.py
+++ b/test/py/cmdlib/testsupport/cmdlib_testcase.py
@@ -362,8 +362,9 @@ class CmdlibTestCase(testutils.GanetiTestCase):
     @see L{assertHooksCall} for parameter description.
 
     """
+    # Count below is set to 2 because both hooks ang global hooks will run.
     self.assertHooksCall(nodes, hook_path, phase,
-                         environment=environment, count=1)
+                         environment=environment, count=2)
 
   def CopyOpCode(self, opcode, **kwargs):
     """Creates a copy of the given opcode and applies modifications to it
-- 
2.6.0.rc2.230.g3dd15c0

Reply via email to