codekingpro/portable-devtools
114k
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# https://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 14import copy15import os16 17import botocore.session18from botocore.client import Config19from botocore.exceptions import DataNotFoundError, UnknownServiceError20 21import boto322import boto3.utils23from boto3.exceptions import ResourceNotExistsError, UnknownAPIVersionError24 25from .resources.factory import ResourceFactory26 27 28class Session:29 """30 A session stores configuration state and allows you to create service31 clients and resources.32 33 :type aws_access_key_id: string34 :param aws_access_key_id: AWS access key ID35 :type aws_secret_access_key: string36 :param aws_secret_access_key: AWS secret access key37 :type aws_session_token: string38 :param aws_session_token: AWS temporary session token39 :type region_name: string40 :param region_name: Default region when creating new connections41 :type botocore_session: botocore.session.Session42 :param botocore_session: Use this Botocore session instead of creating43 a new default one.44 :type profile_name: string45 :param profile_name: The name of a profile to use. If not given, then46 the default profile is used.47 """48 49 def __init__(50 self,51 aws_access_key_id=None,52 aws_secret_access_key=None,53 aws_session_token=None,54 region_name=None,55 botocore_session=None,56 profile_name=None,57 ):58 if botocore_session is not None:59 self._session = botocore_session60 else:61 # Create a new default session62 self._session = botocore.session.get_session()63 64 # Setup custom user-agent string if it isn't already customized65 if self._session.user_agent_name == 'Botocore':66 botocore_info = 'Botocore/{}'.format(67 self._session.user_agent_version68 )69 if self._session.user_agent_extra:70 self._session.user_agent_extra += ' ' + botocore_info71 else:72 self._session.user_agent_extra = botocore_info73 self._session.user_agent_name = 'Boto3'74 self._session.user_agent_version = boto3.__version__75 76 if profile_name is not None:77 self._session.set_config_variable('profile', profile_name)78 79 if aws_access_key_id or aws_secret_access_key or aws_session_token:80 self._session.set_credentials(81 aws_access_key_id, aws_secret_access_key, aws_session_token82 )83 84 if region_name is not None:85 self._session.set_config_variable('region', region_name)86 87 self.resource_factory = ResourceFactory(88 self._session.get_component('event_emitter')89 )90 self._setup_loader()91 self._register_default_handlers()92 93 def __repr__(self):94 return '{}(region_name={})'.format(95 self.__class__.__name__,96 repr(self._session.get_config_variable('region')),97 )98 99 @property100 def profile_name(self):101 """102 The **read-only** profile name.103 """104 return self._session.profile or 'default'105 106 @property107 def region_name(self):108 """109 The **read-only** region name.110 """111 return self._session.get_config_variable('region')112 113 @property114 def events(self):115 """116 The event emitter for a session117 """118 return self._session.get_component('event_emitter')119 120 @property121 def available_profiles(self):122 """123 The profiles available to the session credentials124 """125 return self._session.available_profiles126 127 def _setup_loader(self):128 """129 Setup loader paths so that we can load resources.130 """131 self._loader = self._session.get_component('data_loader')132 self._loader.search_paths.append(133 os.path.join(os.path.dirname(__file__), 'data')134 )135 136 def get_available_services(self):137 """138 Get a list of available services that can be loaded as low-level139 clients via :py:meth:`Session.client`.140 141 :rtype: list142 :return: List of service names143 """144 return self._session.get_available_services()145 146 def get_available_resources(self):147 """148 Get a list of available services that can be loaded as resource149 clients via :py:meth:`Session.resource`.150 151 :rtype: list152 :return: List of service names153 """154 return self._loader.list_available_services(type_name='resources-1')155 156 def get_available_partitions(self):157 """Lists the available partitions158 159 :rtype: list160 :return: Returns a list of partition names (e.g., ["aws", "aws-cn"])161 """162 return self._session.get_available_partitions()163 164 def get_available_regions(165 self, service_name, partition_name='aws', allow_non_regional=False166 ):167 """Lists the region and endpoint names of a particular partition.168 169 The list of regions returned by this method are regions that are170 explicitly known by the client to exist and is not comprehensive. A171 region not returned in this list may still be available for the172 provided service.173 174 :type service_name: string175 :param service_name: Name of a service to list endpoint for (e.g., s3).176 177 :type partition_name: string178 :param partition_name: Name of the partition to limit endpoints to.179 (e.g., aws for the public AWS endpoints, aws-cn for AWS China180 endpoints, aws-us-gov for AWS GovCloud (US) Endpoints, etc.)181 182 :type allow_non_regional: bool183 :param allow_non_regional: Set to True to include endpoints that are184 not regional endpoints (e.g., s3-external-1,185 fips-us-gov-west-1, etc).186 187 :return: Returns a list of endpoint names (e.g., ["us-east-1"]).188 """189 return self._session.get_available_regions(190 service_name=service_name,191 partition_name=partition_name,192 allow_non_regional=allow_non_regional,193 )194 195 def get_credentials(self):196 """197 Return the :class:`botocore.credentials.Credentials` object198 associated with this session. If the credentials have not199 yet been loaded, this will attempt to load them. If they200 have already been loaded, this will return the cached201 credentials.202 """203 return self._session.get_credentials()204 205 def get_partition_for_region(self, region_name):206 """Lists the partition name of a particular region.207 208 :type region_name: string209 :param region_name: Name of the region to list partition for (e.g.,210 us-east-1).211 212 :rtype: string213 :return: Returns the respective partition name (e.g., aws).214 """215 return self._session.get_partition_for_region(region_name)216 217 def client(218 self,219 service_name,220 region_name=None,221 api_version=None,222 use_ssl=True,223 verify=None,224 endpoint_url=None,225 aws_access_key_id=None,226 aws_secret_access_key=None,227 aws_session_token=None,228 config=None,229 ):230 """231 Create a low-level service client by name.232 233 :type service_name: string234 :param service_name: The name of a service, e.g. 's3' or 'ec2'. You235 can get a list of available services via236 :py:meth:`get_available_services`.237 238 :type region_name: string239 :param region_name: The name of the region associated with the client.240 A client is associated with a single region.241 242 :type api_version: string243 :param api_version: The API version to use. By default, botocore will244 use the latest API version when creating a client. You only need245 to specify this parameter if you want to use a previous API version246 of the client.247 248 :type use_ssl: boolean249 :param use_ssl: Whether or not to use SSL. By default, SSL is used.250 Note that not all services support non-ssl connections.251 252 :type verify: boolean/string253 :param verify: Whether or not to verify SSL certificates. By default254 SSL certificates are verified. You can provide the following255 values:256 257 * False - do not validate SSL certificates. SSL will still be258 used (unless use_ssl is False), but SSL certificates259 will not be verified.260 * path/to/cert/bundle.pem - A filename of the CA cert bundle to261 uses. You can specify this argument if you want to use a262 different CA cert bundle than the one used by botocore.263 264 :type endpoint_url: string265 :param endpoint_url: The complete URL to use for the constructed266 client. Normally, botocore will automatically construct the267 appropriate URL to use when communicating with a service. You268 can specify a complete URL (including the "http/https" scheme)269 to override this behavior. If this value is provided,270 then ``use_ssl`` is ignored.271 272 :type aws_access_key_id: string273 :param aws_access_key_id: The access key to use when creating274 the client. This is entirely optional, and if not provided,275 the credentials configured for the session will automatically276 be used. You only need to provide this argument if you want277 to override the credentials used for this specific client.278 279 :type aws_secret_access_key: string280 :param aws_secret_access_key: The secret key to use when creating281 the client. Same semantics as aws_access_key_id above.282 283 :type aws_session_token: string284 :param aws_session_token: The session token to use when creating285 the client. Same semantics as aws_access_key_id above.286 287 :type config: botocore.client.Config288 :param config: Advanced client configuration options. If region_name289 is specified in the client config, its value will take precedence290 over environment variables and configuration values, but not over291 a region_name value passed explicitly to the method. See292 `botocore config documentation293 <https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html>`_294 for more details.295 296 :return: Service client instance297 298 """299 return self._session.create_client(300 service_name,301 region_name=region_name,302 api_version=api_version,303 use_ssl=use_ssl,304 verify=verify,305 endpoint_url=endpoint_url,306 aws_access_key_id=aws_access_key_id,307 aws_secret_access_key=aws_secret_access_key,308 aws_session_token=aws_session_token,309 config=config,310 )311 312 def resource(313 self,314 service_name,315 region_name=None,316 api_version=None,317 use_ssl=True,318 verify=None,319 endpoint_url=None,320 aws_access_key_id=None,321 aws_secret_access_key=None,322 aws_session_token=None,323 config=None,324 ):325 """326 Create a resource service client by name.327 328 :type service_name: string329 :param service_name: The name of a service, e.g. 's3' or 'ec2'. You330 can get a list of available services via331 :py:meth:`get_available_resources`.332 333 :type region_name: string334 :param region_name: The name of the region associated with the client.335 A client is associated with a single region.336 337 :type api_version: string338 :param api_version: The API version to use. By default, botocore will339 use the latest API version when creating a client. You only need340 to specify this parameter if you want to use a previous API version341 of the client.342 343 :type use_ssl: boolean344 :param use_ssl: Whether or not to use SSL. By default, SSL is used.345 Note that not all services support non-ssl connections.346 347 :type verify: boolean/string348 :param verify: Whether or not to verify SSL certificates. By default349 SSL certificates are verified. You can provide the following350 values:351 352 * False - do not validate SSL certificates. SSL will still be353 used (unless use_ssl is False), but SSL certificates354 will not be verified.355 * path/to/cert/bundle.pem - A filename of the CA cert bundle to356 uses. You can specify this argument if you want to use a357 different CA cert bundle than the one used by botocore.358 359 :type endpoint_url: string360 :param endpoint_url: The complete URL to use for the constructed361 client. Normally, botocore will automatically construct the362 appropriate URL to use when communicating with a service. You363 can specify a complete URL (including the "http/https" scheme)364 to override this behavior. If this value is provided,365 then ``use_ssl`` is ignored.366 367 :type aws_access_key_id: string368 :param aws_access_key_id: The access key to use when creating369 the client. This is entirely optional, and if not provided,370 the credentials configured for the session will automatically371 be used. You only need to provide this argument if you want372 to override the credentials used for this specific client.373 374 :type aws_secret_access_key: string375 :param aws_secret_access_key: The secret key to use when creating376 the client. Same semantics as aws_access_key_id above.377 378 :type aws_session_token: string379 :param aws_session_token: The session token to use when creating380 the client. Same semantics as aws_access_key_id above.381 382 :type config: botocore.client.Config383 :param config: Advanced client configuration options. If region_name384 is specified in the client config, its value will take precedence385 over environment variables and configuration values, but not over386 a region_name value passed explicitly to the method. If387 user_agent_extra is specified in the client config, it overrides388 the default user_agent_extra provided by the resource API. See389 `botocore config documentation390 <https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html>`_391 for more details.392 393 :return: Subclass of :py:class:`~boto3.resources.base.ServiceResource`394 """395 try:396 resource_model = self._loader.load_service_model(397 service_name, 'resources-1', api_version398 )399 except UnknownServiceError:400 available = self.get_available_resources()401 has_low_level_client = (402 service_name in self.get_available_services()403 )404 raise ResourceNotExistsError(405 service_name, available, has_low_level_client406 )407 except DataNotFoundError:408 # This is because we've provided an invalid API version.409 available_api_versions = self._loader.list_api_versions(410 service_name, 'resources-1'411 )412 raise UnknownAPIVersionError(413 service_name, api_version, ', '.join(available_api_versions)414 )415 416 if api_version is None:417 # Even though botocore's load_service_model() can handle418 # using the latest api_version if not provided, we need419 # to track this api_version in boto3 in order to ensure420 # we're pairing a resource model with a client model421 # of the same API version. It's possible for the latest422 # API version of a resource model in boto3 to not be423 # the same API version as a service model in botocore.424 # So we need to look up the api_version if one is not425 # provided to ensure we load the same API version of the426 # client.427 #428 # Note: This is relying on the fact that429 # loader.load_service_model(..., api_version=None)430 # and loader.determine_latest_version(..., 'resources-1')431 # both load the same api version of the file.432 api_version = self._loader.determine_latest_version(433 service_name, 'resources-1'434 )435 436 # Creating a new resource instance requires the low-level client437 # and service model, the resource version and resource JSON data.438 # We pass these to the factory and get back a class, which is439 # instantiated on top of the low-level client.440 if config is not None:441 if config.user_agent_extra is None:442 config = copy.deepcopy(config)443 config.user_agent_extra = 'Resource'444 else:445 config = Config(user_agent_extra='Resource')446 client = self.client(447 service_name,448 region_name=region_name,449 api_version=api_version,450 use_ssl=use_ssl,451 verify=verify,452 endpoint_url=endpoint_url,453 aws_access_key_id=aws_access_key_id,454 aws_secret_access_key=aws_secret_access_key,455 aws_session_token=aws_session_token,456 config=config,457 )458 service_model = client.meta.service_model459 460 # Create a ServiceContext object to serve as a reference to461 # important read-only information about the general service.462 service_context = boto3.utils.ServiceContext(463 service_name=service_name,464 service_model=service_model,465 resource_json_definitions=resource_model['resources'],466 service_waiter_model=boto3.utils.LazyLoadedWaiterModel(467 self._session, service_name, api_version468 ),469 )470 471 # Create the service resource class.472 cls = self.resource_factory.load_from_definition(473 resource_name=service_name,474 single_resource_json_definition=resource_model['service'],475 service_context=service_context,476 )477 478 return cls(client=client)479 480 def _register_default_handlers(self):481 # S3 customizations482 self._session.register(483 'creating-client-class.s3',484 boto3.utils.lazy_call(485 'boto3.s3.inject.inject_s3_transfer_methods'486 ),487 )488 self._session.register(489 'creating-resource-class.s3.Bucket',490 boto3.utils.lazy_call('boto3.s3.inject.inject_bucket_methods'),491 )492 self._session.register(493 'creating-resource-class.s3.Object',494 boto3.utils.lazy_call('boto3.s3.inject.inject_object_methods'),495 )496 self._session.register(497 'creating-resource-class.s3.ObjectSummary',498 boto3.utils.lazy_call(499 'boto3.s3.inject.inject_object_summary_methods'500 ),501 )502 503 # DynamoDb customizations504 self._session.register(505 'creating-resource-class.dynamodb',506 boto3.utils.lazy_call(507 'boto3.dynamodb.transform.register_high_level_interface'508 ),509 unique_id='high-level-dynamodb',510 )511 self._session.register(512 'creating-resource-class.dynamodb.Table',513 boto3.utils.lazy_call(514 'boto3.dynamodb.table.register_table_methods'515 ),516 unique_id='high-level-dynamodb-table',517 )518 519 # EC2 Customizations520 self._session.register(521 'creating-resource-class.ec2.ServiceResource',522 boto3.utils.lazy_call('boto3.ec2.createtags.inject_create_tags'),523 )524 525 self._session.register(526 'creating-resource-class.ec2.Instance',527 boto3.utils.lazy_call(528 'boto3.ec2.deletetags.inject_delete_tags',529 event_emitter=self.events,530 ),531 )532 