Revision b21d488b

b/lib/client/gnt_instance.py
1216 1216
  """
1217 1217
  result = []
1218 1218

  
1219
  for (idx, params) in mods:
1220
    if idx == constants.DDM_ADD:
1219
  for (identifier, params) in mods:
1220
    if identifier == constants.DDM_ADD:
1221 1221
      # Add item as last item (legacy interface)
1222 1222
      action = constants.DDM_ADD
1223
      idxno = -1
1224
    elif idx == constants.DDM_REMOVE:
1223
      identifier = -1
1224
    elif identifier == constants.DDM_REMOVE:
1225 1225
      # Remove last item (legacy interface)
1226 1226
      action = constants.DDM_REMOVE
1227
      idxno = -1
1227
      identifier = -1
1228 1228
    else:
1229 1229
      # Modifications and adding/removing at arbitrary indices
1230
      try:
1231
        idxno = int(idx)
1232
      except (TypeError, ValueError):
1233
        raise errors.OpPrereqError("Non-numeric index '%s'" % idx,
1234
                                   errors.ECODE_INVAL)
1235

  
1236 1230
      add = params.pop(constants.DDM_ADD, _MISSING)
1237 1231
      remove = params.pop(constants.DDM_REMOVE, _MISSING)
1238 1232
      modify = params.pop(constants.DDM_MODIFY, _MISSING)
......
1260 1254
      raise errors.OpPrereqError("Not accepting parameters on removal",
1261 1255
                                 errors.ECODE_INVAL)
1262 1256

  
1263
    result.append((action, idxno, params))
1257
    result.append((action, identifier, params))
1264 1258

  
1265 1259
  return result
1266 1260

  
b/lib/cmdlib.py
13123 13123
  return [(op, idx, params, fn()) for (op, idx, params) in mods]
13124 13124

  
13125 13125

  
13126
def GetItemFromContainer(identifier, kind, container):
13127
  """Return the item refered by the identifier.
13128

  
13129
  @type identifier: string
13130
  @param identifier: Item index or name or UUID
13131
  @type kind: string
13132
  @param kind: One-word item description
13133
  @type container: list
13134
  @param container: Container to get the item from
13135

  
13136
  """
13137
  # Index
13138
  try:
13139
    idx = int(identifier)
13140
    if idx == -1:
13141
      # Append
13142
      absidx = len(container) - 1
13143
    elif idx < 0:
13144
      raise IndexError("Not accepting negative indices other than -1")
13145
    elif idx > len(container):
13146
      raise IndexError("Got %s index %s, but there are only %s" %
13147
                       (kind, idx, len(container)))
13148
    else:
13149
      absidx = idx
13150
    return (absidx, container[idx])
13151
  except ValueError:
13152
    pass
13153

  
13154
  for idx, item in enumerate(container):
13155
    if item.uuid == identifier or item.name == identifier:
13156
      return (idx, item)
13157

  
13158
  raise errors.OpPrereqError("Cannot find %s with identifier %s" %
13159
                             (kind, identifier), errors.ECODE_NOENT)
13160

  
13161

  
13126 13162
#: Type description for changes as returned by L{ApplyContainerMods}'s
13127 13163
#: callbacks
13128 13164
_TApplyContModsCbChanges = \
......
13159 13195
    item and private data object as added by L{PrepareContainerMods}
13160 13196

  
13161 13197
  """
13162
  for (op, idx, params, private) in mods:
13163
    if idx == -1:
13164
      # Append
13165
      absidx = len(container) - 1
13166
    elif idx < 0:
13167
      raise IndexError("Not accepting negative indices other than -1")
13168
    elif idx > len(container):
13169
      raise IndexError("Got %s index %s, but there are only %s" %
13170
                       (kind, idx, len(container)))
13171
    else:
13172
      absidx = idx
13173

  
13198
  for (op, identifier, params, private) in mods:
13174 13199
    changes = None
13175 13200

  
13176 13201
    if op == constants.DDM_ADD:
13177 13202
      # Calculate where item will be added
13203
      # When adding an item, identifier can only be an index
13204
      try:
13205
        idx = int(identifier)
13206
      except ValueError:
13207
        raise errors.OpPrereqError("Only possitive integer or -1 is accepted as"
13208
                                   " identifier for %s" % constants.DDM_ADD,
13209
                                   errors.ECODE_INVAL)
13178 13210
      if idx == -1:
13179 13211
        addidx = len(container)
13180 13212
      else:
13213
        if idx < 0:
13214
          raise IndexError("Not accepting negative indices other than -1")
13215
        elif idx > len(container):
13216
          raise IndexError("Got %s index %s, but there are only %s" %
13217
                           (kind, idx, len(container)))
13181 13218
        addidx = idx
13182 13219

  
13183 13220
      if create_fn is None:
......
13194 13231
        container.insert(idx, item)
13195 13232
    else:
13196 13233
      # Retrieve existing item
13197
      try:
13198
        item = container[absidx]
13199
      except IndexError:
13200
        raise IndexError("Invalid %s index %s" % (kind, idx))
13234
      (absidx, item) = GetItemFromContainer(identifier, kind, container)
13201 13235

  
13202 13236
      if op == constants.DDM_REMOVE:
13203 13237
        assert not params
b/lib/opcodes.py
1645 1645
  mod_item_fn = \
1646 1646
    ht.TAnd(ht.TIsLength(3), ht.TItems([
1647 1647
      ht.TElemOf(constants.DDMS_VALUES_WITH_MODIFY),
1648
      ht.Comment("Disk index, can be negative, e.g. -1 for last disk")(ht.TInt),
1648
      ht.Comment("Device index, can be negative, e.g. -1 for last disk")
1649
                 (ht.TOr(ht.TInt, ht.TString)),
1649 1650
      fn,
1650 1651
      ]))
1651 1652

  
......
1667 1668
    _PForceVariant,
1668 1669
    _PIgnoreIpolicy,
1669 1670
    ("nics", ht.EmptyList, TestNicModifications,
1670
     "List of NIC changes: each item is of the form ``(op, index, settings)``,"
1671
     " ``op`` is one of ``%s``, ``%s`` or ``%s``, ``index`` can be either -1"
1672
     " to refer to the last position, or a zero-based index number; a"
1671
     "List of NIC changes: each item is of the form"
1672
     " ``(op, identifier, settings)``, ``op`` is one of ``%s``, ``%s`` or"
1673
     " ``%s``, ``identifier`` can be a zero-based index number (or -1 to refer"
1674
     " to the last position), the NIC's UUID of the NIC's name; a"
1673 1675
     " deprecated version of this parameter used the form ``(op, settings)``,"
1674 1676
     " where ``op`` can be ``%s`` to add a new NIC with the specified"
1675 1677
     " settings, ``%s`` to remove the last NIC or a number to modify the"
b/test/py/ganeti.client.gnt_instance_unittest.py
133 133
      (0, { constants.DDM_REMOVE: True, "param": "value", }),
134 134
      ])
135 135
    self.assertRaises(errors.OpPrereqError, fn, [
136
      ("Hello", {}),
137
      ])
138
    self.assertRaises(errors.OpPrereqError, fn, [
139 136
      (0, {
140 137
        constants.DDM_REMOVE: True,
141 138
        constants.DDM_ADD: True,
......
207 204
        }),
208 205
      ])
209 206

  
207
    # Names and UUIDs
208
    self.assertEqual(fn([
209
      ('name', {
210
        constants.IDISK_MODE: constants.DISK_RDWR,
211
        constants.IDISK_NAME: "rename",
212
        }),
213
      ]), [
214
      (constants.DDM_MODIFY, 'name', {
215
        constants.IDISK_MODE: constants.DISK_RDWR,
216
        constants.IDISK_NAME: "rename",
217
        }),
218
      ])
219
    self.assertEqual(fn([
220
      ('024ef14d-4879-400e-8767-d61c051950bf', {
221
        constants.DDM_MODIFY: True,
222
        constants.IDISK_SIZE: 1024,
223
        constants.IDISK_NAME: "name",
224
        }),
225
      ]), [
226
      (constants.DDM_MODIFY, '024ef14d-4879-400e-8767-d61c051950bf', {
227
        constants.IDISK_SIZE: 1024,
228
        constants.IDISK_NAME: "name",
229
        }),
230
      ])
231
    self.assertEqual(fn([
232
      ('name', {
233
        constants.DDM_REMOVE: True,
234
        }),
235
      ]), [
236
      (constants.DDM_REMOVE, 'name', {}),
237
      ])
238

  
210 239

  
211 240
class TestParseDiskSizes(unittest.TestCase):
212 241
  def test(self):

Also available in: Unified diff