Revision 1ce03fb1
b/lib/errors.py | ||
---|---|---|
189 | 189 |
""" |
190 | 190 |
|
191 | 191 |
|
192 |
class OpResultError(GenericError): |
|
193 |
"""Issue with OpCode result. |
|
194 |
|
|
195 |
""" |
|
196 |
|
|
197 |
|
|
192 | 198 |
class OpCodeUnknown(GenericError): |
193 | 199 |
"""Unknown opcode submitted. |
194 | 200 |
|
b/lib/mcpu.py | ||
---|---|---|
373 | 373 |
assert lu.needed_locks is not None, "needed_locks not set by LU" |
374 | 374 |
|
375 | 375 |
try: |
376 |
return self._LockAndExecLU(lu, locking.LEVEL_INSTANCE, calc_timeout,
|
|
377 |
priority) |
|
376 |
result = self._LockAndExecLU(lu, locking.LEVEL_INSTANCE, calc_timeout,
|
|
377 |
priority)
|
|
378 | 378 |
finally: |
379 | 379 |
if self._ec_id: |
380 | 380 |
self.context.cfg.DropECReservations(self._ec_id) |
... | ... | |
383 | 383 |
finally: |
384 | 384 |
self._cbs = None |
385 | 385 |
|
386 |
resultcheck_fn = op.OP_RESULT |
|
387 |
if not (resultcheck_fn is None or resultcheck_fn(result)): |
|
388 |
logging.error("Expected opcode result matching %s, got %s", |
|
389 |
resultcheck_fn, result) |
|
390 |
raise errors.OpResultError("Opcode result does not match %s" % |
|
391 |
resultcheck_fn) |
|
392 |
|
|
393 |
return result |
|
394 |
|
|
386 | 395 |
def Log(self, *args): |
387 | 396 |
"""Forward call to feedback callback function. |
388 | 397 |
|
b/lib/opcodes.py | ||
---|---|---|
419 | 419 |
|
420 | 420 |
TNoRelativeJobDependencies = _BuildJobDepCheck(False) |
421 | 421 |
|
422 |
#: List of submission status and job ID as returned by C{SubmitManyJobs} |
|
423 |
TJobIdList = ht.TListOf(ht.TItems([ht.TBool, ht.TOr(ht.TString, ht.TJobId)])) |
|
424 |
|
|
422 | 425 |
|
423 | 426 |
class OpCode(BaseOpCode): |
424 | 427 |
"""Abstract OpCode. |
... | ... | |
433 | 436 |
method for details). |
434 | 437 |
@cvar OP_PARAMS: List of opcode attributes, the default values they should |
435 | 438 |
get if not already defined, and types they must match. |
439 |
@cvar OP_RESULT: Callable to verify opcode result |
|
436 | 440 |
@cvar WITH_LU: Boolean that specifies whether this should be included in |
437 | 441 |
mcpu's dispatch table |
438 | 442 |
@ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just |
... | ... | |
454 | 458 |
(COMMENT_ATTR, None, ht.TMaybeString, |
455 | 459 |
"Comment describing the purpose of the opcode"), |
456 | 460 |
] |
461 |
OP_RESULT = None |
|
457 | 462 |
|
458 | 463 |
def __getstate__(self): |
459 | 464 |
"""Specialized getstate for opcodes. |
... | ... | |
595 | 600 |
"""Verify the cluster disks. |
596 | 601 |
|
597 | 602 |
""" |
603 |
OP_RESULT = ht.TStrictDict(True, True, { |
|
604 |
constants.JOB_IDS_KEY: TJobIdList, |
|
605 |
}) |
|
598 | 606 |
|
599 | 607 |
|
600 | 608 |
class OpGroupVerifyDisks(OpCode): |
... | ... | |
619 | 627 |
OP_PARAMS = [ |
620 | 628 |
_PGroupName, |
621 | 629 |
] |
630 |
OP_RESULT = \ |
|
631 |
ht.TAnd(ht.TIsLength(3), |
|
632 |
ht.TItems([ht.TDictOf(ht.TString, ht.TString), |
|
633 |
ht.TListOf(ht.TString), |
|
634 |
ht.TDictOf(ht.TString, ht.TListOf(ht.TString))])) |
|
622 | 635 |
|
623 | 636 |
|
624 | 637 |
class OpClusterRepairDiskSizes(OpCode): |
b/test/ganeti.opcodes_unittest.py | ||
---|---|---|
49 | 49 |
self.assertEqual(cls.OP_ID, opcodes._NameToId(cls.__name__)) |
50 | 50 |
self.assertFalse(compat.any(cls.OP_ID.startswith(prefix) |
51 | 51 |
for prefix in opcodes._SUMMARY_PREFIX.keys())) |
52 |
self.assertTrue(cls.OP_RESULT is None or callable(cls.OP_RESULT)) |
|
52 | 53 |
|
53 | 54 |
self.assertRaises(TypeError, cls, unsupported_parameter="some value") |
54 | 55 |
|
Also available in: Unified diff