From 07923a3c0e85ad3061cabc258945067a72684c8b Mon Sep 17 00:00:00 2001 From: Michael Hanselmann <hansmi@google.com> Date: Fri, 13 Apr 2012 23:28:21 +0200 Subject: [PATCH] Copy debug level, priority and set comment for LU-generated opcodes Before this patch, a node evacuation submitted with high priority would only compute the solution at that priority, but the actual evacuation ran at normal priority. Signed-off-by: Michael Hanselmann <hansmi@google.com> Reviewed-by: Iustin Pop <iustin@google.com> --- lib/cmdlib.py | 2 +- lib/mcpu.py | 72 +++++++++++++++++++++++++----------- test/ganeti.mcpu_unittest.py | 70 +++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 22 deletions(-) diff --git a/lib/cmdlib.py b/lib/cmdlib.py index 71076b945..f4c6f932d 100644 --- a/lib/cmdlib.py +++ b/lib/cmdlib.py @@ -82,7 +82,7 @@ class ResultWithJobs: """Data container for LU results with jobs. Instances of this class returned from L{LogicalUnit.Exec} will be recognized - by L{mcpu.Processor._ProcessResult}. The latter will then submit the jobs + by L{mcpu._ProcessResult}. The latter will then submit the jobs contained in the C{jobs} attribute and include the job IDs in the opcode result. diff --git a/lib/mcpu.py b/lib/mcpu.py index 8b3734e0e..2bf875f87 100644 --- a/lib/mcpu.py +++ b/lib/mcpu.py @@ -31,6 +31,7 @@ are two kinds of classes defined: import logging import random import time +import itertools from ganeti import opcodes from ganeti import constants @@ -171,6 +172,54 @@ def _ComputeDispatchTable(): if op.WITH_LU) +def _SetBaseOpParams(src, defcomment, dst): + """Copies basic opcode parameters. + + @type src: L{opcodes.OpCode} + @param src: Source opcode + @type defcomment: string + @param defcomment: Comment to specify if not already given + @type dst: L{opcodes.OpCode} + @param dst: Destination opcode + + """ + if hasattr(src, "debug_level"): + dst.debug_level = src.debug_level + + if (getattr(dst, "priority", None) is None and + hasattr(src, "priority")): + dst.priority = src.priority + + if not getattr(dst, opcodes.COMMENT_ATTR, None): + dst.comment = defcomment + + +def _ProcessResult(submit_fn, op, result): + """Examines opcode result. + + If necessary, additional processing on the result is done. + + """ + if isinstance(result, cmdlib.ResultWithJobs): + # Copy basic parameters (e.g. priority) + map(compat.partial(_SetBaseOpParams, op, + "Submitted by %s" % op.OP_ID), + itertools.chain(*result.jobs)) + + # Submit jobs + job_submission = submit_fn(result.jobs) + + # Build dictionary + result = result.other + + assert constants.JOB_IDS_KEY not in result, \ + "Key '%s' found in additional return values" % constants.JOB_IDS_KEY + + result[constants.JOB_IDS_KEY] = job_submission + + return result + + def _RpcResultsToHooksResults(rpc_results): """Function to convert RPC results to the format expected by HooksMaster. @@ -230,26 +279,6 @@ class Processor(object): return acquired - def _ProcessResult(self, result): - """Examines opcode result. - - If necessary, additional processing on the result is done. - - """ - if isinstance(result, cmdlib.ResultWithJobs): - # Submit jobs - job_submission = self._cbs.SubmitManyJobs(result.jobs) - - # Build dictionary - result = result.other - - assert constants.JOB_IDS_KEY not in result, \ - "Key '%s' found in additional return values" % constants.JOB_IDS_KEY - - result[constants.JOB_IDS_KEY] = job_submission - - return result - def _ExecLU(self, lu): """Logical Unit execution sequence. @@ -271,7 +300,8 @@ class Processor(object): return lu.dry_run_result try: - result = self._ProcessResult(lu.Exec(self.Log)) + result = _ProcessResult(self._cbs.SubmitManyJobs, lu.op, + lu.Exec(self.Log)) h_results = hm.RunPhase(constants.HOOKS_PHASE_POST) result = lu.HooksCallBack(constants.HOOKS_PHASE_POST, h_results, self.Log, result) diff --git a/test/ganeti.mcpu_unittest.py b/test/ganeti.mcpu_unittest.py index 4285932aa..067814039 100755 --- a/test/ganeti.mcpu_unittest.py +++ b/test/ganeti.mcpu_unittest.py @@ -23,9 +23,12 @@ import unittest +import itertools from ganeti import mcpu from ganeti import opcodes +from ganeti import cmdlib +from ganeti import constants from ganeti.constants import \ LOCK_ATTEMPTS_TIMEOUT, \ LOCK_ATTEMPTS_MAXWAIT, \ @@ -96,5 +99,72 @@ class TestDispatchTable(unittest.TestCase): opcls.OP_ID)) +class TestProcessResult(unittest.TestCase): + def setUp(self): + self._submitted = [] + self._count = itertools.count(200) + + def _Submit(self, jobs): + job_ids = [self._count.next() for _ in jobs] + self._submitted.extend(zip(job_ids, jobs)) + return job_ids + + def testNoJobs(self): + for i in [object(), [], False, True, None, 1, 929, {}]: + self.assertEqual(mcpu._ProcessResult(NotImplemented, NotImplemented, i), + i) + + def testDefaults(self): + src = opcodes.OpTestDummy() + + res = mcpu._ProcessResult(self._Submit, src, cmdlib.ResultWithJobs([[ + opcodes.OpTestDelay(), + opcodes.OpTestDelay(), + ], [ + opcodes.OpTestDelay(), + ]])) + + self.assertEqual(res, { + constants.JOB_IDS_KEY: [200, 201], + }) + + (_, (op1, op2)) = self._submitted.pop(0) + (_, (op3, )) = self._submitted.pop(0) + self.assertRaises(IndexError, self._submitted.pop) + + for op in [op1, op2, op3]: + self.assertTrue("OP_TEST_DUMMY" in op.comment) + self.assertFalse(hasattr(op, "priority")) + self.assertFalse(hasattr(op, "debug_level")) + + def testParams(self): + src = opcodes.OpTestDummy(priority=constants.OP_PRIO_HIGH, + debug_level=3) + + res = mcpu._ProcessResult(self._Submit, src, cmdlib.ResultWithJobs([[ + opcodes.OpTestDelay(priority=constants.OP_PRIO_LOW), + ], [ + opcodes.OpTestDelay(comment="foobar", debug_level=10), + ]], other=True, value=range(10))) + + self.assertEqual(res, { + constants.JOB_IDS_KEY: [200, 201], + "other": True, + "value": range(10), + }) + + (_, (op1, )) = self._submitted.pop(0) + (_, (op2, )) = self._submitted.pop(0) + self.assertRaises(IndexError, self._submitted.pop) + + self.assertEqual(op1.priority, constants.OP_PRIO_LOW) + self.assertTrue("OP_TEST_DUMMY" in op1.comment) + self.assertEqual(op1.debug_level, 3) + + self.assertEqual(op2.priority, constants.OP_PRIO_HIGH) + self.assertEqual(op2.comment, "foobar") + self.assertEqual(op2.debug_level, 3) + + if __name__ == "__main__": testutils.GanetiTestProgram() -- GitLab