Revision 651cc3e2

b/lib/cmdlib.py
10186 10186
    # check nics' parameter names
10187 10187
    for nic in self.op.nics:
10188 10188
      utils.ForceDictType(nic, constants.INIC_PARAMS_TYPES)
10189
    # check that NIC's parameters names are unique and valid
10190
    utils.ValidateDeviceNames("NIC", self.op.nics)
10191

  
10192
    # check that disk's names are unique and valid
10193
    utils.ValidateDeviceNames("disk", self.op.disks)
10189 10194

  
10190 10195
    cluster = self.cfg.GetClusterInfo()
10191 10196
    if not self.op.disk_template in cluster.enabled_disk_templates:
......
14009 14014
                                 " (%d), cannot add more" % constants.MAX_NICS,
14010 14015
                                 errors.ECODE_STATE)
14011 14016

  
14017
    def _PrepareDiskMod(_, disk, params, __):
14018
      disk.name = params.get(constants.IDISK_NAME, None)
14019

  
14012 14020
    # Verify disk changes (operating on a copy)
14013
    disks = instance.disks[:]
14014
    ApplyContainerMods("disk", disks, None, self.diskmod, None, None, None)
14021
    disks = copy.deepcopy(instance.disks)
14022
    ApplyContainerMods("disk", disks, None, self.diskmod, None, _PrepareDiskMod,
14023
                       None)
14024
    utils.ValidateDeviceNames("disk", disks)
14015 14025
    if len(disks) > constants.MAX_DISKS:
14016 14026
      raise errors.OpPrereqError("Instance has too many disks (%d), cannot add"
14017 14027
                                 " more" % constants.MAX_DISKS,
......
14033 14043
      nics = [nic.Copy() for nic in instance.nics]
14034 14044
      ApplyContainerMods("NIC", nics, self._nic_chgdesc, self.nicmod,
14035 14045
                         self._CreateNewNic, self._ApplyNicMods, None)
14046
      # Verify that NIC names are unique and valid
14047
      utils.ValidateDeviceNames("NIC", nics)
14036 14048
      self._new_nics = nics
14037 14049
      ispec[constants.ISPEC_NIC_COUNT] = len(self._new_nics)
14038 14050
    else:
b/lib/utils/__init__.py
797 797

  
798 798
    """
799 799
    return [val for val in items if not self.Matches(val)]
800

  
801

  
802
def ValidateDeviceNames(kind, container):
803
  """Validate instance device names.
804

  
805
  Check that a device container contains only unique and valid names.
806

  
807
  @type kind: string
808
  @param kind: One-word item description
809
  @type container: list
810
  @param container: Container containing the devices
811

  
812
  """
813

  
814
  valid = []
815
  for device in container:
816
    if isinstance(device, dict):
817
      if kind == "NIC":
818
        name = device.get(constants.INIC_NAME, None)
819
      elif kind == "disk":
820
        name = device.get(constants.IDISK_NAME, None)
821
      else:
822
        raise errors.OpPrereqError("Invalid container kind '%s'" % kind,
823
                                   errors.ECODE_INVAL)
824
    else:
825
      name = device.name
826
      # Check that a device name is not the UUID of another device
827
      valid.append(device.uuid)
828

  
829
    try:
830
      int(name)
831
    except (ValueError, TypeError):
832
      pass
833
    else:
834
      raise errors.OpPrereqError("Invalid name '%s'. Purely numeric %s names"
835
                                 " are not allowed" % (name, kind),
836
                                 errors.ECODE_INVAL)
837

  
838
    if name is not None and name.lower() != constants.VALUE_NONE:
839
      if name in valid:
840
        raise errors.OpPrereqError("%s name '%s' already used" % (kind, name),
841
                                   errors.ECODE_NOTUNIQUE)
842
      else:
843
        valid.append(name)
b/test/py/ganeti.utils_unittest.py
369 369
                      some_keys, self.defaults)
370 370

  
371 371

  
372
class TestValidateDeviceNames(unittest.TestCase):
373
  def testEmpty(self):
374
    utils.ValidateDeviceNames("NIC", [])
375
    utils.ValidateDeviceNames("disk", [])
376

  
377
  def testNoName(self):
378
    nics = [{}, {}]
379
    utils.ValidateDeviceNames("NIC", nics)
380

  
381
  def testInvalidName(self):
382
    self.assertRaises(errors.OpPrereqError, utils.ValidateDeviceNames,
383
                      "disk", [{constants.IDISK_NAME: "42"}])
384
    self.assertRaises(errors.OpPrereqError, utils.ValidateDeviceNames,
385
                      "NIC", [{constants.INIC_NAME: "42"}])
386

  
387
  def testUsedName(self):
388
    disks = [{constants.IDISK_NAME: "name1"}, {constants.IDISK_NAME: "name1"}]
389
    self.assertRaises(errors.OpPrereqError, utils.ValidateDeviceNames,
390
                      "disk", disks)
391

  
392

  
372 393
if __name__ == "__main__":
373 394
  testutils.GanetiTestProgram()

Also available in: Unified diff