| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import copy |
| import os |
|
|
| import botocore.session |
| from botocore.client import Config |
| from botocore.exceptions import ( |
| DataNotFoundError, |
| NoCredentialsError, |
| 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. |
| :type aws_account_id: string |
| :param aws_account_id: AWS account ID |
| """ |
|
|
| 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, |
| aws_account_id=None, |
| ): |
| if botocore_session is not None: |
| self._session = botocore_session |
| else: |
| |
| self._session = botocore.session.get_session() |
|
|
| |
| if self._session.user_agent_name == 'Botocore': |
| botocore_info = f'Botocore/{self._session.user_agent_version}' |
| if self._session.user_agent_extra: |
| self._session.user_agent_extra += f" {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) |
|
|
| credentials_kwargs = { |
| "aws_access_key_id": aws_access_key_id, |
| "aws_secret_access_key": aws_secret_access_key, |
| "aws_session_token": aws_session_token, |
| "aws_account_id": aws_account_id, |
| } |
|
|
| if any(credentials_kwargs.values()): |
| if self._account_id_set_without_credentials(**credentials_kwargs): |
| raise NoCredentialsError() |
|
|
| if aws_account_id is None: |
| del credentials_kwargs["aws_account_id"] |
|
|
| self._session.set_credentials(*credentials_kwargs.values()) |
|
|
| 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')), |
| ) |
|
|
| @property |
| def profile_name(self): |
| """ |
| The **read-only** profile name. |
| """ |
| return self._session.profile or 'default' |
|
|
| @property |
| def region_name(self): |
| """ |
| The **read-only** region name. |
| """ |
| return self._session.get_config_variable('region') |
|
|
| @property |
| def events(self): |
| """ |
| The event emitter for a session |
| """ |
| return self._session.get_component('event_emitter') |
|
|
| @property |
| 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, |
| aws_account_id=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. |
| |
| :type aws_account_id: string |
| :param aws_account_id: The account id to use when creating |
| the client. Same semantics as aws_access_key_id above. |
| |
| :return: Service client instance |
| |
| """ |
| create_client_kwargs = { |
| '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, |
| 'aws_account_id': aws_account_id, |
| } |
| if aws_account_id is None: |
| |
| |
| del create_client_kwargs['aws_account_id'] |
|
|
| return self._session.create_client( |
| service_name, **create_client_kwargs |
| ) |
|
|
| 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: |
| |
| 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: |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| api_version = self._loader.determine_latest_version( |
| service_name, 'resources-1' |
| ) |
|
|
| |
| |
| |
| |
| 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 |
|
|
| |
| |
| 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 |
| ), |
| ) |
|
|
| |
| 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): |
| |
| 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' |
| ), |
| ) |
|
|
| |
| 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', |
| ) |
|
|
| |
| 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, |
| ), |
| ) |
|
|
| def _account_id_set_without_credentials( |
| self, |
| *, |
| aws_account_id, |
| aws_access_key_id, |
| aws_secret_access_key, |
| **kwargs, |
| ): |
| if aws_account_id is None: |
| return False |
| elif aws_access_key_id is None or aws_secret_access_key is None: |
| return True |
| return False |
|
|