Adding the new opcode for multi-allocation
authorRené Nussbaumer <rn@google.com>
Thu, 13 Sep 2012 11:18:57 +0000 (13:18 +0200)
committerRené Nussbaumer <rn@google.com>
Mon, 24 Sep 2012 11:48:58 +0000 (13:48 +0200)
Skeleton for the multi-allocation opcode

Signed-off-by: René Nussbaumer <rn@google.com>
Reviewed-by: Michael Hanselmann <hansmi@google.com>

lib/opcodes.py
test/ganeti.opcodes_unittest.py

index e4ad078..4c427d5 100644 (file)
@@ -1208,6 +1208,55 @@ class OpInstanceCreate(OpCode):
   OP_RESULT = ht.Comment("instance nodes")(ht.TListOf(ht.TNonEmptyString))
 
 
+class OpInstanceMultiAlloc(OpCode):
+  """Allocates multiple instances.
+
+  """
+  OP_PARAMS = [
+    ("iallocator", None, ht.TMaybeString,
+     "Iallocator used to allocate all the instances"),
+    ("instances", [], ht.TListOf(ht.TInstanceOf(OpInstanceCreate)),
+     "List of instance create opcodes describing the instances to allocate"),
+    ]
+  _JOB_LIST = ht.Comment("List of submitted jobs")(TJobIdList)
+  ALLOCATABLE_KEY = "allocatable"
+  FAILED_KEY = "allocatable"
+  OP_RESULT = ht.TStrictDict(True, True, {
+    constants.JOB_IDS_KEY: _JOB_LIST,
+    ALLOCATABLE_KEY: ht.TListOf(ht.TNonEmptyString),
+    FAILED_KEY: ht.TListOf(ht.TNonEmptyString)
+    })
+
+  def __getstate__(self):
+    """Generic serializer.
+
+    """
+    state = OpCode.__getstate__(self)
+    if hasattr(self, "instances"):
+      # pylint: disable=E1101
+      state["instances"] = [inst.__getstate__() for inst in self.instances]
+    return state
+
+  def __setstate__(self, state):
+    """Generic unserializer.
+
+    This method just restores from the serialized state the attributes
+    of the current instance.
+
+    @param state: the serialized opcode data
+    @type state: C{dict}
+
+    """
+    if not isinstance(state, dict):
+      raise ValueError("Invalid data to __setstate__: expected dict, got %s" %
+                       type(state))
+
+    if "instances" in state:
+      insts = [OpCode.LoadOpCode(inst) for inst in state["instances"]]
+      state["instances"] = insts
+    return OpCode.__setstate__(self, state)
+
+
 class OpInstanceReinstall(OpCode):
   """Reinstall an instance's OS."""
   OP_DSC_FIELD = "instance_name"
index 9de861c..ebfeb08 100755 (executable)
@@ -77,7 +77,7 @@ class TestOpcodes(unittest.TestCase):
         {"dry_run": False, "debug_level": 0, },
 
         # All variables
-        dict([(name, False) for name in cls.GetAllSlots()])
+        dict([(name, []) for name in cls.GetAllSlots()])
         ]
 
       for i in args:
@@ -290,6 +290,20 @@ class TestOpcodes(unittest.TestCase):
     self.assertEqual(op.debug_level, 123)
 
 
+  def testOpInstanceMultiAlloc(self):
+    inst = dict([(name, []) for name in opcodes.OpInstanceCreate.GetAllSlots()])
+    inst_op = opcodes.OpInstanceCreate(**inst)
+    inst_state = inst_op.__getstate__()
+
+    multialloc = opcodes.OpInstanceMultiAlloc(instances=[inst_op])
+    state = multialloc.__getstate__()
+    self.assertEquals(state["instances"], [inst_state])
+    loaded_multialloc = opcodes.OpCode.LoadOpCode(state)
+    (loaded_inst,) = loaded_multialloc.instances
+    self.assertNotEquals(loaded_inst, inst_op)
+    self.assertEquals(loaded_inst.__getstate__(), inst_state)
+
+
 class TestOpcodeDepends(unittest.TestCase):
   def test(self):
     check_relative = opcodes._BuildJobDepCheck(True)