X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/52e2f66ef0ed40cf0f6ab4274c7cfc0e4998fc82..9332fd8a2a645d97eb8711206cd6944aa1dffb2e:/lib/backend.py diff --git a/lib/backend.py b/lib/backend.py index 7a9e0d8..2a483db 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -89,7 +89,7 @@ def _Decompress(data): raise AssertionError("Unknown data encoding") -def _CleanDirectory(path, exclude=[]): +def _CleanDirectory(path, exclude=None): """Removes all regular files in a directory. @type path: str @@ -97,14 +97,15 @@ def _CleanDirectory(path, exclude=[]): @type exclude: list @param exclude: list of files to be excluded, defaults to the empty list - @rtype: None """ if not os.path.isdir(path): return - - # Normalize excluded paths - exclude = [os.path.normpath(i) for i in exclude] + if exclude is None: + exclude = [] + else: + # Normalize excluded paths + exclude = [os.path.normpath(i) for i in exclude] for rel_name in utils.ListVisibleFiles(path): full_name = os.path.normpath(os.path.join(path, rel_name)) @@ -279,7 +280,7 @@ def LeaveCluster(): from the cluster. If processing is successful, then it raises an - L{errors.GanetiQuitException} which is used as a special case to + L{errors.QuitGanetiException} which is used as a special case to shutdown the node daemon. """ @@ -732,7 +733,38 @@ def _GetVGInfo(vg_name): return retdic -def _GatherBlockDevs(instance): +def _SymlinkBlockDev(instance_name, device_path, device_name): + """Set up symlinks to a instance's block device. + + This is an auxiliary function run when an instance is start (on the primary + node) or when an instance is migrated (on the target node). + + Args: + instance_name: the name of the target instance + device_path: path of the physical block device, on the node + device_name: 'virtual' name of the device + + Returns: + absolute path to the disk's symlink + + """ + link_basename = "%s-%s" % (instance_name, device_name) + link_name = os.path.join(constants.DISK_LINKS_DIR, link_basename) + try: + os.symlink(device_path, link_name) + except OSError, e: + if e.errno == errno.EEXIST: + if (not os.path.islink(link_name) or + os.readlink(link_name) != device_path): + os.remove(link_name) + os.symlink(device_path, link_name) + else: + raise + + return link_name + + +def _GatherAndLinkBlockDevs(instance): """Set up an instance's block device(s). This is run on the primary node at instance startup. The block @@ -740,18 +772,26 @@ def _GatherBlockDevs(instance): @type instance: L{objects.Instance} @param instance: the instance whose disks we shoul assemble - @rtype: list of L{bdev.BlockDev} - @return: list of the block devices + @rtype: list + @return: list of (disk_object, device_path) """ block_devices = [] - for disk in instance.disks: + for idx, disk in enumerate(instance.disks): device = _RecursiveFindBD(disk) if device is None: raise errors.BlockDeviceError("Block device '%s' is not set up." % str(disk)) device.Open() - block_devices.append((disk, device)) + try: + link_name = _SymlinkBlockDev(instance.name, device.dev_path, + "disk%d" % idx) + except OSError, e: + raise errors.BlockDeviceError("Cannot create block device symlink: %s" % + e.strerror) + + block_devices.append((disk, link_name)) + return block_devices @@ -769,7 +809,7 @@ def StartInstance(instance, extra_args): if instance.name in running_instances: return True - block_devices = _GatherBlockDevs(instance) + block_devices = _GatherAndLinkBlockDevs(instance) hyper = hypervisor.GetHypervisor(instance.hypervisor) try: @@ -806,7 +846,6 @@ def ShutdownInstance(instance): return False # test every 10secs for 2min - shutdown_ok = False time.sleep(1) for dummy in range(11): @@ -970,16 +1009,14 @@ def RemoveBlockDevice(disk): @note: This is intended to be called recursively. - @type disk: L{objects.disk} + @type disk: L{objects.Disk} @param disk: the disk object we should remove @rtype: boolean @return: the success of the operation """ try: - # since we are removing the device, allow a partial match - # this allows removal of broken mirrors - rdev = _RecursiveFindBD(disk, allow_partial=True) + rdev = _RecursiveFindBD(disk) except errors.BlockDeviceError, err: # probably can't attach logging.info("Can't attach to device %s in remove", disk) @@ -1069,8 +1106,9 @@ def AssembleBlockDevice(disk, owner, as_primary): def ShutdownBlockDevice(disk): """Shut down a block device. - First, if the device is assembled (can L{Attach()}), then the device - is shutdown. Then the children of the device are shutdown. + First, if the device is assembled (Attach() is successfull), then + the device is shutdown. Then the children of the device are + shutdown. This function is called recursively. Note that we don't cache the children or such, as oppossed to assemble, shutdown of different @@ -1108,7 +1146,7 @@ def MirrorAddChildren(parent_cdev, new_cdevs): @return: the success of the operation """ - parent_bdev = _RecursiveFindBD(parent_cdev, allow_partial=True) + parent_bdev = _RecursiveFindBD(parent_cdev) if parent_bdev is None: logging.error("Can't find parent device") return False @@ -1161,7 +1199,7 @@ def GetMirrorStatus(disks): @rtype: disk @return: a list of (mirror_done, estimated_time) tuples, which - are the result of L{bdev.BlockDevice.CombinedSyncStatus} + are the result of L{bdev.BlockDev.CombinedSyncStatus} @raise errors.BlockDeviceError: if any of the disks cannot be found @@ -1175,17 +1213,13 @@ def GetMirrorStatus(disks): return stats -def _RecursiveFindBD(disk, allow_partial=False): +def _RecursiveFindBD(disk): """Check if a device is activated. If so, return informations about the real device. @type disk: L{objects.Disk} @param disk: the disk object we need to find - @type allow_partial: boolean - @param allow_partial: if true, don't abort the find if a - child of the device can't be found; this is intended - to be used when repairing mirrors @return: None if the device can't be found, otherwise the device instance @@ -1642,15 +1676,16 @@ def FinalizeExport(instance, snap_disks): instance.beparams[constants.BE_VCPUS]) config.set(constants.INISECT_INS, 'disk_template', instance.disk_template) - nic_count = 0 + nic_total = 0 for nic_count, nic in enumerate(instance.nics): + nic_total += 1 config.set(constants.INISECT_INS, 'nic%d_mac' % nic_count, '%s' % nic.mac) config.set(constants.INISECT_INS, 'nic%d_ip' % nic_count, '%s' % nic.ip) config.set(constants.INISECT_INS, 'nic%d_bridge' % nic_count, '%s' % nic.bridge) # TODO: redundant: on load can read nics until it doesn't exist - config.set(constants.INISECT_INS, 'nic_count' , '%d' % nic_count) + config.set(constants.INISECT_INS, 'nic_count' , '%d' % nic_total) disk_total = 0 for disk_count, disk in enumerate(snap_disks): @@ -1981,7 +2016,7 @@ def JobQueueUpdate(file_name, content): def JobQueueRename(old, new): """Renames a job queue file. - This is just a wrapper over L{os.rename} with proper checking. + This is just a wrapper over os.rename with proper checking. @type old: str @param old: the old (actual) file name @@ -1994,7 +2029,7 @@ def JobQueueRename(old, new): if not (_IsJobQueueFile(old) and _IsJobQueueFile(new)): return False - os.rename(old, new) + utils.RenameFile(old, new, mkdir=True) return True @@ -2305,7 +2340,7 @@ class DevCacheManager(object): node nor not @type iv_name: str @param iv_name: the instance-visible name of the - device, as in L{objects.Disk.iv_name} + device, as in objects.Disk.iv_name @rtype: None