Implement functions 'AddDisk' and 'AttachInstDisk'. The first one adds
a new disk to the config file and the second one attaches a disk to an
instance. A wrapper 'AddInstDisk' is provided in order to add a disk and
attach it to an instance at once (because ganeti doesn't support
dangling disks right now).

Signed-off-by: Ilias Tsitsimpis <[email protected]>
---
 lib/config.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/lib/config.py b/lib/config.py
index febc4ee..4df28c5 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -255,6 +255,16 @@ class ConfigManager(object):
     return False
 
 
+def _UpdateIvNames(base_index, disks):
+  """Update the C{iv_name} attribute of disks.
+
+  @type disks: list of L{objects.Disk}
+
+  """
+  for (idx, disk) in enumerate(disks):
+    disk.iv_name = "disk/%s" % (base_index + idx)
+
+
 class ConfigWriter(object):
   """The interface to the cluster configuration.
 
@@ -371,6 +381,89 @@ class ConfigWriter(object):
     """
     return self._UnlockedGetInstanceDisks(instance)
 
+  def _UnlockedAddDisk(self, disk):
+    """Add a disk to the config.
+
+    This function is for internal use, when the config lock is already held.
+
+    @type disk: L{objects.Disk}
+    @param disk: the disk object
+
+    """
+    if not isinstance(disk, objects.Disk):
+      raise errors.ProgrammerError("Invalid type passed to _UnlockedAddDisk")
+
+    logging.info("Adding disk %s to configuration", disk.uuid)
+
+    self._CheckUniqueUUID(disk, include_temporary=False)
+    disk.serial_no = 1
+    disk.ctime = disk.mtime = time.time()
+    disk.UpgradeConfig()
+    self._ConfigData().disks[disk.uuid] = disk
+    self._ConfigData().cluster.serial_no += 1
+
+  def _UnlockedAttachInstDisk(self, instance, disk, idx=None):
+    """Attach a disk to an instance.
+
+    This function is for internal use, when the config lock is already held.
+
+    @type instance: L{objects.Instance}
+    @param instance: the instance object
+    @type disk: L{objects.Disk}
+    @param disk: the disk object
+    @type idx: int
+    @param idx: the index of the newly attached disk
+
+    """
+    if not isinstance(instance, objects.Instance) or \
+        not isinstance(disk, objects.Disk):
+      raise errors.ProgrammerError(
+        "Invalid type passed to _UnlockedAttachInstDisk")
+    if instance.uuid not in self._ConfigData().instances:
+      raise errors.ConfigurationError("Instance %s doesn't exist"
+                                      % instance.uuid)
+    if disk.uuid not in self._ConfigData().disks:
+      raise errors.ConfigurationError("Disk %s doesn't exist" % disk.uuid)
+
+    if idx is None:
+      idx = len(instance.disks)
+    else:
+      if idx < 0:
+        raise IndexError("Not accepting negative indices other than -1")
+      elif idx > len(instance.disks):
+        raise IndexError("Got disk index %s, but there are only %s" %
+                         (idx, len(instance.disks)))
+
+    # Disk must not be attached anywhere else
+    for inst in self._ConfigData().instances.values():
+      if disk.uuid in inst.disks:
+        raise errors.ReservationError("Disk %s already attached to instance %s"
+                                      % (disk.uuid, inst.name))
+
+    instance.disks.insert(idx, disk.uuid)
+    inst_disks = self._UnlockedGetInstanceDisks(instance)
+    _UpdateIvNames(idx, inst_disks[idx:])
+    instance.serial_no += 1
+    instance.mtime = time.time()
+
+    # Update instance object
+    self._ConfigData().instances[instance.uuid] = instance
+
+  @_ConfigSync()
+  def AddInstDisk(self, instance, disk, idx=None):
+    """Add a disk to the config and attach it to instance.
+
+    @type instance: L{objects.Instance}
+    @param instance: the instance object
+    @type disk: L{objects.Disk}
+    @param disk: the disk object
+    @type idx: int
+    @param idx: the index of the newly attached disk
+
+    """
+    self._UnlockedAddDisk(disk)
+    self._UnlockedAttachInstDisk(instance, disk, idx)
+
   def _UnlockedGetDiskInfo(self, disk_uuid):
     """Returns information about an instance.
 
@@ -3084,6 +3177,8 @@ class ConfigWriter(object):
       replace_in(target, self._ConfigData().nodegroups)
     elif isinstance(target, objects.Network):
       replace_in(target, self._ConfigData().networks)
+    elif isinstance(target, objects.Disk):
+      replace_in(target, self._ConfigData().disks)
     else:
       raise errors.ProgrammerError("Invalid object type (%s) passed to"
                                    " ConfigWriter.Update" % type(target))
-- 
1.9.1

Reply via email to