Implement functions 'AddDisk' and 'AttachInstanceDisk'. The first one adds a new disk to the config file and the second one attaches a disk to an instance. A wrapper 'AddInstanceDisk' 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 | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/lib/config.py b/lib/config.py index f926e30..c0359c5 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. @@ -376,6 +386,75 @@ class ConfigWriter(object): """ return self._UnlockedGetInstanceDisks(inst_uuid) + def _UnlockedAddDisk(self, disk): + """Add a disk to the config. + + @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 _UnlockedAttachInstanceDisk(self, inst_uuid, disk_uuid, idx=None): + """Attach a disk to an instance. + + @type inst_uuid: string + @param inst_uuid: The UUID of the instance object + @type disk_uuid: string + @param disk_uuid: The UUID of the disk object + @type idx: int + @param idx: the index of the newly attached disk + + """ + instance = self._UnlockedGetInstanceInfo(inst_uuid) + if instance is None: + raise errors.ConfigurationError("Instance %s doesn't exist" + % inst_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) + instance_disks = self._UnlockedGetInstanceDisks(inst_uuid) + _UpdateIvNames(idx, instance_disks[idx:]) + instance.serial_no += 1 + instance.mtime = time.time() + + @_ConfigSync() + def AddInstanceDisk(self, inst_uuid, disk, idx=None): + """Add a disk to the config and attach it to instance. + + This is a simple wrapper over L{_UnlockedAddDisk} and + L{_UnlockedAttachInstanceDisk}. + + """ + self._UnlockedAddDisk(disk) + self._UnlockedAttachInstanceDisk(inst_uuid, disk.uuid, idx) + def _UnlockedGetDiskInfo(self, disk_uuid): """Returns information about a disk. @@ -3089,6 +3168,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
