Spaces:
Paused
Paused
| # Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"). You | |
| # may not use this file except in compliance with the License. A copy of | |
| # the License is located at | |
| # | |
| # https://aws.amazon.com/apache2.0/ | |
| # | |
| # or in the "license" file accompanying this file. This file is | |
| # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF | |
| # ANY KIND, either express or implied. See the License for the specific | |
| # language governing permissions and limitations under the License. | |
| import copy | |
| import os | |
| import botocore.session | |
| from botocore.client import Config | |
| from botocore.exceptions import DataNotFoundError, UnknownServiceError | |
| import boto3 | |
| import boto3.utils | |
| from boto3.exceptions import ResourceNotExistsError, UnknownAPIVersionError | |
| from .resources.factory import ResourceFactory | |
| class Session: | |
| """ | |
| A session stores configuration state and allows you to create service | |
| clients and resources. | |
| :type aws_access_key_id: string | |
| :param aws_access_key_id: AWS access key ID | |
| :type aws_secret_access_key: string | |
| :param aws_secret_access_key: AWS secret access key | |
| :type aws_session_token: string | |
| :param aws_session_token: AWS temporary session token | |
| :type region_name: string | |
| :param region_name: Default region when creating new connections | |
| :type botocore_session: botocore.session.Session | |
| :param botocore_session: Use this Botocore session instead of creating | |
| a new default one. | |
| :type profile_name: string | |
| :param profile_name: The name of a profile to use. If not given, then | |
| the default profile is used. | |
| """ | |
| def __init__( | |
| self, | |
| aws_access_key_id=None, | |
| aws_secret_access_key=None, | |
| aws_session_token=None, | |
| region_name=None, | |
| botocore_session=None, | |
| profile_name=None, | |
| ): | |
| if botocore_session is not None: | |
| self._session = botocore_session | |
| else: | |
| # Create a new default session | |
| self._session = botocore.session.get_session() | |
| # Setup custom user-agent string if it isn't already customized | |
| if self._session.user_agent_name == 'Botocore': | |
| botocore_info = 'Botocore/{}'.format( | |
| self._session.user_agent_version | |
| ) | |
| if self._session.user_agent_extra: | |
| self._session.user_agent_extra += ' ' + botocore_info | |
| else: | |
| self._session.user_agent_extra = botocore_info | |
| self._session.user_agent_name = 'Boto3' | |
| self._session.user_agent_version = boto3.__version__ | |
| if profile_name is not None: | |
| self._session.set_config_variable('profile', profile_name) | |
| if aws_access_key_id or aws_secret_access_key or aws_session_token: | |
| self._session.set_credentials( | |
| aws_access_key_id, aws_secret_access_key, aws_session_token | |
| ) | |
| if region_name is not None: | |
| self._session.set_config_variable('region', region_name) | |
| self.resource_factory = ResourceFactory( | |
| self._session.get_component('event_emitter') | |
| ) | |
| self._setup_loader() | |
| self._register_default_handlers() | |
| def __repr__(self): | |
| return '{}(region_name={})'.format( | |
| self.__class__.__name__, | |
| repr(self._session.get_config_variable('region')), | |
| ) | |
| def profile_name(self): | |
| """ | |
| The **read-only** profile name. | |
| """ | |
| return self._session.profile or 'default' | |
| def region_name(self): | |
| """ | |
| The **read-only** region name. | |
| """ | |
| return self._session.get_config_variable('region') | |
| def events(self): | |
| """ | |
| The event emitter for a session | |
| """ | |
| return self._session.get_component('event_emitter') | |
| def available_profiles(self): | |
| """ | |
| The profiles available to the session credentials | |
| """ | |
| return self._session.available_profiles | |
| def _setup_loader(self): | |
| """ | |
| Setup loader paths so that we can load resources. | |
| """ | |
| self._loader = self._session.get_component('data_loader') | |
| self._loader.search_paths.append( | |
| os.path.join(os.path.dirname(__file__), 'data') | |
| ) | |
| def get_available_services(self): | |
| """ | |
| Get a list of available services that can be loaded as low-level | |
| clients via :py:meth:`Session.client`. | |
| :rtype: list | |
| :return: List of service names | |
| """ | |
| return self._session.get_available_services() | |
| def get_available_resources(self): | |
| """ | |
| Get a list of available services that can be loaded as resource | |
| clients via :py:meth:`Session.resource`. | |
| :rtype: list | |
| :return: List of service names | |
| """ | |
| return self._loader.list_available_services(type_name='resources-1') | |
| def get_available_partitions(self): | |
| """Lists the available partitions | |
| :rtype: list | |
| :return: Returns a list of partition names (e.g., ["aws", "aws-cn"]) | |
| """ | |
| return self._session.get_available_partitions() | |
| def get_available_regions( | |
| self, service_name, partition_name='aws', allow_non_regional=False | |
| ): | |
| """Lists the region and endpoint names of a particular partition. | |
| The list of regions returned by this method are regions that are | |
| explicitly known by the client to exist and is not comprehensive. A | |
| region not returned in this list may still be available for the | |
| provided service. | |
| :type service_name: string | |
| :param service_name: Name of a service to list endpoint for (e.g., s3). | |
| :type partition_name: string | |
| :param partition_name: Name of the partition to limit endpoints to. | |
| (e.g., aws for the public AWS endpoints, aws-cn for AWS China | |
| endpoints, aws-us-gov for AWS GovCloud (US) Endpoints, etc.) | |
| :type allow_non_regional: bool | |
| :param allow_non_regional: Set to True to include endpoints that are | |
| not regional endpoints (e.g., s3-external-1, | |
| fips-us-gov-west-1, etc). | |
| :return: Returns a list of endpoint names (e.g., ["us-east-1"]). | |
| """ | |
| return self._session.get_available_regions( | |
| service_name=service_name, | |
| partition_name=partition_name, | |
| allow_non_regional=allow_non_regional, | |
| ) | |
| def get_credentials(self): | |
| """ | |
| Return the :class:`botocore.credentials.Credentials` object | |
| associated with this session. If the credentials have not | |
| yet been loaded, this will attempt to load them. If they | |
| have already been loaded, this will return the cached | |
| credentials. | |
| """ | |
| return self._session.get_credentials() | |
| def get_partition_for_region(self, region_name): | |
| """Lists the partition name of a particular region. | |
| :type region_name: string | |
| :param region_name: Name of the region to list partition for (e.g., | |
| us-east-1). | |
| :rtype: string | |
| :return: Returns the respective partition name (e.g., aws). | |
| """ | |
| return self._session.get_partition_for_region(region_name) | |
| def client( | |
| self, | |
| service_name, | |
| region_name=None, | |
| api_version=None, | |
| use_ssl=True, | |
| verify=None, | |
| endpoint_url=None, | |
| aws_access_key_id=None, | |
| aws_secret_access_key=None, | |
| aws_session_token=None, | |
| config=None, | |
| ): | |
| """ | |
| Create a low-level service client by name. | |
| :type service_name: string | |
| :param service_name: The name of a service, e.g. 's3' or 'ec2'. You | |
| can get a list of available services via | |
| :py:meth:`get_available_services`. | |
| :type region_name: string | |
| :param region_name: The name of the region associated with the client. | |
| A client is associated with a single region. | |
| :type api_version: string | |
| :param api_version: The API version to use. By default, botocore will | |
| use the latest API version when creating a client. You only need | |
| to specify this parameter if you want to use a previous API version | |
| of the client. | |
| :type use_ssl: boolean | |
| :param use_ssl: Whether or not to use SSL. By default, SSL is used. | |
| Note that not all services support non-ssl connections. | |
| :type verify: boolean/string | |
| :param verify: Whether or not to verify SSL certificates. By default | |
| SSL certificates are verified. You can provide the following | |
| values: | |
| * False - do not validate SSL certificates. SSL will still be | |
| used (unless use_ssl is False), but SSL certificates | |
| will not be verified. | |
| * path/to/cert/bundle.pem - A filename of the CA cert bundle to | |
| uses. You can specify this argument if you want to use a | |
| different CA cert bundle than the one used by botocore. | |
| :type endpoint_url: string | |
| :param endpoint_url: The complete URL to use for the constructed | |
| client. Normally, botocore will automatically construct the | |
| appropriate URL to use when communicating with a service. You | |
| can specify a complete URL (including the "http/https" scheme) | |
| to override this behavior. If this value is provided, | |
| then ``use_ssl`` is ignored. | |
| :type aws_access_key_id: string | |
| :param aws_access_key_id: The access key to use when creating | |
| the client. This is entirely optional, and if not provided, | |
| the credentials configured for the session will automatically | |
| be used. You only need to provide this argument if you want | |
| to override the credentials used for this specific client. | |
| :type aws_secret_access_key: string | |
| :param aws_secret_access_key: The secret key to use when creating | |
| the client. Same semantics as aws_access_key_id above. | |
| :type aws_session_token: string | |
| :param aws_session_token: The session token to use when creating | |
| the client. Same semantics as aws_access_key_id above. | |
| :type config: botocore.client.Config | |
| :param config: Advanced client configuration options. If region_name | |
| is specified in the client config, its value will take precedence | |
| over environment variables and configuration values, but not over | |
| a region_name value passed explicitly to the method. See | |
| `botocore config documentation | |
| <https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html>`_ | |
| for more details. | |
| :return: Service client instance | |
| """ | |
| return self._session.create_client( | |
| service_name, | |
| region_name=region_name, | |
| api_version=api_version, | |
| use_ssl=use_ssl, | |
| verify=verify, | |
| endpoint_url=endpoint_url, | |
| aws_access_key_id=aws_access_key_id, | |
| aws_secret_access_key=aws_secret_access_key, | |
| aws_session_token=aws_session_token, | |
| config=config, | |
| ) | |
| def resource( | |
| self, | |
| service_name, | |
| region_name=None, | |
| api_version=None, | |
| use_ssl=True, | |
| verify=None, | |
| endpoint_url=None, | |
| aws_access_key_id=None, | |
| aws_secret_access_key=None, | |
| aws_session_token=None, | |
| config=None, | |
| ): | |
| """ | |
| Create a resource service client by name. | |
| :type service_name: string | |
| :param service_name: The name of a service, e.g. 's3' or 'ec2'. You | |
| can get a list of available services via | |
| :py:meth:`get_available_resources`. | |
| :type region_name: string | |
| :param region_name: The name of the region associated with the client. | |
| A client is associated with a single region. | |
| :type api_version: string | |
| :param api_version: The API version to use. By default, botocore will | |
| use the latest API version when creating a client. You only need | |
| to specify this parameter if you want to use a previous API version | |
| of the client. | |
| :type use_ssl: boolean | |
| :param use_ssl: Whether or not to use SSL. By default, SSL is used. | |
| Note that not all services support non-ssl connections. | |
| :type verify: boolean/string | |
| :param verify: Whether or not to verify SSL certificates. By default | |
| SSL certificates are verified. You can provide the following | |
| values: | |
| * False - do not validate SSL certificates. SSL will still be | |
| used (unless use_ssl is False), but SSL certificates | |
| will not be verified. | |
| * path/to/cert/bundle.pem - A filename of the CA cert bundle to | |
| uses. You can specify this argument if you want to use a | |
| different CA cert bundle than the one used by botocore. | |
| :type endpoint_url: string | |
| :param endpoint_url: The complete URL to use for the constructed | |
| client. Normally, botocore will automatically construct the | |
| appropriate URL to use when communicating with a service. You | |
| can specify a complete URL (including the "http/https" scheme) | |
| to override this behavior. If this value is provided, | |
| then ``use_ssl`` is ignored. | |
| :type aws_access_key_id: string | |
| :param aws_access_key_id: The access key to use when creating | |
| the client. This is entirely optional, and if not provided, | |
| the credentials configured for the session will automatically | |
| be used. You only need to provide this argument if you want | |
| to override the credentials used for this specific client. | |
| :type aws_secret_access_key: string | |
| :param aws_secret_access_key: The secret key to use when creating | |
| the client. Same semantics as aws_access_key_id above. | |
| :type aws_session_token: string | |
| :param aws_session_token: The session token to use when creating | |
| the client. Same semantics as aws_access_key_id above. | |
| :type config: botocore.client.Config | |
| :param config: Advanced client configuration options. If region_name | |
| is specified in the client config, its value will take precedence | |
| over environment variables and configuration values, but not over | |
| a region_name value passed explicitly to the method. If | |
| user_agent_extra is specified in the client config, it overrides | |
| the default user_agent_extra provided by the resource API. See | |
| `botocore config documentation | |
| <https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html>`_ | |
| for more details. | |
| :return: Subclass of :py:class:`~boto3.resources.base.ServiceResource` | |
| """ | |
| try: | |
| resource_model = self._loader.load_service_model( | |
| service_name, 'resources-1', api_version | |
| ) | |
| except UnknownServiceError: | |
| available = self.get_available_resources() | |
| has_low_level_client = ( | |
| service_name in self.get_available_services() | |
| ) | |
| raise ResourceNotExistsError( | |
| service_name, available, has_low_level_client | |
| ) | |
| except DataNotFoundError: | |
| # This is because we've provided an invalid API version. | |
| available_api_versions = self._loader.list_api_versions( | |
| service_name, 'resources-1' | |
| ) | |
| raise UnknownAPIVersionError( | |
| service_name, api_version, ', '.join(available_api_versions) | |
| ) | |
| if api_version is None: | |
| # Even though botocore's load_service_model() can handle | |
| # using the latest api_version if not provided, we need | |
| # to track this api_version in boto3 in order to ensure | |
| # we're pairing a resource model with a client model | |
| # of the same API version. It's possible for the latest | |
| # API version of a resource model in boto3 to not be | |
| # the same API version as a service model in botocore. | |
| # So we need to look up the api_version if one is not | |
| # provided to ensure we load the same API version of the | |
| # client. | |
| # | |
| # Note: This is relying on the fact that | |
| # loader.load_service_model(..., api_version=None) | |
| # and loader.determine_latest_version(..., 'resources-1') | |
| # both load the same api version of the file. | |
| api_version = self._loader.determine_latest_version( | |
| service_name, 'resources-1' | |
| ) | |
| # Creating a new resource instance requires the low-level client | |
| # and service model, the resource version and resource JSON data. | |
| # We pass these to the factory and get back a class, which is | |
| # instantiated on top of the low-level client. | |
| if config is not None: | |
| if config.user_agent_extra is None: | |
| config = copy.deepcopy(config) | |
| config.user_agent_extra = 'Resource' | |
| else: | |
| config = Config(user_agent_extra='Resource') | |
| client = self.client( | |
| service_name, | |
| region_name=region_name, | |
| api_version=api_version, | |
| use_ssl=use_ssl, | |
| verify=verify, | |
| endpoint_url=endpoint_url, | |
| aws_access_key_id=aws_access_key_id, | |
| aws_secret_access_key=aws_secret_access_key, | |
| aws_session_token=aws_session_token, | |
| config=config, | |
| ) | |
| service_model = client.meta.service_model | |
| # Create a ServiceContext object to serve as a reference to | |
| # important read-only information about the general service. | |
| service_context = boto3.utils.ServiceContext( | |
| service_name=service_name, | |
| service_model=service_model, | |
| resource_json_definitions=resource_model['resources'], | |
| service_waiter_model=boto3.utils.LazyLoadedWaiterModel( | |
| self._session, service_name, api_version | |
| ), | |
| ) | |
| # Create the service resource class. | |
| cls = self.resource_factory.load_from_definition( | |
| resource_name=service_name, | |
| single_resource_json_definition=resource_model['service'], | |
| service_context=service_context, | |
| ) | |
| return cls(client=client) | |
| def _register_default_handlers(self): | |
| # S3 customizations | |
| self._session.register( | |
| 'creating-client-class.s3', | |
| boto3.utils.lazy_call( | |
| 'boto3.s3.inject.inject_s3_transfer_methods' | |
| ), | |
| ) | |
| self._session.register( | |
| 'creating-resource-class.s3.Bucket', | |
| boto3.utils.lazy_call('boto3.s3.inject.inject_bucket_methods'), | |
| ) | |
| self._session.register( | |
| 'creating-resource-class.s3.Object', | |
| boto3.utils.lazy_call('boto3.s3.inject.inject_object_methods'), | |
| ) | |
| self._session.register( | |
| 'creating-resource-class.s3.ObjectSummary', | |
| boto3.utils.lazy_call( | |
| 'boto3.s3.inject.inject_object_summary_methods' | |
| ), | |
| ) | |
| # DynamoDb customizations | |
| self._session.register( | |
| 'creating-resource-class.dynamodb', | |
| boto3.utils.lazy_call( | |
| 'boto3.dynamodb.transform.register_high_level_interface' | |
| ), | |
| unique_id='high-level-dynamodb', | |
| ) | |
| self._session.register( | |
| 'creating-resource-class.dynamodb.Table', | |
| boto3.utils.lazy_call( | |
| 'boto3.dynamodb.table.register_table_methods' | |
| ), | |
| unique_id='high-level-dynamodb-table', | |
| ) | |
| # EC2 Customizations | |
| self._session.register( | |
| 'creating-resource-class.ec2.ServiceResource', | |
| boto3.utils.lazy_call('boto3.ec2.createtags.inject_create_tags'), | |
| ) | |
| self._session.register( | |
| 'creating-resource-class.ec2.Instance', | |
| boto3.utils.lazy_call( | |
| 'boto3.ec2.deletetags.inject_delete_tags', | |
| event_emitter=self.events, | |
| ), | |
| ) | |