On 11/10/2014 06:12 PM, Aaron Karper wrote:
> On Thu, Nov 06, 2014 at 12:30:44AM +0200, Alex Pyrgiotis wrote:
>> Extend _ApplyContainerMods to accept an attach and detach function.
>> These functions operate in the same way as the add and remove functions,
>> minus the disk creation and disk removal parts.
>>
>> Also, add two functions that should raise an exception if one attempts
>> to attach/detach a NIC.
>>
>> Finally, update the tests in order to work with the new
>> _ApplyContainerMods function.
>>
>> Signed-off-by: Alex Pyrgiotis <[email protected] <mailto:[email protected]>>
>>
>> diff --git a/lib/cmdlib/instance_set___params.py
> b/lib/cmdlib/instance_set___params.py
>> index a4cc576..65e2a6c 100644
>> --- a/lib/cmdlib/instance_set___params.py
>> +++ b/lib/cmdlib/instance_set___params.py
>> @@ -58,7 +58,7 @@ from ganeti.cmdlib.instance_storage import
> CalculateFileStorageDir, \
>>    ComputeDiskSizePerVG, ComputeDisksInfo, CreateDisks, \
>>    CreateSingleBlockDev, GenerateDiskTemplate, \
>>    IsExclusiveStorageEnabledNodeU__uid, ShutdownInstanceDisks, \
>> -  WaitForSync, WipeOrCleanupDisks
>> +  WaitForSync, WipeOrCleanupDisks, AssembleInstanceDisks
>>  from ganeti.cmdlib.instance_utils import BuildInstanceHookEnvByObject, \
>>    NICToTuple, CheckNodeNotDrained, CopyLockList, \
>>    ReleaseLocks, CheckNodeVmCapable, CheckTargetNodeIPolicy, \
>> @@ -783,8 +783,8 @@ class LUInstanceSetParams(__LogicalUnit):
>>      # Verify disk changes (operating on a copy)
>>      inst_disks = self.cfg.GetInstanceDisks(__self.instance.uuid)
>>      disks = copy.deepcopy(inst_disks)
>> -    ApplyContainerMods("disk", disks, None, self.diskmod, None,
>> -                       _PrepareDiskMod, None)
>> +    ApplyContainerMods("disk", disks, None, self.diskmod, None, None,
>> +                       _PrepareDiskMod, None, None)
>>      utils.ValidateDeviceNames("__disk", disks)
>>      if len(disks) > constants.MAX_DISKS:
>>        raise errors.OpPrereqError("Instance has too many disks (%d),
> cannot add"
>> @@ -1160,6 +1160,10 @@ class LUInstanceSetParams(__LogicalUnit):
>>                                     {}, cluster, pnode_uuid)
>>        return (None, None)
>>
>> +    def _PrepareNicAttach(_, __, ___):
>> +      raise errors.OpPrereqError("Attach operation is not supported
> for NICs",
>> +                                 errors.ECODE_INVAL)
>> +
>>      def _PrepareNicMod(_, nic, params, private):
>>        self._PrepareNicModification(__params, private, nic.ip,
> nic.network,
>>                                     nic.nicparams, cluster, pnode_uuid)
>> @@ -1171,10 +1175,15 @@ class LUInstanceSetParams(__LogicalUnit):
>>        if net is not None and ip is not None:
>>          self.cfg.ReleaseIp(net, ip, self.proc.GetECId())
>>
>> +    def _PrepareNicDetach(_, __, ___):
>> +      raise errors.OpPrereqError("Detach operation is not supported
> for NICs",
>> +                                 errors.ECODE_INVAL)
>> +
>>      # Verify NIC changes (operating on copy)
>>      nics = [nic.Copy() for nic in self.instance.nics]
>> -    ApplyContainerMods("NIC", nics, None, self.nicmod,
>> -                       _PrepareNicCreate, _PrepareNicMod,
> _PrepareNicRemove)
>> +    ApplyContainerMods("NIC", nics, None, self.nicmod, _PrepareNicCreate,
>> +                       _PrepareNicAttach, _PrepareNicMod,
> _PrepareNicRemove,
>> +                       _PrepareNicDetach)
>>      if len(nics) > constants.MAX_NICS:
>>        raise errors.OpPrereqError("Instance has too many network
> interfaces"
>>                                   " (%d), cannot add more" %
> constants.MAX_NICS,
>> @@ -1186,8 +1195,8 @@ class LUInstanceSetParams(__LogicalUnit):
>>        # Operate on copies as this is still in prereq
>>        nics = [nic.Copy() for nic in self.instance.nics]
>>        ApplyContainerMods("NIC", nics, self._nic_chgdesc, self.nicmod,
>> -                         self._CreateNewNic, self._ApplyNicMods,
>> -                         self._RemoveNic)
>> +                         self._CreateNewNic, None, self._ApplyNicMods,
>> +                         self._RemoveNic, None)
>>        # Verify that NIC names are unique and valid
>>        utils.ValidateDeviceNames("__NIC", nics)
>>        self._new_nics = nics
>> @@ -1588,6 +1597,36 @@ class LUInstanceSetParams(__LogicalUnit):
>>      if not self.instance.disks_active:
>>        ShutdownInstanceDisks(self, self.instance, disks=[disk])
>>
>> +  def _AttachDisk(self, idx, params, _):
>> +    """Attaches an existing disk to an instance.
>> +
>> +    """
>> +    disk = self.GenericGetDiskInfo(**__params) # pylint: disable=W0142
> 
> see above.
> 

ACK.

>>
>> +    self.cfg.AttachInstanceDisk(__self.instance.uuid, disk, idx)
>> +
>> +    # re-read the instance from the configuration
>> +    self.instance = self.cfg.GetInstanceInfo(self.__instance.uuid)
>> +
>> +    changes = [
>> +      ("disk/%d" % idx,
>> +       "attach:size=%s,mode=%s" % (disk.size, disk.mode)),
>> +      ]
>> +
>> +    if self.op.hotplug:
>> +      disks_ok, _, results = AssembleInstanceDisks(self, self.instance,
>> +                                                   disks=[disk])
>> +      if not disks_ok:
>> +        changes.append(("disk/%d" % idx, "assemble:failed"))
>> +        return disk, changes
>> +
>> +      _, link_name, uri = results[0].payload
>> +      msg = self._HotplugDevice(constants.__HOTPLUG_ACTION_ADD,
>> +                                constants.HOTPLUG_TARGET_DISK,
>> +                                disk, (link_name, uri), idx)
>> +      changes.append(("disk/%d" % idx, msg))
>> +
>> +    return (disk, changes)
>> +
>>    def _ModifyDisk(self, idx, disk, params, _):
>>      """Modifies a disk.
>>
>> @@ -1645,6 +1684,27 @@ class LUInstanceSetParams(__LogicalUnit):
>>
>>      return hotmsg
>>
>> +  def _DetachDisk(self, idx, root, _):
>> +    """Detaches a disk from an instance.
>> +
>> +    """
>> +    hotmsg = ""
>> +    if self.op.hotplug:
>> +      hotmsg = self._HotplugDevice(constants.__HOTPLUG_ACTION_REMOVE,
>> +                                   constants.HOTPLUG_TARGET_DISK,
>> +                                   root, None, idx)
>> +
>> +    # Always shutdown the disk before detaching.
>> +    ShutdownInstanceDisks(self, self.instance, [root])
>> +
>> +    # Remove disk from config
>> +    self.cfg.DetachInstanceDisk(__self.instance.uuid, root.uuid)
>> +
>> +    # re-read the instance from the configuration
>> +    self.instance = self.cfg.GetInstanceInfo(self.__instance.uuid)
>> +
>> +    return hotmsg
>> +
>>    def _CreateNewNic(self, idx, params, private):
>>      """Creates data structure for a new network interface.
>>
>> @@ -1746,8 +1806,9 @@ class LUInstanceSetParams(__LogicalUnit):
>>      # Apply disk changes
>>      inst_disks = self.cfg.GetInstanceDisks(__self.instance.uuid)
>>      ApplyContainerMods("disk", inst_disks, result, self.diskmod,
>> -                       self._CreateNewDisk, self._ModifyDisk,
>> -                       self._RemoveDisk, post_add_fn=self._PostAddDisk)
>> +                       self._CreateNewDisk, self._AttachDisk,
> self._ModifyDisk,
>> +                       self._RemoveDisk, self._DetachDisk,
>> +                       post_add_fn=self._PostAddDisk)
>>
>>      if self.op.disk_template:
>>        if __debug__:
>> diff --git a/lib/cmdlib/instance_utils.py b/lib/cmdlib/instance_utils.py
>> index f3b6a40..5a9849c 100644
>> --- a/lib/cmdlib/instance_utils.py
>> +++ b/lib/cmdlib/instance_utils.py
>> @@ -873,8 +873,8 @@ def PrepareContainerMods(mods, private_fn):
>>
>>
>>  def ApplyContainerMods(kind, container, chgdesc, mods,
>> -                       create_fn, modify_fn, remove_fn,
>> -                       post_add_fn=None):
>> +                       create_fn, attach_fn, modify_fn, remove_fn,
>> +                       detach_fn, post_add_fn=None):
>>    """Applies descriptions in C{mods} to C{container}.
>>
>>    @type kind: string
>> @@ -890,6 +890,10 @@ def ApplyContainerMods(kind, container, chgdesc,
> mods,
>>      receives absolute item index, parameters and private data object
> as added
>>      by L{PrepareContainerMods}, returns tuple containing new item and
> changes
>>      as list
>> +  @type attach_fn: callable
>> +  @param attach_fn: Callback for attaching an existing item to a
> container
>> +    (L{constants.DDM_ATTACH}); receives absolute item index and item
> UUID or
>> +    name, returns tuple containing new item and changes as list
>>    @type modify_fn: callable
>>    @param modify_fn: Callback for modifying an existing item
>>      (L{constants.DDM_MODIFY}); receives absolute item index, item,
> parameters
>> @@ -898,6 +902,9 @@ def ApplyContainerMods(kind, container, chgdesc, mods,
>>    @type remove_fn: callable
>>    @param remove_fn: Callback on removing item; receives absolute item
> index,
>>      item and private data object as added by L{PrepareContainerMods}
>> +  @type detach_fn: callable
>> +  @param detach_fn: Callback on detaching item; receives absolute
> item index,
>> +    item and private data object as added by L{PrepareContainerMods}
>>    @type post_add_fn: callable
>>    @param post_add_fn: Callable for post-processing a newly created
> item after
>>      it has been put into the container. It receives the index of the
> new item
>> @@ -919,6 +926,18 @@ def ApplyContainerMods(kind, container, chgdesc,
> mods,
>>        if post_add_fn is not None:
>>          post_add_fn(addidx, item)
>>
>> +    elif op == constants.DDM_ATTACH:
>> +      addidx = GetIndexFromIdentifier(__identifier, kind, container)
>> +      if attach_fn is None:
>> +        item = params
>> +      else:
>> +        (item, changes) = attach_fn(addidx, params, private)
>> +
>> +      InsertItemToIndex(int(__identifier), item, container)
>> +
>> +      if post_add_fn is not None:
>> +        post_add_fn(addidx, item)
>> +
>>      else:
>>        # Retrieve existing item
>>        (absidx, item) = GetItemFromContainer(__identifier, kind,
> container)
>> @@ -935,6 +954,18 @@ def ApplyContainerMods(kind, container, chgdesc,
> mods,
>>
>>          assert container[absidx] == item
>>          del container[absidx]
>> +      elif op == constants.DDM_DETACH:
>> +        assert not params
>> +
>> +        changes = [("%s/%s" % (kind, absidx), "detach")]
>> +
>> +        if detach_fn is not None:
>> +          msg = detach_fn(absidx, item, private)
>> +          if msg:
>> +            changes.append(("%s/%s" % (kind, absidx), msg))
>> +
>> +        assert container[absidx] == item
>> +        del container[absidx]
>>        elif op == constants.DDM_MODIFY:
>>          if modify_fn is not None:
>>            changes = modify_fn(absidx, item, params, private)
>> diff --git a/test/py/cmdlib/instance___unittest.py
> b/test/py/cmdlib/instance___unittest.py
>> index bc44dd4..32c7496 100644
>> --- a/test/py/cmdlib/instance___unittest.py
>> +++ b/test/py/cmdlib/instance___unittest.py
>> @@ -963,7 +963,7 @@ class TestApplyContainerMods(__unittest.TestCase):
>>      container = []
>>      chgdesc = []
>>      instance_utils.__ApplyContainerMods("test", container, chgdesc,
> [], None,
>> -                                      None, None)
>> +                                      None, None, None, None)
>>      self.assertEqual(container, [])
>>      self.assertEqual(chgdesc, [])
>>
>> @@ -976,8 +976,8 @@ class TestApplyContainerMods(__unittest.TestCase):
>>        (constants.DDM_ADD, 0, "Start"),
>>        (constants.DDM_ADD, -1, "End"),
>>        ], None)
>> -    instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> -                                      None, None, None)
>> +instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> +                                  None, None, None, None, None)
>>      self.assertEqual(container, ["Start", "Hello", "World", "End"])
>>      self.assertEqual(chgdesc, [])
>>
>> @@ -987,8 +987,8 @@ class TestApplyContainerMods(__unittest.TestCase):
>>        (constants.DDM_ADD, 5, "four"),
>>        (constants.DDM_ADD, 7, "xyz"),
>>        ], None)
>> -    instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> -                                      None, None, None)
>> +instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> +                                  None, None, None, None, None)
>>      self.assertEqual(container,
>>                       ["zero", "Start", "Hello", "Added", "World", "four",
>>                        "End", "xyz"])
>> @@ -999,7 +999,8 @@ class TestApplyContainerMods(__unittest.TestCase):
>>          (constants.DDM_ADD, idx, "error"),
>>          ], None)
>>        self.assertRaises(IndexError, instance_utils.__ApplyContainerMods,
>> -                        "test", container, None, mods, None, None, None)
>> +                        "test", container, None, mods, None, None,
> None, None,
>> +                        None)
>>
>>    def testRemoveError(self):
>>      for idx in [0, 1, 2, 100, -1, -4]:
>> @@ -1007,13 +1008,13 @@ class TestApplyContainerMods(__unittest.TestCase):
>>          (constants.DDM_REMOVE, idx, None),
>>          ], None)
>>        self.assertRaises(IndexError, instance_utils.__ApplyContainerMods,
>> -                        "test", [], None, mods, None, None, None)
>> +                        "test", [], None, mods, None, None, None,
> None, None)
>>
>>      mods = instance_utils.__PrepareContainerMods([
>>        (constants.DDM_REMOVE, 0, object()),
>>        ], None)
>>      self.assertRaises(__AssertionError,
> instance_utils.__ApplyContainerMods,
>> -                      "test", [""], None, mods, None, None, None)
>> +                      "test", [""], None, mods, None, None, None,
> None, None)
>>
>>    def testAddError(self):
>>      for idx in range(-100, -1) + [100]:
>> @@ -1021,7 +1022,7 @@ class TestApplyContainerMods(__unittest.TestCase):
>>          (constants.DDM_ADD, idx, None),
>>          ], None)
>>        self.assertRaises(IndexError, instance_utils.__ApplyContainerMods,
>> -                        "test", [], None, mods, None, None, None)
>> +                        "test", [], None, mods, None, None, None,
> None, None)
>>
>>    def testRemove(self):
>>      container = ["item 1", "item 2"]
>> @@ -1031,8 +1032,8 @@ class TestApplyContainerMods(__unittest.TestCase):
>>        (constants.DDM_ADD, -1, "bbb"),
>>        ], None)
>>      chgdesc = []
>> -    instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> -                                      None, None, None)
>> +instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> +                                  None, None, None, None, None)
>>      self.assertEqual(container, ["item 1", "item 2", "bbb"])
>>      self.assertEqual(chgdesc, [
>>        ("test/2", "remove"),
>> @@ -1046,8 +1047,8 @@ class TestApplyContainerMods(__unittest.TestCase):
>>        (constants.DDM_MODIFY, 1, "c"),
>>        ], None)
>>      chgdesc = []
>> -    instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> -                                      None, None, None)
>> +instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> +                                  None, None, None, None, None)
>>      self.assertEqual(container, ["item 1", "item 2"])
>>      self.assertEqual(chgdesc, [])
>>
>> @@ -1056,7 +1057,8 @@ class TestApplyContainerMods(__unittest.TestCase):
>>          (constants.DDM_MODIFY, idx, "error"),
>>          ], None)
>>        self.assertRaises(IndexError, instance_utils.__ApplyContainerMods,
>> -                        "test", container, None, mods, None, None, None)
>> +                        "test", container, None, mods, None, None,
> None, None,
>> +                        None)
>>
>>    @staticmethod
>>    def _CreateTestFn(idx, params, private):
>> @@ -1090,8 +1092,8 @@ class TestApplyContainerMods(__unittest.TestCase):
>>        (constants.DDM_ADD, 1, "More"),
>>        ], mock.Mock)
>>      instance_utils.__ApplyContainerMods("test", container, chgdesc, mods,
>> -                                      self._CreateTestFn,
> self._ModifyTestFn,
>> -                                      self._RemoveTestFn)
>> +                                      self._CreateTestFn, None,
> self._ModifyTestFn,
>> +                                      self._RemoveTestFn, None)
>>      self.assertEqual(container, [
>>        (000, "Start"),
>>        (100, "More"),
>> --
>> 1.7.10.4
>>
> 
> 
> LGTM
> 
> --
> Google Germany GmbH
> Dienerstr. 12
> 80331 München
> 
> Registergericht und -nummer: Hamburg, HRB 86891
> Sitz der Gesellschaft: Hamburg
> Geschäftsführer: Graham Law, Christine Elizabeth Flores


-- 
Alex | [email protected]

Reply via email to