Beispiel #1
0
    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'
Beispiel #2
0
    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'