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
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