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