diff --git a/daemons/ganeti-noded b/daemons/ganeti-noded index 1736904a29f3fbae1275b83a3e261e88d86ae8e5..f344474aa49bdb6ffce604491f6bc4bfd2cad31c 100755 --- a/daemons/ganeti-noded +++ b/daemons/ganeti-noded @@ -476,6 +476,16 @@ class ServerObject(pb.Avatar): hr = backend.HooksRunner() return hr.RunHooks(hpath, phase, env) + # test ----------------------- + + @staticmethod + def perspective_test_delay(params): + """Run test delay. + + """ + duration = params[0] + return utils.TestDelay(duration) + class MyRealm: """Simple realm that forwards all requests to a ServerObject. diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 6bddebf5e8ece2370450120d4759a6a8805217ec..4163eff8de4c96a8f22d35c80d75495dc3fe7528 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -4542,3 +4542,39 @@ class LUDelTags(TagsLU): raise errors.OpRetryError("There has been a modification to the" " config file and the operation has been" " aborted. Please retry.") + +class LUTestDelay(NoHooksLU): + """Sleep for a specified amount of time. + + This LU sleeps on the master and/or nodes for a specified amoutn of + time. + + """ + _OP_REQP = ["duration", "on_master", "on_nodes"] + + def CheckPrereq(self): + """Check prerequisites. + + This checks that we have a good list of nodes and/or the duration + is valid. + + """ + + if self.op.on_nodes: + self.op.on_nodes = _GetWantedNodes(self, self.op.on_nodes) + + def Exec(self, feedback_fn): + """Do the actual sleep. + + """ + if self.op.on_master: + if not utils.TestDelay(self.op.duration): + raise errors.OpExecError("Error during master delay test") + if self.op.on_nodes: + result = rpc.call_test_delay(self.op.on_nodes, self.op.duration) + if not result: + raise errors.OpExecError("Complete failure from rpc call") + for node, node_result in result.items(): + if not node_result: + raise errors.OpExecError("Failure during rpc call to node %s," + " result: %s" % (node, node_result)) diff --git a/lib/mcpu.py b/lib/mcpu.py index 4ba5926b9a4c2848c57a5eba42e11313af58f5fe..564d146bb16c616b66bb45bc73541fb3483028f7 100644 --- a/lib/mcpu.py +++ b/lib/mcpu.py @@ -85,6 +85,8 @@ class Processor(object): opcodes.OpSearchTags: cmdlib.LUSearchTags, opcodes.OpAddTags: cmdlib.LUAddTags, opcodes.OpDelTags: cmdlib.LUDelTags, + # test lu + opcodes.OpTestDelay: cmdlib.LUTestDelay, } def __init__(self, feedback=None): diff --git a/lib/opcodes.py b/lib/opcodes.py index 73afaf8c7743b066c0b1ce907a81b7a0682cf573..7203b8aa501c09b766c14d2c181b7e4f934b951d 100644 --- a/lib/opcodes.py +++ b/lib/opcodes.py @@ -310,3 +310,29 @@ class OpDelTags(OpCode): """Remove a list of tags from a given object.""" OP_ID = "OP_TAGS_DEL" __slots__ = ["kind", "name", "tags"] + + +# Test opcodes +class OpTestDelay(OpCode): + """Sleeps for a configured amount of time. + + This is used just for debugging and testing. + + Parameters: + - duration: the time to sleep + - on_master: if true, sleep on the master + - on_nodes: list of nodes in which to sleep + + If the on_master parameter is true, it will execute a sleep on the + master (before any node sleep). + + If the on_nodes list is not empty, it will sleep on those nodes + (after the sleep on the master, if that is enabled). + + As an additional feature, the case of duration < 0 will be reported + as an execution error, so this opcode can be used as a failure + generator. The case of duration == 0 will not be treated specially. + + """ + OP_ID = "OP_TEST_DELAY" + __slots__ = ["duration", "on_master", "on_nodes"] diff --git a/lib/rpc.py b/lib/rpc.py index e3e5a73897e344784e27da8a1014f9a0526fe167..7a1210745f604fbe2dccfae495bc35b35ee6359c 100644 --- a/lib/rpc.py +++ b/lib/rpc.py @@ -801,3 +801,15 @@ def call_node_volumes(node_list): c.connect_list(node_list) c.run() return c.getresult() + + +def call_test_delay(node_list, duration): + """Sleep for a fixed time on given node(s). + + This is a multi-node call. + + """ + c = Client("test_delay", [duration]) + c.connect_list(node_list) + c.run() + return c.getresult() diff --git a/lib/utils.py b/lib/utils.py index f854f5aaa9031f92cc807cd86bcad85bc9c5147f..6cbd268c7a24ced08efcd8f37a8cc6e0c0200355 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -1065,3 +1065,13 @@ def IsValidMac(mac): """ mac_check = re.compile("^([0-9a-f]{2}(:|$)){6}$") return mac_check.match(mac) is not None + + +def TestDelay(duration): + """Sleep for a fixed amount of time. + + """ + if duration < 0: + return False + time.sleep(duration) + return True