Exemplo n.º 1
0
def get_valid_required_extra_specs(extra_specs):
    """Returns required extra specs from dict.

    Returns None if extra specs are not valid, or if
    some required extras specs is missed.
    """
    extra_specs = extra_specs or {}

    missed_extra_specs = set(get_required_extra_specs()) - set(extra_specs)

    if missed_extra_specs:
        specs = ",".join(missed_extra_specs)
        msg = _("Required extra specs '%s' not specified.") % specs
        raise exception.InvalidExtraSpec(reason=msg)

    required_extra_specs = {}

    for k in get_required_extra_specs():
        value = extra_specs.get(k, '')
        if not is_valid_required_extra_spec(k, value):
            msg = _("Value of required extra_spec %s is not valid") % k
            raise exception.InvalidExtraSpec(reason=msg)

        required_extra_specs[k] = value

    return required_extra_specs
Exemplo n.º 2
0
def get_valid_optional_extra_specs(extra_specs):
    """Validates and returns optional/standard extra specs from dict.

    Raises InvalidExtraSpec if extra specs are not valid.
    """

    extra_specs = extra_specs or {}
    present_optional_extra_spec_keys = set(extra_specs).intersection(
        set(get_optional_extra_specs()))

    optional_extra_specs = {}

    for key in present_optional_extra_spec_keys:
        value = extra_specs.get(key, '')
        if not is_valid_optional_extra_spec(key, value):
            msg = _("Value of optional extra_spec %s is not valid.") % key
            raise exception.InvalidExtraSpec(reason=msg)

        optional_extra_specs[key] = value

    return optional_extra_specs
Exemplo n.º 3
0
def parse_boolean_extra_spec(extra_spec_key, extra_spec_value):
    """Parse extra spec values of the form '<is> True' or '<is> False'

    This method returns the boolean value of an extra spec value.  If
    the value does not conform to the standard boolean pattern, it raises
    an InvalidExtraSpec exception.
    """
    if not isinstance(extra_spec_value, six.string_types):
        extra_spec_value = six.text_type(extra_spec_value)

    match = re.match(r'^<is>\s*(?P<value>True|False)$',
                     extra_spec_value.strip(),
                     re.IGNORECASE)
    if match:
        extra_spec_value = match.group('value')
    try:
        return strutils.bool_from_string(extra_spec_value, strict=True)
    except ValueError:
        msg = (_('Invalid boolean extra spec %(key)s : %(value)s') %
               {'key': extra_spec_key, 'value': extra_spec_value})
        raise exception.InvalidExtraSpec(reason=msg)
Exemplo n.º 4
0
    def manage_existing(self, share, driver_options):
        """Manages a share that exists on backend."""
        if share['share_proto'].lower() == 'nfs':
            # 10.0.0.1:/share/example
            LOG.info(
                "Share %(shr_path)s will be managed with ID "
                "%(shr_id)s.", {
                    'shr_path': share['export_locations'][0]['path'],
                    'shr_id': share['id']
                })

            old_path_info = share['export_locations'][0]['path'].split(
                ':/share/')

            if len(old_path_info) == 2:
                ip = old_path_info[0]
                share_name = old_path_info[1]
            else:
                msg = _("Incorrect path. It should have the following format: "
                        "IP:/share/share_name.")
                raise exception.ShareBackendException(msg=msg)
        else:
            msg = _('Invalid NAS protocol: %s') % share['share_proto']
            raise exception.InvalidInput(reason=msg)

        if ip != self.configuration.qnap_share_ip:
            msg = _("The NAS IP %(ip)s is not configured.") % {'ip': ip}
            raise exception.ShareBackendException(msg=msg)

        existing_share = self.api_executor.get_share_info(
            self.configuration.qnap_poolname, vol_label=share_name)
        if existing_share is None:
            msg = _("The share %s trying to be managed was not found on "
                    "backend.") % share['id']
            raise exception.ManageInvalidShare(reason=msg)

        extra_specs = share_types.get_extra_specs_from_share(share)
        qnap_thin_provision = share_types.parse_boolean_extra_spec(
            'thin_provisioning',
            extra_specs.get("thin_provisioning")
            or extra_specs.get('capabilities:thin_provisioning') or 'true')
        qnap_compression = share_types.parse_boolean_extra_spec(
            'compression',
            extra_specs.get("compression")
            or extra_specs.get('capabilities:compression') or 'true')
        qnap_deduplication = share_types.parse_boolean_extra_spec(
            'dedupe',
            extra_specs.get("dedupe") or extra_specs.get('capabilities:dedupe')
            or 'false')
        qnap_ssd_cache = share_types.parse_boolean_extra_spec(
            'qnap_ssd_cache',
            extra_specs.get("qnap_ssd_cache")
            or extra_specs.get("capabilities:qnap_ssd_cache") or 'false')
        LOG.debug(
            'qnap_thin_provision: %(qnap_thin_provision)s '
            'qnap_compression: %(qnap_compression)s '
            'qnap_deduplication: %(qnap_deduplication)s '
            'qnap_ssd_cache: %(qnap_ssd_cache)s', {
                'qnap_thin_provision': qnap_thin_provision,
                'qnap_compression': qnap_compression,
                'qnap_deduplication': qnap_deduplication,
                'qnap_ssd_cache': qnap_ssd_cache
            })
        if (qnap_deduplication and not qnap_thin_provision):
            msg = _("Dedupe cannot be enabled without thin_provisioning.")
            LOG.debug('Dedupe cannot be enabled without thin_provisioning.')
            raise exception.InvalidExtraSpec(reason=msg)

        vol_no = existing_share.find('vol_no').text
        vol = self.api_executor.get_specific_volinfo(vol_no)
        vol_size_gb = math.ceil(float(vol.find('size').text) / units.Gi)

        share_dict = {
            'sharename': share_name,
            'old_sharename': share_name,
            'thin_provision': qnap_thin_provision,
            'compression': qnap_compression,
            'deduplication': qnap_deduplication,
            'ssd_cache': qnap_ssd_cache,
            'share_proto': share['share_proto']
        }
        self.api_executor.edit_share(share_dict)

        _metadata = {}
        _metadata['volID'] = vol_no
        _metadata['volName'] = share_name
        _metadata['thin_provision'] = qnap_thin_provision
        _metadata['compression'] = qnap_compression
        _metadata['deduplication'] = qnap_deduplication
        _metadata['ssd_cache'] = qnap_ssd_cache
        self.private_storage.update(share['id'], _metadata)

        LOG.info(
            "Share %(shr_path)s was successfully managed with ID "
            "%(shr_id)s.", {
                'shr_path': share['export_locations'][0]['path'],
                'shr_id': share['id']
            })

        export_locations = self._get_location_path(
            share_name, share['share_proto'], self.configuration.qnap_share_ip,
            vol_no)

        return {'size': vol_size_gb, 'export_locations': export_locations}
Exemplo n.º 5
0
    def create_share(self, context, share, share_server=None):
        """Create a new share."""
        LOG.debug('share: %s', share.__dict__)
        extra_specs = share_types.get_extra_specs_from_share(share)
        LOG.debug('extra_specs: %s', extra_specs)
        qnap_thin_provision = share_types.parse_boolean_extra_spec(
            'thin_provisioning',
            extra_specs.get("thin_provisioning")
            or extra_specs.get('capabilities:thin_provisioning') or 'true')
        qnap_compression = share_types.parse_boolean_extra_spec(
            'compression',
            extra_specs.get("compression")
            or extra_specs.get('capabilities:compression') or 'true')
        qnap_deduplication = share_types.parse_boolean_extra_spec(
            'dedupe',
            extra_specs.get("dedupe") or extra_specs.get('capabilities:dedupe')
            or 'false')
        qnap_ssd_cache = share_types.parse_boolean_extra_spec(
            'qnap_ssd_cache',
            extra_specs.get("qnap_ssd_cache")
            or extra_specs.get("capabilities:qnap_ssd_cache") or 'false')
        LOG.debug(
            'qnap_thin_provision: %(qnap_thin_provision)s '
            'qnap_compression: %(qnap_compression)s '
            'qnap_deduplication: %(qnap_deduplication)s '
            'qnap_ssd_cache: %(qnap_ssd_cache)s', {
                'qnap_thin_provision': qnap_thin_provision,
                'qnap_compression': qnap_compression,
                'qnap_deduplication': qnap_deduplication,
                'qnap_ssd_cache': qnap_ssd_cache
            })

        share_proto = share['share_proto']

        # User could create two shares with the same name on horizon.
        # Therefore, we should not use displayname to create shares on NAS.
        create_share_name = self._gen_random_name("share")
        # If share name exists, need to change to another name.
        created_share = self.api_executor.get_share_info(
            self.configuration.qnap_poolname, vol_label=create_share_name)
        LOG.debug('created_share: %s', created_share)
        if created_share is not None:
            msg = (_("The share name %s is used by other share on NAS.") %
                   create_share_name)
            LOG.error(msg)
            raise exception.ShareBackendException(msg=msg)

        if (qnap_deduplication and not qnap_thin_provision):
            msg = _("Dedupe cannot be enabled without thin_provisioning.")
            LOG.debug('Dedupe cannot be enabled without thin_provisioning.')
            raise exception.InvalidExtraSpec(reason=msg)
        self.api_executor.create_share(share,
                                       self.configuration.qnap_poolname,
                                       create_share_name,
                                       share_proto,
                                       qnap_thin_provision=qnap_thin_provision,
                                       qnap_compression=qnap_compression,
                                       qnap_deduplication=qnap_deduplication,
                                       qnap_ssd_cache=qnap_ssd_cache)
        created_share = self._get_share_info(create_share_name)
        volID = created_share.find('vol_no').text
        # Use private_storage to record volume ID and Name created in the NAS.
        LOG.debug('volID: %(volID)s '
                  'volName: %(create_share_name)s', {
                      'volID': volID,
                      'create_share_name': create_share_name
                  })
        _metadata = {
            'volID': volID,
            'volName': create_share_name,
            'thin_provision': qnap_thin_provision,
            'compression': qnap_compression,
            'deduplication': qnap_deduplication,
            'ssd_cache': qnap_ssd_cache
        }
        self.private_storage.update(share['id'], _metadata)

        return self._get_location_path(create_share_name, share['share_proto'],
                                       self.configuration.qnap_share_ip, volID)