Commit 1ce03fb1 authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

Add ht-based result checks to opcodes

This adds the infrastructure necessary to check opcode results using
ht-based functions. Checks are added for two opcodes.
Signed-off-by: default avatarMichael Hanselmann <>
Reviewed-by: default avatarIustin Pop <>
parent ae1a845c
......@@ -189,6 +189,12 @@ class OpExecError(GenericError):
class OpResultError(GenericError):
"""Issue with OpCode result.
class OpCodeUnknown(GenericError):
"""Unknown opcode submitted.
......@@ -373,8 +373,8 @@ class Processor(object):
assert lu.needed_locks is not None, "needed_locks not set by LU"
return self._LockAndExecLU(lu, locking.LEVEL_INSTANCE, calc_timeout,
result = self._LockAndExecLU(lu, locking.LEVEL_INSTANCE, calc_timeout,
if self._ec_id:
......@@ -383,6 +383,15 @@ class Processor(object):
self._cbs = None
resultcheck_fn = op.OP_RESULT
if not (resultcheck_fn is None or resultcheck_fn(result)):
logging.error("Expected opcode result matching %s, got %s",
resultcheck_fn, result)
raise errors.OpResultError("Opcode result does not match %s" %
return result
def Log(self, *args):
"""Forward call to feedback callback function.
......@@ -419,6 +419,9 @@ def _BuildJobDepCheck(relative):
TNoRelativeJobDependencies = _BuildJobDepCheck(False)
#: List of submission status and job ID as returned by C{SubmitManyJobs}
TJobIdList = ht.TListOf(ht.TItems([ht.TBool, ht.TOr(ht.TString, ht.TJobId)]))
class OpCode(BaseOpCode):
"""Abstract OpCode.
......@@ -433,6 +436,7 @@ class OpCode(BaseOpCode):
method for details).
@cvar OP_PARAMS: List of opcode attributes, the default values they should
get if not already defined, and types they must match.
@cvar OP_RESULT: Callable to verify opcode result
@cvar WITH_LU: Boolean that specifies whether this should be included in
mcpu's dispatch table
@ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just
......@@ -454,6 +458,7 @@ class OpCode(BaseOpCode):
(COMMENT_ATTR, None, ht.TMaybeString,
"Comment describing the purpose of the opcode"),
def __getstate__(self):
"""Specialized getstate for opcodes.
......@@ -595,6 +600,9 @@ class OpClusterVerifyDisks(OpCode):
"""Verify the cluster disks.
OP_RESULT = ht.TStrictDict(True, True, {
constants.JOB_IDS_KEY: TJobIdList,
class OpGroupVerifyDisks(OpCode):
......@@ -619,6 +627,11 @@ class OpGroupVerifyDisks(OpCode):
ht.TItems([ht.TDictOf(ht.TString, ht.TString),
ht.TDictOf(ht.TString, ht.TListOf(ht.TString))]))
class OpClusterRepairDiskSizes(OpCode):
......@@ -49,6 +49,7 @@ class TestOpcodes(unittest.TestCase):
self.assertEqual(cls.OP_ID, opcodes._NameToId(cls.__name__))
for prefix in opcodes._SUMMARY_PREFIX.keys()))
self.assertTrue(cls.OP_RESULT is None or callable(cls.OP_RESULT))
self.assertRaises(TypeError, cls, unsupported_parameter="some value")
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment