+
+class FakeEnvLU(cmdlib.LogicalUnit):
+ HPATH = "env_test_lu"
+ HTYPE = constants.HTYPE_GROUP
+
+ def __init__(self, *args):
+ cmdlib.LogicalUnit.__init__(self, *args)
+ self.hook_env = None
+
+ def BuildHooksEnv(self):
+ assert self.hook_env is not None
+ return self.hook_env
+
+ def BuildHooksNodes(self):
+ return (["localhost"], ["localhost"])
+
+
+class FakeNoHooksLU(cmdlib.NoHooksLU):
+ pass
+
+
+class TestHooksRunnerEnv(unittest.TestCase):
+ def setUp(self):
+ self._rpcs = []
+
+ self.op = opcodes.OpTestDummy(result=False, messages=[], fail=False)
+ self.lu = FakeEnvLU(FakeProc(), self.op, FakeContext(), None)
+
+ def _HooksRpc(self, *args):
+ self._rpcs.append(args)
+ return FakeHooksRpcSuccess(*args)
+
+ def _CheckEnv(self, env, phase, hpath):
+ self.assertTrue(env["PATH"].startswith("/sbin"))
+ self.assertEqual(env["GANETI_HOOKS_PHASE"], phase)
+ self.assertEqual(env["GANETI_HOOKS_PATH"], hpath)
+ self.assertEqual(env["GANETI_OP_CODE"], self.op.OP_ID)
+ self.assertEqual(env["GANETI_HOOKS_VERSION"], str(constants.HOOKS_VERSION))
+ self.assertEqual(env["GANETI_DATA_DIR"], constants.DATA_DIR)
+ if "GANETI_OBJECT_TYPE" in env:
+ self.assertEqual(env["GANETI_OBJECT_TYPE"], constants.HTYPE_GROUP)
+ else:
+ self.assertTrue(self.lu.HTYPE is None)
+
+ def testEmptyEnv(self):
+ # Check pre-phase hook
+ self.lu.hook_env = {}
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+ hm.RunPhase(constants.HOOKS_PHASE_PRE)
+
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(node_list, set(["localhost"]))
+ self.assertEqual(hpath, self.lu.HPATH)
+ self.assertEqual(phase, constants.HOOKS_PHASE_PRE)
+ self._CheckEnv(env, constants.HOOKS_PHASE_PRE, self.lu.HPATH)
+
+ # Check post-phase hook
+ self.lu.hook_env = {}
+ hm.RunPhase(constants.HOOKS_PHASE_POST)
+
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(node_list, set(["localhost"]))
+ self.assertEqual(hpath, self.lu.HPATH)
+ self.assertEqual(phase, constants.HOOKS_PHASE_POST)
+ self._CheckEnv(env, constants.HOOKS_PHASE_POST, self.lu.HPATH)
+
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ def testEnv(self):
+ # Check pre-phase hook
+ self.lu.hook_env = {
+ "FOO": "pre-foo-value",
+ }
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+ hm.RunPhase(constants.HOOKS_PHASE_PRE)
+
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(node_list, set(["localhost"]))
+ self.assertEqual(hpath, self.lu.HPATH)
+ self.assertEqual(phase, constants.HOOKS_PHASE_PRE)
+ self.assertEqual(env["GANETI_FOO"], "pre-foo-value")
+ self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
+ self._CheckEnv(env, constants.HOOKS_PHASE_PRE, self.lu.HPATH)
+
+ # Check post-phase hook
+ self.lu.hook_env = {
+ "FOO": "post-value",
+ "BAR": 123,
+ }
+ hm.RunPhase(constants.HOOKS_PHASE_POST)
+
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(node_list, set(["localhost"]))
+ self.assertEqual(hpath, self.lu.HPATH)
+ self.assertEqual(phase, constants.HOOKS_PHASE_POST)
+ self.assertEqual(env["GANETI_FOO"], "pre-foo-value")
+ self.assertEqual(env["GANETI_POST_FOO"], "post-value")
+ self.assertEqual(env["GANETI_POST_BAR"], "123")
+ self.assertFalse("GANETI_BAR" in env)
+ self._CheckEnv(env, constants.HOOKS_PHASE_POST, self.lu.HPATH)
+
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ # Check configuration update hook
+ hm.RunConfigUpdate()
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(set(node_list), set([self.lu.cfg.GetMasterNode()]))
+ self.assertEqual(hpath, constants.HOOKS_NAME_CFGUPDATE)
+ self.assertEqual(phase, constants.HOOKS_PHASE_POST)
+ self._CheckEnv(env, constants.HOOKS_PHASE_POST,
+ constants.HOOKS_NAME_CFGUPDATE)
+ self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
+ self.assertEqual(env["GANETI_FOO"], "pre-foo-value")
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ def testConflict(self):
+ for name in ["DATA_DIR", "OP_CODE"]:
+ self.lu.hook_env = { name: "value" }
+
+ # Test using a clean HooksMaster instance
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+
+ for phase in [constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST]:
+ self.assertRaises(AssertionError, hm.RunPhase, phase)
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ def testNoNodes(self):
+ self.lu.hook_env = {}
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+ hm.RunPhase(constants.HOOKS_PHASE_PRE, nodes=[])
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ def testSpecificNodes(self):
+ self.lu.hook_env = {}
+
+ nodes = [
+ "node1.example.com",
+ "node93782.example.net",
+ ]
+
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+
+ for phase in [constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST]:
+ hm.RunPhase(phase, nodes=nodes)
+
+ (node_list, hpath, rpc_phase, env) = self._rpcs.pop(0)
+ self.assertEqual(set(node_list), set(nodes))
+ self.assertEqual(hpath, self.lu.HPATH)
+ self.assertEqual(rpc_phase, phase)
+ self._CheckEnv(env, phase, self.lu.HPATH)
+
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ def testRunConfigUpdateNoPre(self):
+ self.lu.hook_env = {
+ "FOO": "value",
+ }
+
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+ hm.RunConfigUpdate()
+
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(set(node_list), set([self.lu.cfg.GetMasterNode()]))
+ self.assertEqual(hpath, constants.HOOKS_NAME_CFGUPDATE)
+ self.assertEqual(phase, constants.HOOKS_PHASE_POST)
+ self.assertEqual(env["GANETI_FOO"], "value")
+ self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
+ self._CheckEnv(env, constants.HOOKS_PHASE_POST,
+ constants.HOOKS_NAME_CFGUPDATE)
+
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ def testNoPreBeforePost(self):
+ self.lu.hook_env = {
+ "FOO": "value",
+ }
+
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+ hm.RunPhase(constants.HOOKS_PHASE_POST)
+
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(node_list, set(["localhost"]))
+ self.assertEqual(hpath, self.lu.HPATH)
+ self.assertEqual(phase, constants.HOOKS_PHASE_POST)
+ self.assertEqual(env["GANETI_FOO"], "value")
+ self.assertEqual(env["GANETI_POST_FOO"], "value")
+ self._CheckEnv(env, constants.HOOKS_PHASE_POST, self.lu.HPATH)
+
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ def testNoHooksLU(self):
+ self.lu = FakeNoHooksLU(FakeProc(), self.op, FakeContext(), None)
+ self.assertRaises(AssertionError, self.lu.BuildHooksEnv)
+ self.assertRaises(AssertionError, self.lu.BuildHooksNodes)
+
+ hm = mcpu.HooksMaster.BuildFromLu(self._HooksRpc, self.lu)
+ self.assertEqual(hm.pre_env, {})
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ hm.RunPhase(constants.HOOKS_PHASE_PRE)
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ hm.RunPhase(constants.HOOKS_PHASE_POST)
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ hm.RunConfigUpdate()
+
+ (node_list, hpath, phase, env) = self._rpcs.pop(0)
+ self.assertEqual(set(node_list), set([self.lu.cfg.GetMasterNode()]))
+ self.assertEqual(hpath, constants.HOOKS_NAME_CFGUPDATE)
+ self.assertEqual(phase, constants.HOOKS_PHASE_POST)
+ self.assertFalse(compat.any(key.startswith("GANETI_POST") for key in env))
+ self._CheckEnv(env, constants.HOOKS_PHASE_POST,
+ constants.HOOKS_NAME_CFGUPDATE)
+ self.assertRaises(IndexError, self._rpcs.pop)
+
+ assert isinstance(self.lu, FakeNoHooksLU), "LU was replaced"
+
+