def _construct_api_key(self, usage_plan_logical_id, create_usage_plan, rest_api_stage): """ :param usage_plan_logical_id: String :param create_usage_plan: String :param rest_api_stage: model.apigateway.ApiGatewayStage stage: the stage of rest api :return: api_key model.apigateway.ApiGatewayApiKey resource which is created for the given usage plan """ if create_usage_plan == "SHARED": # create an api key resource for all the apis api_key_logical_id = "ServerlessApiKey" api_key = ApiGatewayApiKey(logical_id=api_key_logical_id, depends_on=[usage_plan_logical_id]) api_key.Enabled = True stage_key = dict() stage_key["RestApiId"] = ref(self.logical_id) stage_key["StageName"] = ref(rest_api_stage.logical_id) if stage_key not in ApiGenerator.stage_keys_shared: ApiGenerator.stage_keys_shared.append(stage_key) api_key.StageKeys = ApiGenerator.stage_keys_shared # for create_usage_plan = "PER_API" else: # create an api key resource for this api api_key_logical_id = self.logical_id + "ApiKey" api_key = ApiGatewayApiKey(logical_id=api_key_logical_id, depends_on=[usage_plan_logical_id]) api_key.Enabled = True stage_keys = list() stage_key = dict() stage_key["RestApiId"] = ref(self.logical_id) stage_key["StageName"] = ref(rest_api_stage.logical_id) stage_keys.append(stage_key) api_key.StageKeys = stage_keys return api_key
class CodeDeployApplication(Resource): resource_type = "AWS::CodeDeploy::Application" property_types = { "ComputePlatform": PropertyType(False, one_of(is_str(), is_type(dict))) } runtime_attrs = {"name": lambda self: ref(self.logical_id)}
def _depend_on_lambda_permissions_using_tag(self, bucket, permission): """ Since conditional DependsOn is not supported this undocumented way of implicitely making dependency through tags is used. See https://stackoverflow.com/questions/34607476/cloudformation-apply-condition-on-dependson It is done by using Ref wrapped in a conditional Fn::If. Using Ref implies a dependency, so CloudFormation will automatically wait once it reaches that function, the same as if you were using a DependsOn. """ properties = bucket.get('Properties', None) if properties is None: properties = {} bucket['Properties'] = properties tags = properties.get('Tags', None) if tags is None: tags = [] properties['Tags'] = tags dep_tag = { 'sam:ConditionalDependsOn:' + permission.logical_id: { 'Fn::If': [ permission.resource_attributes[CONDITION], ref(permission.logical_id), 'no dependency' ] } } properties['Tags'] = tags + get_tag_list(dep_tag) return bucket
class LambdaFunction(Resource): resource_type = 'AWS::Lambda::Function' property_types = { 'Code': PropertyType(True, is_type(dict)), 'DeadLetterConfig': PropertyType(False, is_type(dict)), 'Description': PropertyType(False, is_str()), 'FunctionName': PropertyType(False, is_str()), 'Handler': PropertyType(True, is_str()), 'MemorySize': PropertyType(False, is_type(int)), 'Role': PropertyType(False, is_str()), 'Runtime': PropertyType(False, is_str()), 'Timeout': PropertyType(False, is_type(int)), 'VpcConfig': PropertyType(False, is_type(dict)), 'Environment': PropertyType(False, is_type(dict)), 'Tags': PropertyType(False, list_of(is_type(dict))), 'TracingConfig': PropertyType(False, is_type(dict)), 'KmsKeyArn': PropertyType(False, one_of(is_type(dict), is_str())), 'Layers': PropertyType(False, list_of(one_of(is_str(), is_type(dict)))), 'ReservedConcurrentExecutions': PropertyType(False, any_type()) } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn") }
class S3Bucket(Resource): resource_type = 'AWS::S3::Bucket' property_types = { 'AccessControl': PropertyType(False, any_type()), 'AccelerateConfiguration': PropertyType(False, any_type()), 'AnalyticsConfigurations': PropertyType(False, any_type()), 'BucketEncryption': PropertyType(False, any_type()), 'BucketName': PropertyType(False, is_str()), 'CorsConfiguration': PropertyType(False, any_type()), 'InventoryConfigurations': PropertyType(False, any_type()), 'LifecycleConfiguration': PropertyType(False, any_type()), 'LoggingConfiguration': PropertyType(False, any_type()), 'MetricsConfigurations': PropertyType(False, any_type()), 'NotificationConfiguration': PropertyType(False, is_type(dict)), 'PublicAccessBlockConfiguration': PropertyType(False, is_type(dict)), 'ReplicationConfiguration': PropertyType(False, any_type()), 'Tags': PropertyType(False, is_type(list)), 'VersioningConfiguration': PropertyType(False, any_type()), 'WebsiteConfiguration': PropertyType(False, any_type()), } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn") }
class CognitoUserPool(Resource): resource_type = "AWS::Cognito::UserPool" property_types = { "AdminCreateUserConfig": PropertyType(False, is_type(dict)), "AliasAttributes": PropertyType(False, list_of(is_str())), "AutoVerifiedAttributes": PropertyType(False, list_of(is_str())), "DeviceConfiguration": PropertyType(False, is_type(dict)), "EmailConfiguration": PropertyType(False, is_type(dict)), "EmailVerificationMessage": PropertyType(False, is_str()), "EmailVerificationSubject": PropertyType(False, is_str()), "LambdaConfig": PropertyType(False, is_type(dict)), "MfaConfiguration": PropertyType(False, is_str()), "Policies": PropertyType(False, is_type(dict)), "Schema": PropertyType(False, list_of(dict)), "SmsAuthenticationMessage": PropertyType(False, is_str()), "SmsConfiguration": PropertyType(False, list_of(dict)), "SmsVerificationMessage": PropertyType(False, is_str()), "UsernameAttributes": PropertyType(False, list_of(is_str())), "UserPoolAddOns": PropertyType(False, list_of(dict)), "UserPoolName": PropertyType(False, is_str()), "UserPoolTags": PropertyType(False, is_type(dict)), "VerificationMessageTemplate": PropertyType(False, is_type(dict)), } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn"), "provider_name": lambda self: fnGetAtt(self.logical_id, "ProviderName"), "provider_url": lambda self: fnGetAtt(self.logical_id, "ProviderURL"), }
def _construct_stage(self, deployment, swagger): """Constructs and returns the ApiGateway Stage. :param model.apigateway.ApiGatewayDeployment deployment: the Deployment for this Stage :returns: the Stage to which this SAM Api corresponds :rtype: model.apigateway.ApiGatewayStage """ # If StageName is some intrinsic function, then don't prefix the Stage's logical ID # This will NOT create duplicates because we allow only ONE stage per API resource stage_name_prefix = self.stage_name if isinstance(self.stage_name, string_types) else "" stage = ApiGatewayStage(self.logical_id + stage_name_prefix + 'Stage') stage.RestApiId = ref(self.logical_id) stage.update_deployment_ref(deployment.logical_id) stage.StageName = self.stage_name stage.CacheClusterEnabled = self.cache_cluster_enabled stage.CacheClusterSize = self.cache_cluster_size stage.Variables = self.variables stage.MethodSettings = self.method_settings if swagger is not None: deployment.make_auto_deployable(stage, swagger) return stage
def _construct_stage(self): """Constructs and returns the ApiGatewayV2 Stage. :returns: the Stage to which this SAM Api corresponds :rtype: model.apigatewayv2.ApiGatewayV2Stage """ # If there are no special configurations, don't create a stage and use the default if not self.stage_name and not self.stage_variables and not self.access_log_settings: return # If StageName is some intrinsic function, then don't prefix the Stage's logical ID # This will NOT create duplicates because we allow only ONE stage per API resource stage_name_prefix = self.stage_name if isinstance(self.stage_name, string_types) else "" if stage_name_prefix.isalnum(): stage_logical_id = self.logical_id + stage_name_prefix + "Stage" elif stage_name_prefix == DefaultStageName: stage_logical_id = self.logical_id + "ApiGatewayDefaultStage" else: generator = logical_id_generator.LogicalIdGenerator(self.logical_id + "Stage", stage_name_prefix) stage_logical_id = generator.gen() stage = ApiGatewayV2Stage(stage_logical_id, attributes=self.passthrough_resource_attributes) stage.ApiId = ref(self.logical_id) stage.StageName = self.stage_name stage.StageVariables = self.stage_variables stage.AccessLogSettings = self.access_log_settings stage.AutoDeploy = True if self.tags is not None: stage.Tags = get_tag_list(self.tags) return stage
class ApiGatewayDeployment(Resource): resource_type = 'AWS::ApiGateway::Deployment' property_types = { 'Description': PropertyType(False, is_str()), 'RestApiId': PropertyType(True, is_str()), 'StageDescription': PropertyType(False, is_type(dict)), 'StageName': PropertyType(False, is_str()) } runtime_attrs = { "deployment_id": lambda self: ref(self.logical_id), } def make_auto_deployable(self, stage, swagger=None): """ Sets up the resource such that it will triggers a re-deployment when Swagger changes :param swagger: Dictionary containing the Swagger definition of the API """ if not swagger: return # CloudFormation does NOT redeploy the API unless it has a new deployment resource # that points to latest RestApi resource. Append a hash of Swagger Body location to # redeploy only when the API data changes. First 10 characters of hash is good enough # to prevent redeployment when API has not changed # NOTE: `str(swagger)` is for backwards compatibility. Changing it to a JSON or something will break compat generator = logical_id_generator.LogicalIdGenerator( self.logical_id, str(swagger)) self.logical_id = generator.gen() hash = generator.get_hash(length=40) # Get the full hash self.Description = "RestApi deployment id: {}".format(hash) stage.update_deployment_ref(self.logical_id)
class SQSQueue(Resource): resource_type = 'AWS::SQS::Queue' property_types = {} runtime_attrs = { "queue_url": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn"), }
class S3Bucket(Resource): resource_type = "AWS::S3::Bucket" property_types = { "AccessControl": PropertyType(False, any_type()), "AccelerateConfiguration": PropertyType(False, any_type()), "AnalyticsConfigurations": PropertyType(False, any_type()), "BucketEncryption": PropertyType(False, any_type()), "BucketName": PropertyType(False, is_str()), "CorsConfiguration": PropertyType(False, any_type()), "InventoryConfigurations": PropertyType(False, any_type()), "LifecycleConfiguration": PropertyType(False, any_type()), "LoggingConfiguration": PropertyType(False, any_type()), "MetricsConfigurations": PropertyType(False, any_type()), "NotificationConfiguration": PropertyType(False, is_type(dict)), "PublicAccessBlockConfiguration": PropertyType(False, is_type(dict)), "ReplicationConfiguration": PropertyType(False, any_type()), "Tags": PropertyType(False, is_type(list)), "VersioningConfiguration": PropertyType(False, any_type()), "WebsiteConfiguration": PropertyType(False, any_type()), } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn") }
class DynamoDBTable(Resource): resource_type = 'AWS::DynamoDB::Table' property_types = { 'AttributeDefinitions': PropertyType(True, list_of(is_type(dict))), 'GlobalSecondaryIndexes': PropertyType(False, list_of(is_type(dict))), 'KeySchema': PropertyType(False, list_of(is_type(dict))), 'LocalSecondaryIndexes': PropertyType(False, list_of(is_type(dict))), 'ProvisionedThroughput': PropertyType(False, dict_of(is_str(), one_of(is_type(int), is_type(dict)))), 'StreamSpecification': PropertyType(False, is_type(dict)), 'TableName': PropertyType(False, one_of(is_str(), is_type(dict))), 'Tags': PropertyType(False, list_of(is_type(dict))), 'SSESpecification': PropertyType(False, is_type(dict)), 'BillingMode': PropertyType(False, is_str()) } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn"), "stream_arn": lambda self: fnGetAtt(self.logical_id, "StreamArn") }
def _construct_stage(self, deployment, swagger): """Constructs and returns the ApiGateway Stage. :param model.apigateway.ApiGatewayDeployment deployment: the Deployment for this Stage :returns: the Stage to which this SAM Api corresponds :rtype: model.apigateway.ApiGatewayStage """ # If StageName is some intrinsic function, then don't prefix the Stage's logical ID # This will NOT create duplicates because we allow only ONE stage per API resource stage_name_prefix = self.stage_name if isinstance( self.stage_name, string_types) else "" stage = ApiGatewayStage(self.logical_id + stage_name_prefix + 'Stage') stage.RestApiId = ref(self.logical_id) stage.update_deployment_ref(deployment.logical_id) stage.StageName = self.stage_name stage.CacheClusterEnabled = self.cache_cluster_enabled stage.CacheClusterSize = self.cache_cluster_size stage.Variables = self.variables stage.MethodSettings = self.method_settings stage.AccessLogSetting = self.access_log_setting if swagger is not None: deployment.make_auto_deployable(stage, swagger) return stage
def to_cloudformation(self, **kwargs): function = kwargs.get('function') if not function: raise TypeError("Missing required keyword argument: function") resources = [] resource = 'rule/${RuleName}' partition = ArnGenerator.get_partition_name() source_arn = fnSub( ArnGenerator.generate_arn(partition=partition, service='iot', resource=resource), {'RuleName': ref(self.logical_id)}) source_account = fnSub('${AWS::AccountId}') resources.append( self._construct_permission(function, source_arn=source_arn, source_account=source_account)) resources.append(self._construct_iot_rule(function)) return resources
class CognitoUserPool(Resource): resource_type = 'AWS::Cognito::UserPool' property_types = { 'AdminCreateUserConfig': PropertyType(False, is_type(dict)), 'AliasAttributes': PropertyType(False, list_of(is_str())), 'AutoVerifiedAttributes': PropertyType(False, list_of(is_str())), 'DeviceConfiguration': PropertyType(False, is_type(dict)), 'EmailConfiguration': PropertyType(False, is_type(dict)), 'EmailVerificationMessage': PropertyType(False, is_str()), 'EmailVerificationSubject': PropertyType(False, is_str()), 'LambdaConfig': PropertyType(False, is_type(dict)), 'MfaConfiguration': PropertyType(False, is_str()), 'Policies': PropertyType(False, is_type(dict)), 'Schema': PropertyType(False, list_of(dict)), 'SmsAuthenticationMessage': PropertyType(False, is_str()), 'SmsConfiguration': PropertyType(False, list_of(dict)), 'SmsVerificationMessage': PropertyType(False, is_str()), 'UsernameAttributes': PropertyType(False, list_of(is_str())), 'UserPoolAddOns': PropertyType(False, list_of(dict)), 'UserPoolName': PropertyType(False, is_str()), 'UserPoolTags': PropertyType(False, is_str()), 'VerificationMessageTemplate': PropertyType(False, is_type(dict)) } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn"), "provider_name": lambda self: fnGetAtt(self.logical_id, "ProviderName"), "provider_url": lambda self: fnGetAtt(self.logical_id, "ProviderURL") }
def gen_skeleton(): """ Method to make an empty swagger file, with just some basic structure. Just enough to pass validator. :return dict: Dictionary of a skeleton swagger document """ return {"openapi": "3.0.1", "info": {"version": "1.0", "title": ref("AWS::StackName")}, "paths": {}}
class LambdaFunction(Resource): resource_type = "AWS::Lambda::Function" property_types = { "Code": PropertyType(True, is_type(dict)), "PackageType": PropertyType(False, is_str()), "DeadLetterConfig": PropertyType(False, is_type(dict)), "Description": PropertyType(False, is_str()), "FunctionName": PropertyType(False, is_str()), "Handler": PropertyType(False, is_str()), "MemorySize": PropertyType(False, is_type(int)), "Role": PropertyType(False, is_str()), "Runtime": PropertyType(False, is_str()), "Timeout": PropertyType(False, is_type(int)), "VpcConfig": PropertyType(False, is_type(dict)), "Environment": PropertyType(False, is_type(dict)), "Tags": PropertyType(False, list_of(is_type(dict))), "TracingConfig": PropertyType(False, is_type(dict)), "KmsKeyArn": PropertyType(False, one_of(is_type(dict), is_str())), "Layers": PropertyType(False, list_of(one_of(is_str(), is_type(dict)))), "ReservedConcurrentExecutions": PropertyType(False, any_type()), "FileSystemConfigs": PropertyType(False, list_of(is_type(dict))), "CodeSigningConfigArn": PropertyType(False, is_str()), "ImageConfig": PropertyType(False, is_type(dict)), } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn") }
class IotTopicRule(Resource): resource_type = 'AWS::IoT::TopicRule' property_types = {'TopicRulePayload': PropertyType(False, is_type(dict))} runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn") }
class ApiGatewayDeployment(Resource): _X_HASH_DELIMITER = "||" resource_type = "AWS::ApiGateway::Deployment" property_types = { "Description": PropertyType(False, is_str()), "RestApiId": PropertyType(True, is_str()), "StageDescription": PropertyType(False, is_type(dict)), "StageName": PropertyType(False, is_str()), } runtime_attrs = {"deployment_id": lambda self: ref(self.logical_id)} def make_auto_deployable(self, stage, openapi_version=None, swagger=None, domain=None, redeploy_restapi_parameters=None): """ Sets up the resource such that it will trigger a re-deployment when Swagger changes or the openapi version changes or a domain resource changes. :param swagger: Dictionary containing the Swagger definition of the API :param openapi_version: string containing value of OpenApiVersion flag in the template :param domain: Dictionary containing the custom domain configuration for the API :param redeploy_restapi_parameters: Dictionary containing the properties for which rest api will be redeployed """ if not swagger: return # CloudFormation does NOT redeploy the API unless it has a new deployment resource # that points to latest RestApi resource. Append a hash of Swagger Body location to # redeploy only when the API data changes. First 10 characters of hash is good enough # to prevent redeployment when API has not changed # NOTE: `str(swagger)` is for backwards compatibility. Changing it to a JSON or something will break compat hash_input = [str(swagger)] if openapi_version: hash_input.append(str(openapi_version)) if domain: hash_input.append(json.dumps(domain)) if redeploy_restapi_parameters: function_names = redeploy_restapi_parameters.get("function_names") else: function_names = None # The deployment logical id is <api logicalId> + "Deployment" # The keyword "Deployment" is removed and all the function names associated with api is obtained if function_names and function_names.get(self.logical_id[:-10], None): hash_input.append(function_names.get(self.logical_id[:-10], "")) data = self._X_HASH_DELIMITER.join(hash_input) generator = logical_id_generator.LogicalIdGenerator( self.logical_id, data) self.logical_id = generator.gen() digest = generator.get_hash(length=40) # Get the full hash self.Description = "RestApi deployment id: {}".format(digest) stage.update_deployment_ref(self.logical_id)
class LambdaAlias(Resource): resource_type = 'AWS::Lambda::Alias' property_types = { 'Description': PropertyType(False, is_str()), 'Name': PropertyType(False, is_str()), 'FunctionName': PropertyType(True, one_of(is_str(), is_type(dict))), 'FunctionVersion': PropertyType(True, one_of(is_str(), is_type(dict))) } runtime_attrs = {"arn": lambda self: ref(self.logical_id)}
def to_dict(self): """ :return: a dict that can be used as part of a cloudformation template """ dict_with_nones = self._asdict() codedeploy_lambda_alias_update_dict = dict( (k, v) for k, v in dict_with_nones.items() if v != ref(None) and v is not None) return { "CodeDeployLambdaAliasUpdate": codedeploy_lambda_alias_update_dict }
class ApiGatewayUsagePlan(Resource): resource_type = "AWS::ApiGateway::UsagePlan" property_types = { "ApiStages": PropertyType(False, is_type(list)), "Description": PropertyType(False, is_str()), "Quota": PropertyType(False, is_type(dict)), "Tags": PropertyType(False, list_of(dict)), "Throttle": PropertyType(False, is_type(dict)), "UsagePlanName": PropertyType(False, is_str()), } runtime_attrs = {"usage_plan_id": lambda self: ref(self.logical_id)}
class LambdaEventSourceMapping(Resource): resource_type = 'AWS::Lambda::EventSourceMapping' property_types = { 'BatchSize': PropertyType(False, is_type(int)), 'Enabled': PropertyType(False, is_type(bool)), 'EventSourceArn': PropertyType(True, is_str()), 'FunctionName': PropertyType(True, is_str()), 'StartingPosition': PropertyType(True, is_str()) } runtime_attrs = {"name": lambda self: ref(self.logical_id)}
class LambdaAlias(Resource): resource_type = "AWS::Lambda::Alias" property_types = { "Description": PropertyType(False, is_str()), "Name": PropertyType(False, is_str()), "FunctionName": PropertyType(True, one_of(is_str(), is_type(dict))), "FunctionVersion": PropertyType(True, one_of(is_str(), is_type(dict))), "ProvisionedConcurrencyConfig": PropertyType(False, is_type(dict)), } runtime_attrs = {"arn": lambda self: ref(self.logical_id)}
class IAMRole(Resource): resource_type = "AWS::IAM::Role" property_types = { "AssumeRolePolicyDocument": PropertyType(True, is_type(dict)), "ManagedPolicyArns": PropertyType(False, is_type(list)), "Path": PropertyType(False, is_str()), "Policies": PropertyType(False, is_type(list)), "PermissionsBoundary": PropertyType(False, is_str()), "Tags": PropertyType(False, list_of(is_type(dict))), } runtime_attrs = {"name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn")}
class LambdaVersion(Resource): resource_type = 'AWS::Lambda::Version' property_types = { 'CodeSha256': PropertyType(False, is_str()), 'Description': PropertyType(False, is_str()), 'FunctionName': PropertyType(True, one_of(is_str(), is_type(dict))) } runtime_attrs = { "arn": lambda self: ref(self.logical_id), "version": lambda self: fnGetAtt(self.logical_id, "Version") }
class SubscriptionFilter(Resource): resource_type = "AWS::Logs::SubscriptionFilter" property_types = { "LogGroupName": PropertyType(True, is_str()), "FilterPattern": PropertyType(True, is_str()), "DestinationArn": PropertyType(True, is_str()), } runtime_attrs = { "name": lambda self: ref(self.logical_id), "arn": lambda self: fnGetAtt(self.logical_id, "Arn") }
class NestedStack(Resource): resource_type = 'AWS::CloudFormation::Stack' # TODO: support passthrough parameters for stacks (Conditions, etc) property_types = { 'TemplateURL': PropertyType(True, is_str()), 'Parameters': PropertyType(False, is_type(dict)), 'NotificationArns': PropertyType(False, list_of(is_str())), 'Tags': PropertyType(False, list_of(is_type(dict))), 'TimeoutInMinutes': PropertyType(False, is_type(int)) } runtime_attrs = {"stack_id": lambda self: ref(self.logical_id)}
def _construct_usage_plan_key(self, usage_plan_logical_id, create_usage_plan, api_key): """ :param usage_plan_logical_id: String :param create_usage_plan: String :param api_key: model.apigateway.ApiGatewayApiKey resource :return: model.apigateway.ApiGatewayUsagePlanKey resource that contains the mapping between usage plan and api key """ if create_usage_plan == "SHARED": # create a mapping between api key and the usage plan usage_plan_key_logical_id = "ServerlessUsagePlanKey" # for create_usage_plan = "PER_API" else: # create a mapping between api key and the usage plan usage_plan_key_logical_id = self.logical_id + "UsagePlanKey" usage_plan_key = ApiGatewayUsagePlanKey(logical_id=usage_plan_key_logical_id, depends_on=[api_key.logical_id]) usage_plan_key.KeyId = ref(api_key.logical_id) usage_plan_key.KeyType = "API_KEY" usage_plan_key.UsagePlanId = ref(usage_plan_logical_id) return usage_plan_key
class ApiGatewayV2HttpApi(Resource): resource_type = "AWS::ApiGatewayV2::Api" property_types = { "Body": PropertyType(False, is_type(dict)), "BodyS3Location": PropertyType(False, is_type(dict)), "Description": PropertyType(False, is_str()), "FailOnWarnings": PropertyType(False, is_type(bool)), "BasePath": PropertyType(False, is_str()), "CorsConfiguration": PropertyType(False, is_type(dict)), } runtime_attrs = {"http_api_id": lambda self: ref(self.logical_id)}
def _construct_basepath_mappings(self, basepaths, http_api): basepath_resource_list = [] if basepaths is None: basepath_mapping = ApiGatewayV2ApiMapping( self.logical_id + "ApiMapping", attributes=self.passthrough_resource_attributes ) basepath_mapping.DomainName = ref(self.domain.get("ApiDomainName")) basepath_mapping.ApiId = ref(http_api.logical_id) basepath_mapping.Stage = ref(http_api.logical_id + ".Stage") basepath_resource_list.extend([basepath_mapping]) else: for path in basepaths: # search for invalid characters in the path and raise error if there are invalid_regex = r"[^0-9a-zA-Z\/\-\_]+" if re.search(invalid_regex, path) is not None: raise InvalidResourceException(self.logical_id, "Invalid Basepath name provided.") # ignore leading and trailing `/` in the path name m = re.search(r"[a-zA-Z0-9]+[\-\_]?[a-zA-Z0-9]+", path) path = m.string[m.start(0) : m.end(0)] if path is None: raise InvalidResourceException(self.logical_id, "Invalid Basepath name provided.") logical_id = "{}{}{}".format(self.logical_id, re.sub(r"[\-\_]+", "", path), "ApiMapping") basepath_mapping = ApiGatewayV2ApiMapping(logical_id, attributes=self.passthrough_resource_attributes) basepath_mapping.DomainName = ref(self.domain.get("ApiDomainName")) basepath_mapping.ApiId = ref(http_api.logical_id) basepath_mapping.Stage = ref(http_api.logical_id + ".Stage") basepath_mapping.ApiMappingKey = path basepath_resource_list.extend([basepath_mapping]) return basepath_resource_list
def gen_skeleton(): """ Method to make an empty swagger file, with just some basic structure. Just enough to pass validator. :return dict: Dictionary of a skeleton swagger document """ return { 'swagger': '2.0', 'info': { 'version': '1.0', 'title': ref('AWS::StackName') }, 'paths': { } }
def to_cloudformation(self, **kwargs): """Returns the Lambda Permission resource allowing S3 to invoke the function this event source triggers. :param dict kwargs: S3 bucket resource :returns: a list of vanilla CloudFormation Resources, to which this S3 event expands :rtype: list """ function = kwargs.get('function') if not function: raise TypeError("Missing required keyword argument: function") if 'bucket' not in kwargs or kwargs['bucket'] is None: raise TypeError("Missing required keyword argument: bucket") if 'bucket_id' not in kwargs or kwargs['bucket_id'] is None: raise TypeError("Missing required keyword argument: bucket_id") bucket = kwargs['bucket'] bucket_id = kwargs['bucket_id'] resources = [] source_account = ref('AWS::AccountId') permission = self._construct_permission(function, source_account=source_account) if CONDITION in permission.resource_attributes: self._depend_on_lambda_permissions_using_tag(bucket, permission) else: self._depend_on_lambda_permissions(bucket, permission) resources.append(permission) # NOTE: `bucket` here is a dictionary representing the S3 Bucket resource in your SAM template. If there are # multiple S3 Events attached to the same bucket, we will update the Bucket resource with notification # configuration for each event. This is the reason why we continue to use existing bucket dict and append onto # it. # # NOTE: There is some fragile logic here where we will append multiple resources to output # SAM template but de-dupe them when merging into output CFN template. This is scary because the order of # merging is literally "last one wins", which works fine because we linearly loop through the template once. # The de-dupe happens inside `samtranslator.translator.Translator.translate` method when merging results of # to_cloudformation() to output template. self._inject_notification_configuration(function, bucket) resources.append(S3Bucket.from_dict(bucket_id, bucket)) return resources
def to_cloudformation(self, **kwargs): function = kwargs.get('function') if not function: raise TypeError("Missing required keyword argument: function") resources = [] resource = 'rule/${RuleName}' partition = ArnGenerator.get_partition_name() source_arn = fnSub(ArnGenerator.generate_arn(partition=partition, service='iot', resource=resource), {'RuleName': ref(self.logical_id)}) source_account = fnSub('${AWS::AccountId}') resources.append(self._construct_permission(function, source_arn=source_arn, source_account=source_account)) resources.append(self._construct_iot_rule(function)) return resources
def update_deployment_ref(self, deployment_logical_id): self.DeploymentId = ref(deployment_logical_id)