def _extract_availability_zone(self, availability_zone, snapshot,
                                   source_volume, group):
        """Extracts and returns a validated availability zone.

        This function will extract the availability zone (if not provided) from
        the snapshot or source_volume and then performs a set of validation
        checks on the provided or extracted availability zone and then returns
        the validated availability zone.
        """

        refresh_az = False
        # If the volume will be created in a group, it should be placed in
        # in same availability zone as the group.
        if group:
            try:
                availability_zone = group['availability_zone']
            except (TypeError, KeyError):
                pass

        # Try to extract the availability zone from the corresponding snapshot
        # or source volume if either is valid so that we can be in the same
        # availability zone as the source.
        if availability_zone is None:
            if snapshot:
                try:
                    availability_zone = snapshot['volume']['availability_zone']
                except (TypeError, KeyError):
                    pass
            if source_volume and availability_zone is None:
                try:
                    availability_zone = source_volume['availability_zone']
                except (TypeError, KeyError):
                    pass

        if availability_zone is None:
            if CONF.default_availability_zone:
                availability_zone = CONF.default_availability_zone
            else:
                # For backwards compatibility use the storage_availability_zone
                availability_zone = CONF.storage_availability_zone

        if availability_zone not in self.availability_zones:
            refresh_az = True
            if CONF.allow_availability_zone_fallback:
                original_az = availability_zone
                availability_zone = (
                    CONF.default_availability_zone or
                    CONF.storage_availability_zone)
                LOG.warning("Availability zone '%(s_az)s' "
                            "not found, falling back to "
                            "'%(s_fallback_az)s'.",
                            {'s_az': original_az,
                             's_fallback_az': availability_zone})
            else:
                raise exception.InvalidAvailabilityZone(az=availability_zone)

        # If the configuration only allows cloning to the same availability
        # zone then we need to enforce that.
        if CONF.cloned_volume_same_az:
            snap_az = None
            try:
                snap_az = snapshot['volume']['availability_zone']
            except (TypeError, KeyError):
                pass
            if snap_az and snap_az != availability_zone:
                msg = _("Volume must be in the same "
                        "availability zone as the snapshot")
                raise exception.InvalidInput(reason=msg)
            source_vol_az = None
            try:
                source_vol_az = source_volume['availability_zone']
            except (TypeError, KeyError):
                pass
            if source_vol_az and source_vol_az != availability_zone:
                msg = _("Volume must be in the same "
                        "availability zone as the source volume")
                raise exception.InvalidInput(reason=msg)

        return availability_zone, refresh_az
예제 #2
0
    def _extract_availability_zones(
        self,
        availability_zone: Optional[str],
        snapshot,
        source_volume,
        group: Optional[dict],
        volume_type: Optional[dict[str,
                                   Any]] = None) -> tuple[list[str], bool]:
        """Extracts and returns a validated availability zone list.

        This function will extract the availability zone (if not provided) from
        the snapshot or source_volume and then performs a set of validation
        checks on the provided or extracted availability zone and then returns
        the validated availability zone.
        """
        refresh_az = False
        type_azs = volume_utils.extract_availability_zones_from_volume_type(
            volume_type)
        type_az_configured = type_azs is not None
        if type_az_configured:
            assert type_azs is not None
            safe_azs = list(
                set(type_azs).intersection(self.availability_zones))
            if not safe_azs:
                raise exception.InvalidTypeAvailabilityZones(az=type_azs)
        else:
            safe_azs = self.availability_zones

        # If the volume will be created in a group, it should be placed in
        # in same availability zone as the group.
        if group:
            try:
                availability_zone = group['availability_zone']
            except (TypeError, KeyError):
                pass

        # Try to extract the availability zone from the corresponding snapshot
        # or source volume if either is valid so that we can be in the same
        # availability zone as the source.
        if availability_zone is None:
            if snapshot:
                try:
                    availability_zone = snapshot['volume']['availability_zone']
                except (TypeError, KeyError):
                    pass
            if source_volume:
                try:
                    availability_zone = source_volume['availability_zone']
                except (TypeError, KeyError):
                    pass

        if availability_zone is None and not type_az_configured:
            if CONF.default_availability_zone:
                availability_zone = CONF.default_availability_zone
            else:
                # For backwards compatibility use the storage_availability_zone
                availability_zone = CONF.storage_availability_zone

        if availability_zone and availability_zone not in safe_azs:
            refresh_az = True
            if CONF.allow_availability_zone_fallback:
                original_az = availability_zone
                availability_zone = (CONF.default_availability_zone
                                     or CONF.storage_availability_zone)
                LOG.warning(
                    "Availability zone '%(s_az)s' "
                    "not found, falling back to "
                    "'%(s_fallback_az)s'.", {
                        's_az': original_az,
                        's_fallback_az': availability_zone
                    })
            else:
                raise exception.InvalidAvailabilityZone(az=availability_zone)

        # If the configuration only allows cloning to the same availability
        # zone then we need to enforce that.
        if availability_zone and CONF.cloned_volume_same_az:
            snap_az = None
            try:
                snap_az = snapshot['volume']['availability_zone']
            except (TypeError, KeyError):
                pass
            if snap_az and snap_az != availability_zone:
                msg = _("Volume must be in the same "
                        "availability zone as the snapshot")
                raise exception.InvalidInput(reason=msg)
            source_vol_az = None
            try:
                source_vol_az = source_volume['availability_zone']
            except (TypeError, KeyError):
                pass
            if source_vol_az and source_vol_az != availability_zone:
                msg = _("Volume must be in the same "
                        "availability zone as the source volume")
                raise exception.InvalidInput(reason=msg)

        if availability_zone:
            return [availability_zone], refresh_az
        else:
            return safe_azs, refresh_az