def valid_disk(ceph_iscsi_config, logger, **kwargs): """ determine whether the given image info is valid for a disk operation :param ceph_iscsi_config: Config object :param logger: logger object :param image_id: (str) <pool>.<image> format :return: (str) either 'ok' or an error description """ # create can also pass optional controls dict mode_vars = { "create": ['pool', 'image', 'size', 'count'], "resize": ['pool', 'image', 'size'], "reconfigure": ['pool', 'image', 'controls'], "delete": ['pool', 'image'] } if 'mode' in kwargs.keys(): mode = kwargs['mode'] else: mode = None backstore = kwargs['backstore'] if backstore not in LUN.BACKSTORES: return "Invalid '{}' backstore - Supported backstores: " \ "{}".format(backstore, ','.join(LUN.BACKSTORES)) if mode in mode_vars: if not all(x in kwargs for x in mode_vars[mode]): return ("{} request must contain the following " "variables: ".format(mode, ','.join(mode_vars[mode]))) else: return "disk operation mode '{}' is invalid".format(mode) config = ceph_iscsi_config.config disk_key = "{}.{}".format(kwargs['pool'], kwargs['image']) if mode in ['create', 'resize']: if kwargs['pool'] not in get_pools(): return "pool name is invalid" if mode == 'create': if kwargs['size'] and not valid_size(kwargs['size']): return "Size is invalid" if len(config['disks']) >= 256: return "Disk limit of 256 reached." disk_regex = re.compile(r"^[a-zA-Z0-9\-_]+$") if not disk_regex.search(kwargs['pool']): return "Invalid pool name (use alphanumeric, '_', or '-' characters)" if not disk_regex.search(kwargs['image']): return "Invalid image name (use alphanumeric, '_', or '-' characters)" if kwargs['count'].isdigit(): if not 1 <= int(kwargs['count']) <= 10: return "invalid count specified, must be an integer (1-10)" else: return "invalid count specified, must be an integer (1-10)" if kwargs['count'] == '1': new_disks = {disk_key} else: limit = int(kwargs['count']) + 1 new_disks = set( ['{}{}'.format(disk_key, ctr) for ctr in range(1, limit)]) if any(new_disk in config['disks'] for new_disk in new_disks): return ("at least one rbd image(s) with that name/prefix is " "already defined") if mode in ["resize", "delete", "reconfigure"]: # disk must exist in the config if disk_key not in config['disks']: return ("rbd {}/{} is not defined to the " "configuration".format(kwargs['pool'], kwargs['image'])) if mode == 'resize': if not valid_size(kwargs['size']): return "Size is invalid" size = kwargs['size'].upper() current_size = get_rbd_size(kwargs['pool'], kwargs['image']) if convert_2_bytes(size) <= current_size: return ("resize value must be larger than the " "current size ({}/{})".format(human_size(current_size), current_size)) if mode in ['create', 'reconfigure']: try: settings.Settings.normalize_controls(kwargs['controls'], LUN.SETTINGS[backstore]) except ValueError as err: return (err) if mode == 'delete': # disk must *not* be allocated to a client in the config mapped_list = [] allocation_list = [] for target_iqn, target in config['targets'].items(): if disk_key in target['disks']: mapped_list.append(target_iqn) for client_iqn in target['clients']: client_metadata = target['clients'][client_iqn] if disk_key in client_metadata['luns']: allocation_list.append(client_iqn) if allocation_list: return ("Unable to delete {}. Allocated " "to: {}".format(disk_key, ','.join(allocation_list))) if mapped_list: return ("Unable to delete {}. Mapped " "to: {}".format(disk_key, ','.join(mapped_list))) return 'ok'
def valid_disk(ceph_iscsi_config, logger, **kwargs): """ determine whether the given image info is valid for a disk operation :param ceph_iscsi_config: Config object :param logger: logger object :param image_id: (str) <pool>.<image> format :return: (str) either 'ok' or an error description """ # create can also pass optional controls dict mode_vars = { "create": ['pool', 'image', 'size', 'count'], "resize": ['pool', 'image', 'size'], "reconfigure": ['pool', 'image', 'controls'], "delete": ['pool', 'image'] } if 'mode' in kwargs.keys(): mode = kwargs['mode'] else: mode = None if mode in mode_vars: if not all(x in kwargs for x in mode_vars[mode]): return ("{} request must contain the following " "variables: ".format(mode, ','.join(mode_vars[mode]))) else: return "disk operation mode '{}' is invalid".format(mode) config = ceph_iscsi_config.config disk_key = "{}.{}".format(kwargs['pool'], kwargs['image']) if mode in ['create', 'resize']: if not valid_size(kwargs['size']): return "Size is invalid" elif kwargs['pool'] not in get_pools(): return "pool name is invalid" if mode == 'create': if len(config['disks']) >= 256: return "Disk limit of 256 reached." disk_regex = re.compile(r"^[a-zA-Z0-9\-_]+$") if not disk_regex.search(kwargs['pool']): return "Invalid pool name (use alphanumeric, '_', or '-' characters)" if not disk_regex.search(kwargs['image']): return "Invalid image name (use alphanumeric, '_', or '-' characters)" if kwargs['count'].isdigit(): if not 1 <= int(kwargs['count']) <= 10: return "invalid count specified, must be an integer (1-10)" else: return "invalid count specified, must be an integer (1-10)" if kwargs['count'] == '1': new_disks = {disk_key} else: limit = int(kwargs['count']) + 1 new_disks = set( ['{}{}'.format(disk_key, ctr) for ctr in range(1, limit)]) if any(new_disk in config['disks'] for new_disk in new_disks): return ("at least one rbd image(s) with that name/prefix is " "already defined") gateways_defined = len([ key for key in config['gateways'] if isinstance(config['gateways'][key], dict) ]) if gateways_defined < settings.config.minimum_gateways: return ("disks can not be added until at least {} gateways " "are defined".format(settings.config.minimum_gateways)) if mode in ["resize", "delete", "reconfigure"]: # disk must exist in the config if disk_key not in config['disks']: return ("rbd {}/{} is not defined to the " "configuration".format(kwargs['pool'], kwargs['image'])) if mode == 'resize': size = kwargs['size'].upper() current_size = get_rbd_size(kwargs['pool'], kwargs['image']) if convert_2_bytes(size) <= current_size: return ("resize value must be larger than the " "current size ({}/{})".format(human_size(current_size), current_size)) if mode in ['create', 'reconfigure']: try: settings.Settings.normalize_controls(kwargs['controls'], LUN.SETTINGS) except ValueError as err: return (err) if mode == 'delete': # disk must *not* be allocated to a client in the config allocation_list = [] for client_iqn in config['clients']: client_metadata = config['clients'][client_iqn] if disk_key in client_metadata['luns']: allocation_list.append(client_iqn) if allocation_list: return ("Unable to delete {}. Allocated " "to: {}".format(disk_key, ','.join(allocation_list))) try: with rados.Rados(conffile=settings.config.cephconf) as cluster: with cluster.open_ioctx(kwargs['pool']) as ioctx: with rbd.Image(ioctx, kwargs['image']) as rbd_image: if list(rbd_image.list_snaps()): return ("Unable to delete {}. Snapshots must " "be removed first.".format(disk_key)) except rbd.ImageNotFound: pass except Exception as e: return "Unable to query {}: {}".format(disk_key, e) return 'ok'