diff --git a/lib/cmdlib.py b/lib/cmdlib.py index fa8716e5ca4e3f37f62e0024cead94eea2a6cbd7..af51ec209eead156ac0988f2564e65bdec04b934 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -83,6 +83,7 @@ class LogicalUnit(object): - implement CheckPrereq (except when tasklets are used) - implement Exec (except when tasklets are used) - implement BuildHooksEnv + - implement BuildHooksNodes - redefine HPATH and HTYPE - optionally redefine their run requirements: REQ_BGL: the LU needs to hold the Big Ganeti Lock exclusively @@ -273,21 +274,28 @@ class LogicalUnit(object): def BuildHooksEnv(self): """Build hooks environment for this LU. - This method should return a three-node tuple consisting of: a dict - containing the environment that will be used for running the - specific hook for this LU, a list of node names on which the hook - should run before the execution, and a list of node names on which - the hook should run after the execution. + @rtype: dict + @return: Dictionary containing the environment that will be used for + running the hooks for this LU. The keys of the dict must not be prefixed + with "GANETI_"--that'll be added by the hooks runner. The hooks runner + will extend the environment with additional variables. If no environment + should be defined, an empty dictionary should be returned (not C{None}). + @note: If the C{HPATH} attribute of the LU class is C{None}, this function + will not be called. - The keys of the dict must not have 'GANETI_' prefixed as this will - be handled in the hooks runner. Also note additional keys will be - added by the hooks runner. If the LU doesn't define any - environment, an empty dict (and not None) should be returned. + """ + raise NotImplementedError - No nodes should be returned as an empty list (and not None). + def BuildHooksNodes(self): + """Build list of nodes to run LU's hooks. - Note that if the HPATH for a LU class is None, this function will - not be called. + @rtype: tuple; (list, list) + @return: Tuple containing a list of node names on which the hook + should run before the execution and a list of node names on which the + hook should run after the execution. No nodes should be returned as an + empty list (and not None). + @note: If the C{HPATH} attribute of the LU class is C{None}, this function + will not be called. """ raise NotImplementedError @@ -397,7 +405,13 @@ class NoHooksLU(LogicalUnit): # pylint: disable-msg=W0223 This just raises an error. """ - assert False, "BuildHooksEnv called for NoHooksLUs" + raise AssertionError("BuildHooksEnv called for NoHooksLUs") + + def BuildHooksNodes(self): + """Empty BuildHooksNodes for NoHooksLU. + + """ + raise AssertionError("BuildHooksNodes called for NoHooksLU") class Tasklet: @@ -1109,9 +1123,15 @@ class LUClusterPostInit(LogicalUnit): """Build hooks env. """ - env = {"OP_TARGET": self.cfg.GetClusterName()} - mn = self.cfg.GetMasterNode() - return env, [], [mn] + return { + "OP_TARGET": self.cfg.GetClusterName(), + } + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + return ([], [self.cfg.GetMasterNode()]) def Exec(self, feedback_fn): """Nothing to do. @@ -1131,8 +1151,15 @@ class LUClusterDestroy(LogicalUnit): """Build hooks env. """ - env = {"OP_TARGET": self.cfg.GetClusterName()} - return env, [], [] + return { + "OP_TARGET": self.cfg.GetClusterName(), + } + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + return ([], []) def CheckPrereq(self): """Check prerequisites. @@ -2065,7 +2092,6 @@ class LUClusterVerify(LogicalUnit): except errors.GenericError, err: self._ErrorIf(True, self.ECLUSTERCFG, None, msg % str(err)) - def BuildHooksEnv(self): """Build hooks env. @@ -2073,14 +2099,22 @@ class LUClusterVerify(LogicalUnit): the output be logged in the verify output and the verification to fail. """ - all_nodes = self.cfg.GetNodeList() + cfg = self.cfg + env = { - "CLUSTER_TAGS": " ".join(self.cfg.GetClusterInfo().GetTags()) + "CLUSTER_TAGS": " ".join(cfg.GetClusterInfo().GetTags()) } - for node in self.cfg.GetAllNodesInfo().values(): - env["NODE_TAGS_%s" % node.name] = " ".join(node.GetTags()) - return env, [], all_nodes + env.update(("NODE_TAGS_%s" % node.name, " ".join(node.GetTags())) + for node in cfg.GetAllNodesInfo().values()) + + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + return ([], self.cfg.GetNodeList()) def Exec(self, feedback_fn): """Verify integrity of cluster, performing various test on nodes. @@ -2634,13 +2668,16 @@ class LUClusterRename(LogicalUnit): """Build hooks env. """ - env = { + return { "OP_TARGET": self.cfg.GetClusterName(), "NEW_NAME": self.op.name, } - mn = self.cfg.GetMasterNode() - all_nodes = self.cfg.GetNodeList() - return env, [mn], all_nodes + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + return ([self.cfg.GetMasterNode()], self.cfg.GetNodeList()) def CheckPrereq(self): """Verify that the passed name is a valid one. @@ -2734,12 +2771,17 @@ class LUClusterSetParams(LogicalUnit): """Build hooks env. """ - env = { + return { "OP_TARGET": self.cfg.GetClusterName(), "NEW_VG_NAME": self.op.vg_name, } + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ mn = self.cfg.GetMasterNode() - return env, [mn], [mn] + return ([mn], [mn]) def CheckPrereq(self): """Check prerequisites. @@ -3580,17 +3622,22 @@ class LUNodeRemove(LogicalUnit): node would then be impossible to remove. """ - env = { + return { "OP_TARGET": self.op.node_name, "NODE_NAME": self.op.node_name, } + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ all_nodes = self.cfg.GetNodeList() try: all_nodes.remove(self.op.node_name) except ValueError: - logging.warning("Node %s which is about to be removed not found" - " in the all nodes list", self.op.node_name) - return env, all_nodes, all_nodes + logging.warning("Node '%s', which is about to be removed, was not found" + " in the list of all nodes", self.op.node_name) + return (all_nodes, all_nodes) def CheckPrereq(self): """Check prerequisites. @@ -4106,7 +4153,7 @@ class LUNodeAdd(LogicalUnit): This will run on all nodes before, and on all nodes + the new node after. """ - env = { + return { "OP_TARGET": self.op.node_name, "NODE_NAME": self.op.node_name, "NODE_PIP": self.op.primary_ip, @@ -4115,11 +4162,15 @@ class LUNodeAdd(LogicalUnit): "VM_CAPABLE": str(self.op.vm_capable), } + def BuildHooksNodes(self): + """Build hooks nodes. + + """ # Exclude added node pre_nodes = list(set(self.cfg.GetNodeList()) - set([self.op.node_name])) post_nodes = pre_nodes + [self.op.node_name, ] - return (env, pre_nodes, post_nodes) + return (pre_nodes, post_nodes) def CheckPrereq(self): """Check prerequisites. @@ -4432,7 +4483,7 @@ class LUNodeSetParams(LogicalUnit): This runs on the master node. """ - env = { + return { "OP_TARGET": self.op.node_name, "MASTER_CANDIDATE": str(self.op.master_candidate), "OFFLINE": str(self.op.offline), @@ -4440,9 +4491,13 @@ class LUNodeSetParams(LogicalUnit): "MASTER_CAPABLE": str(self.op.master_capable), "VM_CAPABLE": str(self.op.vm_capable), } - nl = [self.cfg.GetMasterNode(), - self.op.node_name] - return env, nl, nl + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + nl = [self.cfg.GetMasterNode(), self.op.node_name] + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -5136,9 +5191,17 @@ class LUInstanceStartup(LogicalUnit): env = { "FORCE": self.op.force, } + env.update(_BuildInstanceHookEnvByObject(self, self.instance)) + + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -5233,9 +5296,17 @@ class LUInstanceReboot(LogicalUnit): "REBOOT_TYPE": self.op.reboot_type, "SHUTDOWN_TIMEOUT": self.op.shutdown_timeout, } + env.update(_BuildInstanceHookEnvByObject(self, self.instance)) + + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -5315,8 +5386,14 @@ class LUInstanceShutdown(LogicalUnit): """ env = _BuildInstanceHookEnvByObject(self, self.instance) env["TIMEOUT"] = self.op.timeout + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -5375,9 +5452,14 @@ class LUInstanceReinstall(LogicalUnit): This runs on master, primary and secondary nodes of the instance. """ - env = _BuildInstanceHookEnvByObject(self, self.instance) + return _BuildInstanceHookEnvByObject(self, self.instance) + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -5461,9 +5543,14 @@ class LUInstanceRecreateDisks(LogicalUnit): This runs on master, primary and secondary nodes of the instance. """ - env = _BuildInstanceHookEnvByObject(self, self.instance) + return _BuildInstanceHookEnvByObject(self, self.instance) + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -5528,8 +5615,14 @@ class LUInstanceRename(LogicalUnit): """ env = _BuildInstanceHookEnvByObject(self, self.instance) env["INSTANCE_NEW_NAME"] = self.op.new_name + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -5639,9 +5732,15 @@ class LUInstanceRemove(LogicalUnit): """ env = _BuildInstanceHookEnvByObject(self, self.instance) env["SHUTDOWN_TIMEOUT"] = self.op.shutdown_timeout + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] nl_post = list(self.instance.all_nodes) + nl - return env, nl, nl_post + return (nl, nl_post) def CheckPrereq(self): """Check prerequisites. @@ -5777,10 +5876,15 @@ class LUInstanceFailover(LogicalUnit): env["OLD_SECONDARY"] = env["NEW_SECONDARY"] = "" env.update(_BuildInstanceHookEnvByObject(self, instance)) - nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes) - nl_post = list(nl) - nl_post.append(source_node) - return env, nl, nl_post + + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + nl = [self.cfg.GetMasterNode()] + list(self.instance.secondary_nodes) + return (nl, nl + [self.instance.primary_node]) def CheckPrereq(self): """Check prerequisites. @@ -5994,12 +6098,12 @@ class LUInstanceMigrate(LogicalUnit): source_node = instance.primary_node target_node = self._migrater.target_node env = _BuildInstanceHookEnvByObject(self, instance) - env["MIGRATE_LIVE"] = self._migrater.live - env["MIGRATE_CLEANUP"] = self.op.cleanup env.update({ - "OLD_PRIMARY": source_node, - "NEW_PRIMARY": target_node, - }) + "MIGRATE_LIVE": self._migrater.live, + "MIGRATE_CLEANUP": self.op.cleanup, + "OLD_PRIMARY": source_node, + "NEW_PRIMARY": target_node, + }) if instance.disk_template in constants.DTS_INT_MIRROR: env["OLD_SECONDARY"] = target_node @@ -6007,10 +6111,15 @@ class LUInstanceMigrate(LogicalUnit): else: env["OLD_SECONDARY"] = env["NEW_SECONDARY"] = None + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + instance = self._migrater.instance nl = [self.cfg.GetMasterNode()] + list(instance.secondary_nodes) - nl_post = list(nl) - nl_post.append(source_node) - return env, nl, nl_post + return (nl, nl + [instance.primary_node]) class LUInstanceMove(LogicalUnit): @@ -6043,9 +6152,18 @@ class LUInstanceMove(LogicalUnit): "SHUTDOWN_TIMEOUT": self.op.shutdown_timeout, } env.update(_BuildInstanceHookEnvByObject(self, self.instance)) - nl = [self.cfg.GetMasterNode()] + [self.instance.primary_node, - self.op.target_node] - return env, nl, nl + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + nl = [ + self.cfg.GetMasterNode(), + self.instance.primary_node, + self.op.target_node, + ] + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -6244,13 +6362,16 @@ class LUNodeMigrate(LogicalUnit): This runs on the master, the primary and all the secondaries. """ - env = { + return { "NODE_NAME": self.op.node_name, } - nl = [self.cfg.GetMasterNode()] + def BuildHooksNodes(self): + """Build hooks nodes. - return (env, nl, nl) + """ + nl = [self.cfg.GetMasterNode()] + return (nl, nl) class TLMigrateInstance(Tasklet): @@ -7469,9 +7590,14 @@ class LUInstanceCreate(LogicalUnit): hypervisor_name=self.op.hypervisor, )) - nl = ([self.cfg.GetMasterNode(), self.op.pnode] + - self.secondaries) - return env, nl, nl + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + nl = [self.cfg.GetMasterNode(), self.op.pnode] + self.secondaries + return nl, nl def _ReadExportInfo(self): """Reads the export information from disk. @@ -8258,13 +8384,20 @@ class LUInstanceReplaceDisks(LogicalUnit): "OLD_SECONDARY": instance.secondary_nodes[0], } env.update(_BuildInstanceHookEnvByObject(self, instance)) + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ + instance = self.replacer.instance nl = [ self.cfg.GetMasterNode(), instance.primary_node, ] if self.op.remote_node is not None: nl.append(self.op.remote_node) - return env, nl, nl + return nl, nl class TLReplaceDisks(Tasklet): @@ -9099,8 +9232,14 @@ class LUInstanceGrowDisk(LogicalUnit): "AMOUNT": self.op.amount, } env.update(_BuildInstanceHookEnvByObject(self, self.instance)) + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -9507,8 +9646,15 @@ class LUInstanceSetParams(LogicalUnit): env = _BuildInstanceHookEnvByObject(self, self.instance, override=args) if self.op.disk_template: env["NEW_DISK_TEMPLATE"] = self.op.disk_template + + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode()] + list(self.instance.all_nodes) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -10125,12 +10271,18 @@ class LUBackupExport(LogicalUnit): env.update(_BuildInstanceHookEnvByObject(self, self.instance)) + return env + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ nl = [self.cfg.GetMasterNode(), self.instance.primary_node] if self.op.mode == constants.EXPORT_MODE_LOCAL: nl.append(self.op.target_node) - return env, nl, nl + return (nl, nl) def CheckPrereq(self): """Check prerequisites. @@ -10440,11 +10592,16 @@ class LUGroupAdd(LogicalUnit): """Build hooks env. """ - env = { + return { "GROUP_NAME": self.op.group_name, } + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ mn = self.cfg.GetMasterNode() - return env, [mn], [mn] + return ([mn], [mn]) def Exec(self, feedback_fn): """Add the node group to the cluster. @@ -10711,12 +10868,17 @@ class LUGroupSetParams(LogicalUnit): """Build hooks env. """ - env = { + return { "GROUP_NAME": self.op.group_name, "NEW_ALLOC_POLICY": self.op.alloc_policy, } + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ mn = self.cfg.GetMasterNode() - return env, [mn], [mn] + return ([mn], [mn]) def Exec(self, feedback_fn): """Modifies the node group. @@ -10779,11 +10941,16 @@ class LUGroupRemove(LogicalUnit): """Build hooks env. """ - env = { + return { "GROUP_NAME": self.op.group_name, } + + def BuildHooksNodes(self): + """Build hooks nodes. + + """ mn = self.cfg.GetMasterNode() - return env, [mn], [mn] + return ([mn], [mn]) def Exec(self, feedback_fn): """Remove the node group. @@ -10831,21 +10998,25 @@ class LUGroupRename(LogicalUnit): """Build hooks env. """ - env = { + return { "OLD_NAME": self.op.group_name, "NEW_NAME": self.op.new_name, } + def BuildHooksNodes(self): + """Build hooks nodes. + + """ mn = self.cfg.GetMasterNode() + all_nodes = self.cfg.GetAllNodesInfo() - run_nodes = [mn] all_nodes.pop(mn, None) - for node in all_nodes.values(): - if node.group == self.group_uuid: - run_nodes.append(node.name) + run_nodes = [mn] + run_nodes.extend(node.name for node in all_nodes.values() + if node.group == self.group_uuid) - return env, run_nodes, run_nodes + return (run_nodes, run_nodes) def Exec(self, feedback_fn): """Rename the node group. diff --git a/lib/mcpu.py b/lib/mcpu.py index 399fcbe63b8b7c28afd51a2bdc03fe6256712080..863cf9aa8e9f44265aa5b50f5efa8f4b095df7a3 100644 --- a/lib/mcpu.py +++ b/lib/mcpu.py @@ -427,8 +427,14 @@ class HooksMaster(object): self.callfn = callfn self.lu = lu self.op = lu.op - self.pre_env = None - self.post_nodes = None + self.pre_env = self._BuildEnv(constants.HOOKS_PHASE_PRE) + + if self.lu.HPATH is None: + nodes = (None, None) + else: + nodes = map(frozenset, self.lu.BuildHooksNodes()) + + (self.pre_nodes, self.post_nodes) = nodes def _BuildEnv(self, phase): """Compute the environment and the target nodes. @@ -447,34 +453,29 @@ class HooksMaster(object): env = {} if self.lu.HPATH is not None: - (lu_env, lu_nodes_pre, lu_nodes_post) = self.lu.BuildHooksEnv() + lu_env = self.lu.BuildHooksEnv() if lu_env: - assert not compat.any(key.upper().startswith(prefix) - for key in lu_env) + assert not compat.any(key.upper().startswith(prefix) for key in lu_env) env.update(("%s%s" % (prefix, key), value) for (key, value) in lu_env.items()) - else: - lu_nodes_pre = lu_nodes_post = [] if phase == constants.HOOKS_PHASE_PRE: assert compat.all((key.startswith("GANETI_") and not key.startswith("GANETI_POST_")) for key in env) - # Record environment for any post-phase hooks - self.pre_env = env - elif phase == constants.HOOKS_PHASE_POST: assert compat.all(key.startswith("GANETI_POST_") for key in env) + assert isinstance(self.pre_env, dict) - if self.pre_env: - assert not compat.any(key.startswith("GANETI_POST_") - for key in self.pre_env) - env.update(self.pre_env) + # Merge with pre-phase environment + assert not compat.any(key.startswith("GANETI_POST_") + for key in self.pre_env) + env.update(self.pre_env) else: raise AssertionError("Unknown phase '%s'" % phase) - return env, frozenset(lu_nodes_pre), frozenset(lu_nodes_post) + return env def _RunWrapper(self, node_list, hpath, phase, phase_env): """Simple wrapper over self.callfn. @@ -488,12 +489,14 @@ class HooksMaster(object): "PATH": "/sbin:/bin:/usr/sbin:/usr/bin", "GANETI_HOOKS_VERSION": constants.HOOKS_VERSION, "GANETI_OP_CODE": self.op.OP_ID, - "GANETI_OBJECT_TYPE": self.lu.HTYPE, "GANETI_DATA_DIR": constants.DATA_DIR, "GANETI_HOOKS_PHASE": phase, "GANETI_HOOKS_PATH": hpath, } + if self.lu.HTYPE: + env["GANETI_OBJECT_TYPE"] = self.lu.HTYPE + if cfg is not None: env["GANETI_CLUSTER"] = cfg.GetClusterName() env["GANETI_MASTER"] = cfg.GetMasterNode() @@ -523,17 +526,16 @@ class HooksMaster(object): @raise errors.HooksAbort: on failure of one of the hooks """ - (env, node_list_pre, node_list_post) = self._BuildEnv(phase) - if nodes is None: - if phase == constants.HOOKS_PHASE_PRE: - nodes = node_list_pre - self.post_nodes = node_list_post - elif self.post_nodes is None: - raise AssertionError("Pre-phase must be run before post-phase") - elif phase == constants.HOOKS_PHASE_POST: + if phase == constants.HOOKS_PHASE_PRE: + if nodes is None: + nodes = self.pre_nodes + env = self.pre_env + elif phase == constants.HOOKS_PHASE_POST: + if nodes is None: nodes = self.post_nodes - else: - raise AssertionError("Unknown phase '%s'" % phase) + env = self._BuildEnv(phase) + else: + raise AssertionError("Unknown phase '%s'" % phase) if not nodes: # empty node list, we should not attempt to run this as either @@ -584,9 +586,6 @@ class HooksMaster(object): top-level LI if the configuration has been updated. """ - if self.pre_env is None: - raise AssertionError("Pre-phase must be run before configuration update") - phase = constants.HOOKS_PHASE_POST hpath = constants.HOOKS_NAME_CFGUPDATE nodes = [self.lu.cfg.GetMasterNode()] diff --git a/test/ganeti.hooks_unittest.py b/test/ganeti.hooks_unittest.py index 30836cd67bd473535a41254a7232bc8d023f74b1..abbb7c1bad615d2ee4392e5217d9f1e2f80b581a 100755 --- a/test/ganeti.hooks_unittest.py +++ b/test/ganeti.hooks_unittest.py @@ -45,8 +45,12 @@ import testutils class FakeLU(cmdlib.LogicalUnit): HPATH = "test" + def BuildHooksEnv(self): - return {}, ["localhost"], ["localhost"] + return {} + + def BuildHooksNodes(self): + return ["localhost"], ["localhost"] class TestHooksRunner(unittest.TestCase): @@ -282,8 +286,14 @@ class FakeEnvLU(cmdlib.LogicalUnit): def BuildHooksEnv(self): assert self.hook_env is not None + return self.hook_env + + def BuildHooksNodes(self): + return (["localhost"], ["localhost"]) + - return self.hook_env, ["localhost"], ["localhost"] +class FakeNoHooksLU(cmdlib.NoHooksLU): + pass class TestHooksRunnerEnv(unittest.TestCase): @@ -292,7 +302,6 @@ class TestHooksRunnerEnv(unittest.TestCase): self.op = opcodes.OpTestDummy(result=False, messages=[], fail=False) self.lu = FakeEnvLU(FakeProc(), self.op, FakeContext(), None) - self.hm = mcpu.HooksMaster(self._HooksRpc, self.lu) def _HooksRpc(self, *args): self._rpcs.append(args) @@ -303,14 +312,18 @@ class TestHooksRunnerEnv(unittest.TestCase): 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_OBJECT_TYPE"], constants.HTYPE_GROUP) 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 = {} - self.hm.RunPhase(constants.HOOKS_PHASE_PRE) + hm = mcpu.HooksMaster(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"])) @@ -320,7 +333,7 @@ class TestHooksRunnerEnv(unittest.TestCase): # Check post-phase hook self.lu.hook_env = {} - self.hm.RunPhase(constants.HOOKS_PHASE_POST) + hm.RunPhase(constants.HOOKS_PHASE_POST) (node_list, hpath, phase, env) = self._rpcs.pop(0) self.assertEqual(node_list, set(["localhost"])) @@ -335,7 +348,8 @@ class TestHooksRunnerEnv(unittest.TestCase): self.lu.hook_env = { "FOO": "pre-foo-value", } - self.hm.RunPhase(constants.HOOKS_PHASE_PRE) + hm = mcpu.HooksMaster(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"])) @@ -350,7 +364,7 @@ class TestHooksRunnerEnv(unittest.TestCase): "FOO": "post-value", "BAR": 123, } - self.hm.RunPhase(constants.HOOKS_PHASE_POST) + hm.RunPhase(constants.HOOKS_PHASE_POST) (node_list, hpath, phase, env) = self._rpcs.pop(0) self.assertEqual(node_list, set(["localhost"])) @@ -365,7 +379,7 @@ class TestHooksRunnerEnv(unittest.TestCase): self.assertRaises(IndexError, self._rpcs.pop) # Check configuration update hook - self.hm.RunConfigUpdate() + 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) @@ -389,7 +403,8 @@ class TestHooksRunnerEnv(unittest.TestCase): def testNoNodes(self): self.lu.hook_env = {} - self.hm.RunPhase(constants.HOOKS_PHASE_PRE, nodes=[]) + hm = mcpu.HooksMaster(self._HooksRpc, self.lu) + hm.RunPhase(constants.HOOKS_PHASE_PRE, nodes=[]) self.assertRaises(IndexError, self._rpcs.pop) def testSpecificNodes(self): @@ -400,8 +415,10 @@ class TestHooksRunnerEnv(unittest.TestCase): "node93782.example.net", ] + hm = mcpu.HooksMaster(self._HooksRpc, self.lu) + for phase in [constants.HOOKS_PHASE_PRE, constants.HOOKS_PHASE_POST]: - self.hm.RunPhase(phase, nodes=nodes) + hm.RunPhase(phase, nodes=nodes) (node_list, hpath, rpc_phase, env) = self._rpcs.pop(0) self.assertEqual(set(node_list), set(nodes)) @@ -412,14 +429,69 @@ class TestHooksRunnerEnv(unittest.TestCase): self.assertRaises(IndexError, self._rpcs.pop) def testRunConfigUpdateNoPre(self): - self.lu.hook_env = {} - self.assertRaises(AssertionError, self.hm.RunConfigUpdate) + self.lu.hook_env = { + "FOO": "value", + } + + hm = mcpu.HooksMaster(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 = {} - self.assertRaises(AssertionError, self.hm.RunPhase, - constants.HOOKS_PHASE_POST) + self.lu.hook_env = { + "FOO": "value", + } + + hm = mcpu.HooksMaster(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(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" if __name__ == '__main__':