Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
regions.py831 linesDownload Raw Back to botocore
1# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License"). You4# may not use this file except in compliance with the License. A copy of5# the License is located at6#7# http://aws.amazon.com/apache2.0/8#9# or in the "license" file accompanying this file. This file is10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF11# ANY KIND, either express or implied. See the License for the specific12# language governing permissions and limitations under the License.13"""Resolves regions and endpoints.14 15This module implements endpoint resolution, including resolving endpoints for a16given service and region and resolving the available endpoints for a service17in a specific AWS partition.18"""19import copy20import logging21import re22from enum import Enum23 24from botocore import UNSIGNED, xform_name25from botocore.auth import AUTH_TYPE_MAPS, HAS_CRT26from botocore.crt import CRT_SUPPORTED_AUTH_TYPES27from botocore.endpoint_provider import EndpointProvider28from botocore.exceptions import (29    EndpointProviderError,30    EndpointVariantError,31    InvalidEndpointConfigurationError,32    InvalidHostLabelError,33    MissingDependencyException,34    NoRegionError,35    ParamValidationError,36    UnknownEndpointResolutionBuiltInName,37    UnknownRegionError,38    UnknownSignatureVersionError,39    UnsupportedS3AccesspointConfigurationError,40    UnsupportedS3ConfigurationError,41    UnsupportedS3ControlArnError,42    UnsupportedS3ControlConfigurationError,43)44from botocore.utils import ensure_boolean, instance_cache45 46LOG = logging.getLogger(__name__)47DEFAULT_URI_TEMPLATE = '{service}.{region}.{dnsSuffix}'  # noqa48DEFAULT_SERVICE_DATA = {'endpoints': {}}49 50 51class BaseEndpointResolver:52    """Resolves regions and endpoints. Must be subclassed."""53 54    def construct_endpoint(self, service_name, region_name=None):55        """Resolves an endpoint for a service and region combination.56 57        :type service_name: string58        :param service_name: Name of the service to resolve an endpoint for59            (e.g., s3)60 61        :type region_name: string62        :param region_name: Region/endpoint name to resolve (e.g., us-east-1)63            if no region is provided, the first found partition-wide endpoint64            will be used if available.65 66        :rtype: dict67        :return: Returns a dict containing the following keys:68            - partition: (string, required) Resolved partition name69            - endpointName: (string, required) Resolved endpoint name70            - hostname: (string, required) Hostname to use for this endpoint71            - sslCommonName: (string) sslCommonName to use for this endpoint.72            - credentialScope: (dict) Signature version 4 credential scope73              - region: (string) region name override when signing.74              - service: (string) service name override when signing.75            - signatureVersions: (list<string>) A list of possible signature76              versions, including s3, v4, v2, and s3v477            - protocols: (list<string>) A list of supported protocols78              (e.g., http, https)79            - ...: Other keys may be included as well based on the metadata80        """81        raise NotImplementedError82 83    def get_available_partitions(self):84        """Lists the partitions available to the endpoint resolver.85 86        :return: Returns a list of partition names (e.g., ["aws", "aws-cn"]).87        """88        raise NotImplementedError89 90    def get_available_endpoints(91        self, service_name, partition_name='aws', allow_non_regional=False92    ):93        """Lists the endpoint names of a particular partition.94 95        :type service_name: string96        :param service_name: Name of a service to list endpoint for (e.g., s3)97 98        :type partition_name: string99        :param partition_name: Name of the partition to limit endpoints to.100            (e.g., aws for the public AWS endpoints, aws-cn for AWS China101            endpoints, aws-us-gov for AWS GovCloud (US) Endpoints, etc.102 103        :type allow_non_regional: bool104        :param allow_non_regional: Set to True to include endpoints that are105             not regional endpoints (e.g., s3-external-1,106             fips-us-gov-west-1, etc).107        :return: Returns a list of endpoint names (e.g., ["us-east-1"]).108        """109        raise NotImplementedError110 111 112class EndpointResolver(BaseEndpointResolver):113    """Resolves endpoints based on partition endpoint metadata"""114 115    _UNSUPPORTED_DUALSTACK_PARTITIONS = ['aws-iso', 'aws-iso-b']116 117    def __init__(self, endpoint_data, uses_builtin_data=False):118        """119        :type endpoint_data: dict120        :param endpoint_data: A dict of partition data.121 122        :type uses_builtin_data: boolean123        :param uses_builtin_data: Whether the endpoint data originates in the124            package's data directory.125        """126        if 'partitions' not in endpoint_data:127            raise ValueError('Missing "partitions" in endpoint data')128        self._endpoint_data = endpoint_data129        self.uses_builtin_data = uses_builtin_data130 131    def get_service_endpoints_data(self, service_name, partition_name='aws'):132        for partition in self._endpoint_data['partitions']:133            if partition['partition'] != partition_name:134                continue135            services = partition['services']136            if service_name not in services:137                continue138            return services[service_name]['endpoints']139 140    def get_available_partitions(self):141        result = []142        for partition in self._endpoint_data['partitions']:143            result.append(partition['partition'])144        return result145 146    def get_available_endpoints(147        self,148        service_name,149        partition_name='aws',150        allow_non_regional=False,151        endpoint_variant_tags=None,152    ):153        result = []154        for partition in self._endpoint_data['partitions']:155            if partition['partition'] != partition_name:156                continue157            services = partition['services']158            if service_name not in services:159                continue160            service_endpoints = services[service_name]['endpoints']161            for endpoint_name in service_endpoints:162                is_regional_endpoint = endpoint_name in partition['regions']163                # Only regional endpoints can be modeled with variants164                if endpoint_variant_tags and is_regional_endpoint:165                    variant_data = self._retrieve_variant_data(166                        service_endpoints[endpoint_name], endpoint_variant_tags167                    )168                    if variant_data:169                        result.append(endpoint_name)170                elif allow_non_regional or is_regional_endpoint:171                    result.append(endpoint_name)172        return result173 174    def get_partition_dns_suffix(175        self, partition_name, endpoint_variant_tags=None176    ):177        for partition in self._endpoint_data['partitions']:178            if partition['partition'] == partition_name:179                if endpoint_variant_tags:180                    variant = self._retrieve_variant_data(181                        partition.get('defaults'), endpoint_variant_tags182                    )183                    if variant and 'dnsSuffix' in variant:184                        return variant['dnsSuffix']185                else:186                    return partition['dnsSuffix']187        return None188 189    def construct_endpoint(190        self,191        service_name,192        region_name=None,193        partition_name=None,194        use_dualstack_endpoint=False,195        use_fips_endpoint=False,196    ):197        if (198            service_name == 's3'199            and use_dualstack_endpoint200            and region_name is None201        ):202            region_name = 'us-east-1'203 204        if partition_name is not None:205            valid_partition = None206            for partition in self._endpoint_data['partitions']:207                if partition['partition'] == partition_name:208                    valid_partition = partition209 210            if valid_partition is not None:211                result = self._endpoint_for_partition(212                    valid_partition,213                    service_name,214                    region_name,215                    use_dualstack_endpoint,216                    use_fips_endpoint,217                    True,218                )219                return result220            return None221 222        # Iterate over each partition until a match is found.223        for partition in self._endpoint_data['partitions']:224            if use_dualstack_endpoint and (225                partition['partition']226                in self._UNSUPPORTED_DUALSTACK_PARTITIONS227            ):228                continue229            result = self._endpoint_for_partition(230                partition,231                service_name,232                region_name,233                use_dualstack_endpoint,234                use_fips_endpoint,235            )236            if result:237                return result238 239    def get_partition_for_region(self, region_name):240        for partition in self._endpoint_data['partitions']:241            if self._region_match(partition, region_name):242                return partition['partition']243        raise UnknownRegionError(244            region_name=region_name,245            error_msg='No partition found for provided region_name.',246        )247 248    def _endpoint_for_partition(249        self,250        partition,251        service_name,252        region_name,253        use_dualstack_endpoint,254        use_fips_endpoint,255        force_partition=False,256    ):257        partition_name = partition["partition"]258        if (259            use_dualstack_endpoint260            and partition_name in self._UNSUPPORTED_DUALSTACK_PARTITIONS261        ):262            error_msg = (263                "Dualstack endpoints are currently not supported"264                " for %s partition" % partition_name265            )266            raise EndpointVariantError(tags=['dualstack'], error_msg=error_msg)267 268        # Get the service from the partition, or an empty template.269        service_data = partition['services'].get(270            service_name, DEFAULT_SERVICE_DATA271        )272        # Use the partition endpoint if no region is supplied.273        if region_name is None:274            if 'partitionEndpoint' in service_data:275                region_name = service_data['partitionEndpoint']276            else:277                raise NoRegionError()278 279        resolve_kwargs = {280            'partition': partition,281            'service_name': service_name,282            'service_data': service_data,283            'endpoint_name': region_name,284            'use_dualstack_endpoint': use_dualstack_endpoint,285            'use_fips_endpoint': use_fips_endpoint,286        }287 288        # Attempt to resolve the exact region for this partition.289        if region_name in service_data['endpoints']:290            return self._resolve(**resolve_kwargs)291 292        # Check to see if the endpoint provided is valid for the partition.293        if self._region_match(partition, region_name) or force_partition:294            # Use the partition endpoint if set and not regionalized.295            partition_endpoint = service_data.get('partitionEndpoint')296            is_regionalized = service_data.get('isRegionalized', True)297            if partition_endpoint and not is_regionalized:298                LOG.debug(299                    'Using partition endpoint for %s, %s: %s',300                    service_name,301                    region_name,302                    partition_endpoint,303                )304                resolve_kwargs['endpoint_name'] = partition_endpoint305                return self._resolve(**resolve_kwargs)306            LOG.debug(307                'Creating a regex based endpoint for %s, %s',308                service_name,309                region_name,310            )311            return self._resolve(**resolve_kwargs)312 313    def _region_match(self, partition, region_name):314        if region_name in partition['regions']:315            return True316        if 'regionRegex' in partition:317            return re.compile(partition['regionRegex']).match(region_name)318        return False319 320    def _retrieve_variant_data(self, endpoint_data, tags):321        variants = endpoint_data.get('variants', [])322        for variant in variants:323            if set(variant['tags']) == set(tags):324                result = variant.copy()325                return result326 327    def _create_tag_list(self, use_dualstack_endpoint, use_fips_endpoint):328        tags = []329        if use_dualstack_endpoint:330            tags.append('dualstack')331        if use_fips_endpoint:332            tags.append('fips')333        return tags334 335    def _resolve_variant(336        self, tags, endpoint_data, service_defaults, partition_defaults337    ):338        result = {}339        for variants in [endpoint_data, service_defaults, partition_defaults]:340            variant = self._retrieve_variant_data(variants, tags)341            if variant:342                self._merge_keys(variant, result)343        return result344 345    def _resolve(346        self,347        partition,348        service_name,349        service_data,350        endpoint_name,351        use_dualstack_endpoint,352        use_fips_endpoint,353    ):354        endpoint_data = service_data.get('endpoints', {}).get(355            endpoint_name, {}356        )357 358        if endpoint_data.get('deprecated'):359            LOG.warning(360                'Client is configured with the deprecated endpoint: %s'361                % (endpoint_name)362            )363 364        service_defaults = service_data.get('defaults', {})365        partition_defaults = partition.get('defaults', {})366        tags = self._create_tag_list(use_dualstack_endpoint, use_fips_endpoint)367 368        if tags:369            result = self._resolve_variant(370                tags, endpoint_data, service_defaults, partition_defaults371            )372            if result == {}:373                error_msg = (374                    f"Endpoint does not exist for {service_name} "375                    f"in region {endpoint_name}"376                )377                raise EndpointVariantError(tags=tags, error_msg=error_msg)378            self._merge_keys(endpoint_data, result)379        else:380            result = endpoint_data381 382        # If dnsSuffix has not already been consumed from a variant definition383        if 'dnsSuffix' not in result:384            result['dnsSuffix'] = partition['dnsSuffix']385 386        result['partition'] = partition['partition']387        result['endpointName'] = endpoint_name388 389        # Merge in the service defaults then the partition defaults.390        self._merge_keys(service_defaults, result)391        self._merge_keys(partition_defaults, result)392 393        result['hostname'] = self._expand_template(394            partition,395            result['hostname'],396            service_name,397            endpoint_name,398            result['dnsSuffix'],399        )400        if 'sslCommonName' in result:401            result['sslCommonName'] = self._expand_template(402                partition,403                result['sslCommonName'],404                service_name,405                endpoint_name,406                result['dnsSuffix'],407            )408 409        return result410 411    def _merge_keys(self, from_data, result):412        for key in from_data:413            if key not in result:414                result[key] = from_data[key]415 416    def _expand_template(417        self, partition, template, service_name, endpoint_name, dnsSuffix418    ):419        return template.format(420            service=service_name, region=endpoint_name, dnsSuffix=dnsSuffix421        )422 423 424class EndpointResolverBuiltins(str, Enum):425    # The AWS Region configured for the SDK client (str)426    AWS_REGION = "AWS::Region"427    # Whether the UseFIPSEndpoint configuration option has been enabled for428    # the SDK client (bool)429    AWS_USE_FIPS = "AWS::UseFIPS"430    # Whether the UseDualStackEndpoint configuration option has been enabled431    # for the SDK client (bool)432    AWS_USE_DUALSTACK = "AWS::UseDualStack"433    # Whether the global endpoint should be used with STS, rather the the434    # regional endpoint for us-east-1 (bool)435    AWS_STS_USE_GLOBAL_ENDPOINT = "AWS::STS::UseGlobalEndpoint"436    # Whether the global endpoint should be used with S3, rather then the437    # regional endpoint for us-east-1 (bool)438    AWS_S3_USE_GLOBAL_ENDPOINT = "AWS::S3::UseGlobalEndpoint"439    # Whether S3 Transfer Acceleration has been requested (bool)440    AWS_S3_ACCELERATE = "AWS::S3::Accelerate"441    # Whether S3 Force Path Style has been enabled (bool)442    AWS_S3_FORCE_PATH_STYLE = "AWS::S3::ForcePathStyle"443    # Whether to use the ARN region or raise an error when ARN and client444    # region differ (for s3 service only, bool)445    AWS_S3_USE_ARN_REGION = "AWS::S3::UseArnRegion"446    # Whether to use the ARN region or raise an error when ARN and client447    # region differ (for s3-control service only, bool)448    AWS_S3CONTROL_USE_ARN_REGION = 'AWS::S3Control::UseArnRegion'449    # Whether multi-region access points (MRAP) should be disabled (bool)450    AWS_S3_DISABLE_MRAP = "AWS::S3::DisableMultiRegionAccessPoints"451    # Whether a custom endpoint has been configured (str)452    SDK_ENDPOINT = "SDK::Endpoint"453 454 455class EndpointRulesetResolver:456    """Resolves endpoints using a service's endpoint ruleset"""457 458    def __init__(459        self,460        endpoint_ruleset_data,461        partition_data,462        service_model,463        builtins,464        client_context,465        event_emitter,466        use_ssl=True,467        requested_auth_scheme=None,468    ):469        self._provider = EndpointProvider(470            ruleset_data=endpoint_ruleset_data,471            partition_data=partition_data,472        )473        self._param_definitions = self._provider.ruleset.parameters474        self._service_model = service_model475        self._builtins = builtins476        self._client_context = client_context477        self._event_emitter = event_emitter478        self._use_ssl = use_ssl479        self._requested_auth_scheme = requested_auth_scheme480        self._instance_cache = {}481 482    def construct_endpoint(483        self,484        operation_model,485        call_args,486        request_context,487    ):488        """Invokes the provider with params defined in the service's ruleset"""489        if call_args is None:490            call_args = {}491 492        if request_context is None:493            request_context = {}494 495        provider_params = self._get_provider_params(496            operation_model, call_args, request_context497        )498        LOG.debug(499            'Calling endpoint provider with parameters: %s' % provider_params500        )501        try:502            provider_result = self._provider.resolve_endpoint(503                **provider_params504            )505        except EndpointProviderError as ex:506            botocore_exception = self.ruleset_error_to_botocore_exception(507                ex, provider_params508            )509            if botocore_exception is None:510                raise511            else:512                raise botocore_exception from ex513        LOG.debug('Endpoint provider result: %s' % provider_result.url)514 515        # The endpoint provider does not support non-secure transport.516        if not self._use_ssl and provider_result.url.startswith('https://'):517            provider_result = provider_result._replace(518                url=f'http://{provider_result.url[8:]}'519            )520 521        # Multi-valued headers are not supported in botocore. Replace the list522        # of values returned for each header with just its first entry,523        # dropping any additionally entries.524        provider_result = provider_result._replace(525            headers={526                key: val[0] for key, val in provider_result.headers.items()527            }528        )529 530        return provider_result531 532    def _get_provider_params(533        self, operation_model, call_args, request_context534    ):535        """Resolve a value for each parameter defined in the service's ruleset536 537        The resolution order for parameter values is:538        1. Operation-specific static context values from the service definition539        2. Operation-specific dynamic context values from API parameters540        3. Client-specific context parameters541        4. Built-in values such as region, FIPS usage, ...542        """543        provider_params = {}544        # Builtin values can be customized for each operation by hooks545        # subscribing to the ``before-endpoint-resolution.*`` event.546        customized_builtins = self._get_customized_builtins(547            operation_model, call_args, request_context548        )549        for param_name, param_def in self._param_definitions.items():550            param_val = self._resolve_param_from_context(551                param_name=param_name,552                operation_model=operation_model,553                call_args=call_args,554            )555            if param_val is None and param_def.builtin is not None:556                param_val = self._resolve_param_as_builtin(557                    builtin_name=param_def.builtin,558                    builtins=customized_builtins,559                )560            if param_val is not None:561                provider_params[param_name] = param_val562 563        return provider_params564 565    def _resolve_param_from_context(566        self, param_name, operation_model, call_args567    ):568        static = self._resolve_param_as_static_context_param(569            param_name, operation_model570        )571        if static is not None:572            return static573        dynamic = self._resolve_param_as_dynamic_context_param(574            param_name, operation_model, call_args575        )576        if dynamic is not None:577            return dynamic578        return self._resolve_param_as_client_context_param(param_name)579 580    def _resolve_param_as_static_context_param(581        self, param_name, operation_model582    ):583        static_ctx_params = self._get_static_context_params(operation_model)584        return static_ctx_params.get(param_name)585 586    def _resolve_param_as_dynamic_context_param(587        self, param_name, operation_model, call_args588    ):589        dynamic_ctx_params = self._get_dynamic_context_params(operation_model)590        if param_name in dynamic_ctx_params:591            member_name = dynamic_ctx_params[param_name]592            return call_args.get(member_name)593 594    def _resolve_param_as_client_context_param(self, param_name):595        client_ctx_params = self._get_client_context_params()596        if param_name in client_ctx_params:597            client_ctx_varname = client_ctx_params[param_name]598            return self._client_context.get(client_ctx_varname)599 600    def _resolve_param_as_builtin(self, builtin_name, builtins):601        if builtin_name not in EndpointResolverBuiltins.__members__.values():602            raise UnknownEndpointResolutionBuiltInName(name=builtin_name)603        return builtins.get(builtin_name)604 605    @instance_cache606    def _get_static_context_params(self, operation_model):607        """Mapping of param names to static param value for an operation"""608        return {609            param.name: param.value610            for param in operation_model.static_context_parameters611        }612 613    @instance_cache614    def _get_dynamic_context_params(self, operation_model):615        """Mapping of param names to member names for an operation"""616        return {617            param.name: param.member_name618            for param in operation_model.context_parameters619        }620 621    @instance_cache622    def _get_client_context_params(self):623        """Mapping of param names to client configuration variable"""624        return {625            param.name: xform_name(param.name)626            for param in self._service_model.client_context_parameters627        }628 629    def _get_customized_builtins(630        self, operation_model, call_args, request_context631    ):632        service_id = self._service_model.service_id.hyphenize()633        customized_builtins = copy.copy(self._builtins)634        # Handlers are expected to modify the builtins dict in place.635        self._event_emitter.emit(636            'before-endpoint-resolution.%s' % service_id,637            builtins=customized_builtins,638            model=operation_model,639            params=call_args,640            context=request_context,641        )642        return customized_builtins643 644    def auth_schemes_to_signing_ctx(self, auth_schemes):645        """Convert an Endpoint's authSchemes property to a signing_context dict646 647        :type auth_schemes: list648        :param auth_schemes: A list of dictionaries taken from the649            ``authSchemes`` property of an Endpoint object returned by650            ``EndpointProvider``.651 652        :rtype: str, dict653        :return: Tuple of auth type string (to be used in654            ``request_context['auth_type']``) and signing context dict (for use655            in ``request_context['signing']``).656        """657        if not isinstance(auth_schemes, list) or len(auth_schemes) == 0:658            raise TypeError("auth_schemes must be a non-empty list.")659 660        LOG.debug(661            'Selecting from endpoint provider\'s list of auth schemes: %s. '662            'User selected auth scheme is: "%s"',663            ', '.join([f'"{s.get("name")}"' for s in auth_schemes]),664            self._requested_auth_scheme,665        )666 667        if self._requested_auth_scheme == UNSIGNED:668            return 'none', {}669 670        auth_schemes = [671            {**scheme, 'name': self._strip_sig_prefix(scheme['name'])}672            for scheme in auth_schemes673        ]674        if self._requested_auth_scheme is not None:675            try:676                # Use the first scheme that matches the requested scheme,677                # after accounting for naming differences between botocore and678                # endpoint rulesets. Keep the requested name.679                name, scheme = next(680                    (self._requested_auth_scheme, s)681                    for s in auth_schemes682                    if self._does_botocore_authname_match_ruleset_authname(683                        self._requested_auth_scheme, s['name']684                    )685                )686            except StopIteration:687                # For legacy signers, no match will be found. Do not raise an688                # exception, instead default to the logic in botocore689                # customizations.690                return None, {}691        else:692            try:693                name, scheme = next(694                    (s['name'], s)695                    for s in auth_schemes696                    if s['name'] in AUTH_TYPE_MAPS697                )698            except StopIteration:699                # If no auth scheme was specifically requested and an700                # authSchemes list is present in the Endpoint object but none701                # of the entries are supported, raise an exception.702                fixable_with_crt = False703                auth_type_options = [s['name'] for s in auth_schemes]704                if not HAS_CRT:705                    fixable_with_crt = any(706                        scheme in CRT_SUPPORTED_AUTH_TYPES707                        for scheme in auth_type_options708                    )709 710                if fixable_with_crt:711                    raise MissingDependencyException(712                        msg='This operation requires an additional dependency.'713                        ' Use pip install botocore[crt] before proceeding.'714                    )715                else:716                    raise UnknownSignatureVersionError(717                        signature_version=', '.join(auth_type_options)718                    )719 720        signing_context = {}721        if 'signingRegion' in scheme:722            signing_context['region'] = scheme['signingRegion']723        elif 'signingRegionSet' in scheme:724            if len(scheme['signingRegionSet']) > 0:725                signing_context['region'] = scheme['signingRegionSet'][0]726        if 'signingName' in scheme:727            signing_context.update(signing_name=scheme['signingName'])728        if 'disableDoubleEncoding' in scheme:729            signing_context['disableDoubleEncoding'] = ensure_boolean(730                scheme['disableDoubleEncoding']731            )732 733        LOG.debug(734            'Selected auth type "%s" as "%s" with signing context params: %s',735            scheme['name'],  # original name without "sig"736            name,  # chosen name can differ when `signature_version` is set737            signing_context,738        )739        return name, signing_context740 741    def _strip_sig_prefix(self, auth_name):742        """Normalize auth type names by removing any "sig" prefix"""743        return auth_name[3:] if auth_name.startswith('sig') else auth_name744 745    def _does_botocore_authname_match_ruleset_authname(self, botoname, rsname):746        """747        Whether a valid string provided as signature_version parameter for748        client construction refers to the same auth methods as a string749        returned by the endpoint ruleset provider. This accounts for:750 751        * The ruleset prefixes auth names with "sig"752        * The s3 and s3control rulesets don't distinguish between v4[a] and753          s3v4[a] signers754        * The v2, v3, and HMAC v1 based signers (s3, s3-*) are botocore legacy755          features and do not exist in the rulesets756        * Only characters up to the first dash are considered757 758        Example matches:759        * v4, sigv4760        * v4, v4761        * s3v4, sigv4762        * s3v7, sigv7 (hypothetical example)763        * s3v4a, sigv4a764        * s3v4-query, sigv4765 766        Example mismatches:767        * v4a, sigv4768        * s3, sigv4769        * s3-presign-post, sigv4770        """771        rsname = self._strip_sig_prefix(rsname)772        botoname = botoname.split('-')[0]773        if botoname != 's3' and botoname.startswith('s3'):774            botoname = botoname[2:]775        return rsname == botoname776 777    def ruleset_error_to_botocore_exception(self, ruleset_exception, params):778        """Attempts to translate ruleset errors to pre-existing botocore779        exception types by string matching exception strings.780        """781        msg = ruleset_exception.kwargs.get('msg')782        if msg is None:783            return784 785        if msg.startswith('Invalid region in ARN: '):786            # Example message:787            # "Invalid region in ARN: `us-we$t-2` (invalid DNS name)"788            try:789                label = msg.split('`')[1]790            except IndexError:791                label = msg792            return InvalidHostLabelError(label=label)793 794        service_name = self._service_model.service_name795        if service_name == 's3':796            if (797                msg == 'S3 Object Lambda does not support S3 Accelerate'798                or msg == 'Accelerate cannot be used with FIPS'799            ):800                return UnsupportedS3ConfigurationError(msg=msg)801            if (802                msg.startswith('S3 Outposts does not support')803                or msg.startswith('S3 MRAP does not support')804                or msg.startswith('S3 Object Lambda does not support')805                or msg.startswith('Access Points do not support')806                or msg.startswith('Invalid configuration:')807                or msg.startswith('Client was configured for partition')808            ):809                return UnsupportedS3AccesspointConfigurationError(msg=msg)810            if msg.lower().startswith('invalid arn:'):811                return ParamValidationError(report=msg)812        if service_name == 's3control':813            if msg.startswith('Invalid ARN:'):814                arn = params.get('Bucket')815                return UnsupportedS3ControlArnError(arn=arn, msg=msg)816            if msg.startswith('Invalid configuration:') or msg.startswith(817                'Client was configured for partition'818            ):819                return UnsupportedS3ControlConfigurationError(msg=msg)820            if msg == "AccountId is required but not set":821                return ParamValidationError(report=msg)822        if service_name == 'events':823            if msg.startswith(824                'Invalid Configuration: FIPS is not supported with '825                'EventBridge multi-region endpoints.'826            ):827                return InvalidEndpointConfigurationError(msg=msg)828            if msg == 'EndpointId must be a valid host label.':829                return InvalidEndpointConfigurationError(msg=msg)830        return None831 
codekingpro/portable-devtools · Team Ai