From b1d2bd906300aaabd5f4f1dad64d59a16077f8de Mon Sep 17 00:00:00 2001 From: Praneeta Date: Tue, 21 May 2019 15:18:49 -0700 Subject: [PATCH 01/13] Adding a global and Api flag called 'OpenApiVersion' https://sim.amazon.com/issues/Squirrel-496 --- docs/cloudformation_compatibility.rst | 1 + docs/globals.rst | 1 + samtranslator/model/api/api_generator.py | 5 ++++- samtranslator/model/apigateway.py | 3 ++- samtranslator/model/sam_resources.py | 6 ++++-- samtranslator/plugins/globals/globals.py | 3 ++- .../output/error_globals_api_with_stage_name.json | 4 ++-- 7 files changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/cloudformation_compatibility.rst b/docs/cloudformation_compatibility.rst index fcce6ef05..89daa985a 100644 --- a/docs/cloudformation_compatibility.rst +++ b/docs/cloudformation_compatibility.rst @@ -171,6 +171,7 @@ BinaryMediaTypes All MinimumCompressionSize All Cors All TracingEnabled All +OpenApiVersion All ================================== ======================== ======================== diff --git a/docs/globals.rst b/docs/globals.rst index c0878242e..c409da5f4 100644 --- a/docs/globals.rst +++ b/docs/globals.rst @@ -88,6 +88,7 @@ Currently, the following resources and properties are being supported: AccessLogSetting: CanarySetting: TracingEnabled: + OpenApiVersion: SimpleTable: # Properties of AWS::Serverless::SimpleTable diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 4946f4d92..b5616d237 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -31,7 +31,8 @@ def __init__(self, logical_id, cache_cluster_enabled, cache_cluster_size, variab definition_body, definition_uri, name, stage_name, endpoint_configuration=None, method_settings=None, binary_media=None, minimum_compression_size=None, cors=None, auth=None, gateway_responses=None, access_log_setting=None, canary_setting=None, - tracing_enabled=None, resource_attributes=None, passthrough_resource_attributes=None): + tracing_enabled=None, resource_attributes=None, passthrough_resource_attributes=None, + open_api_version=None): """Constructs an API Generator class that generates API Gateway resources :param logical_id: Logical id of the SAM API Resource @@ -70,6 +71,7 @@ def __init__(self, logical_id, cache_cluster_enabled, cache_cluster_size, variab self.tracing_enabled = tracing_enabled self.resource_attributes = resource_attributes self.passthrough_resource_attributes = passthrough_resource_attributes + self.open_api_version = open_api_version def _construct_rest_api(self): """Constructs and returns the ApiGateway RestApi. @@ -80,6 +82,7 @@ def _construct_rest_api(self): rest_api = ApiGatewayRestApi(self.logical_id, depends_on=self.depends_on, attributes=self.resource_attributes) rest_api.BinaryMediaTypes = self.binary_media rest_api.MinimumCompressionSize = self.minimum_compression_size + rest_api.OpenApiVersion = self.open_api_version if self.endpoint_configuration: self._set_endpoint_configuration(rest_api, self.endpoint_configuration) diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index c59983e19..abe1997f2 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -20,7 +20,8 @@ class ApiGatewayRestApi(Resource): 'Parameters': PropertyType(False, is_type(dict)), 'EndpointConfiguration': PropertyType(False, is_type(dict)), "BinaryMediaTypes": PropertyType(False, is_type(list)), - "MinimumCompressionSize": PropertyType(False, is_type(int)) + "MinimumCompressionSize": PropertyType(False, is_type(int)), + 'OpenApiVersion': PropertyType(False, is_str()) } runtime_attrs = { diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 66008dee5..778143b67 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -445,7 +445,8 @@ class SamApi(SamResourceMacro): 'GatewayResponses': PropertyType(False, is_type(dict)), 'AccessLogSetting': PropertyType(False, is_type(dict)), 'CanarySetting': PropertyType(False, is_type(dict)), - 'TracingEnabled': PropertyType(False, is_type(bool)) + 'TracingEnabled': PropertyType(False, is_type(bool)), + 'OpenApiVersion': PropertyType(False, is_str()) } referable_properties = { @@ -483,7 +484,8 @@ def to_cloudformation(self, **kwargs): canary_setting=self.CanarySetting, tracing_enabled=self.TracingEnabled, resource_attributes=self.resource_attributes, - passthrough_resource_attributes=self.get_passthrough_resource_attributes()) + passthrough_resource_attributes=self.get_passthrough_resource_attributes(), + open_api_version=self.OpenApiVersion) rest_api, deployment, stage, permissions = api_generator.to_cloudformation() diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index f74029b99..d53185c99 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -53,7 +53,8 @@ class Globals(object): "GatewayResponses", "AccessLogSetting", "CanarySetting", - "TracingEnabled" + "TracingEnabled", + "OpenApiVersion" ], SamResourceType.SimpleTable.value: [ diff --git a/tests/translator/output/error_globals_api_with_stage_name.json b/tests/translator/output/error_globals_api_with_stage_name.json index 899ef37ea..0b4d867ab 100644 --- a/tests/translator/output/error_globals_api_with_stage_name.json +++ b/tests/translator/output/error_globals_api_with_stage_name.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "'Globals' section is invalid. 'StageName' is not a supported property of 'Api'. Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting']" + "errorMessage": "'Globals' section is invalid. 'StageName' is not a supported property of 'Api'. Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting', 'OpenApiVersion']" } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'StageName' is not a supported property of 'Api'. Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'MinimumCompressionSize', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting', 'TracingEnabled']" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'StageName' is not a supported property of 'Api'. Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'MinimumCompressionSize', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting', 'TracingEnabled', 'OpenApiVersion']" } From 69db04176db6c539bec4cab9a6093ce08b9bd960 Mon Sep 17 00:00:00 2001 From: Praneeta Date: Tue, 21 May 2019 16:11:52 -0700 Subject: [PATCH 02/13] Basic test for OpenApiVersion flag to make sure the translator doesnt bail when it's defined https://sim.amazon.com/issues/Squirrel-496 --- samtranslator/model/api/api_generator.py | 1 - .../input/api_with_open_api_version.yaml | 24 +++ .../output/api_with_open_api_version.json | 174 ++++++++++++++++ .../aws-cn/api_with_open_api_version.json | 190 ++++++++++++++++++ .../aws-us-gov/api_with_open_api_version.json | 190 ++++++++++++++++++ tests/translator/test_translator.py | 1 + 6 files changed, 579 insertions(+), 1 deletion(-) create mode 100644 tests/translator/input/api_with_open_api_version.yaml create mode 100644 tests/translator/output/api_with_open_api_version.json create mode 100644 tests/translator/output/aws-cn/api_with_open_api_version.json create mode 100644 tests/translator/output/aws-us-gov/api_with_open_api_version.json diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index b5616d237..36d3cb017 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -82,7 +82,6 @@ def _construct_rest_api(self): rest_api = ApiGatewayRestApi(self.logical_id, depends_on=self.depends_on, attributes=self.resource_attributes) rest_api.BinaryMediaTypes = self.binary_media rest_api.MinimumCompressionSize = self.minimum_compression_size - rest_api.OpenApiVersion = self.open_api_version if self.endpoint_configuration: self._set_endpoint_configuration(rest_api, self.endpoint_configuration) diff --git a/tests/translator/input/api_with_open_api_version.yaml b/tests/translator/input/api_with_open_api_version.yaml new file mode 100644 index 000000000..d0b53c3b6 --- /dev/null +++ b/tests/translator/input/api_with_open_api_version.yaml @@ -0,0 +1,24 @@ +Globals: + Api: + OpenApiVersion: '3.0' + +Resources: + ImplicitApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs8.10 + Events: + GetHtml: + Type: Api + Properties: + Path: / + Method: get + + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionUri: s3://sam-demo-bucket/webpage_swagger.json + OpenApiVersion: '3.0' diff --git a/tests/translator/output/api_with_open_api_version.json b/tests/translator/output/api_with_open_api_version.json new file mode 100644 index 000000000..1892023ef --- /dev/null +++ b/tests/translator/output/api_with_open_api_version.json @@ -0,0 +1,174 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ExplicitApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment62b96c1a61" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment62b96c1a61": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 62b96c1a611878eefb13e8ef66dbc71b9ba3dd19", + "StageName": "Stage" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0" + } + } + } + } + } \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_open_api_version.json b/tests/translator/output/aws-cn/api_with_open_api_version.json new file mode 100644 index 000000000..42ceb3026 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_open_api_version.json @@ -0,0 +1,190 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentcb4fb12558" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeploymentcb4fb12558": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: cb4fb1255811b7b6a25dd35f23ee7ad133003b89", + "StageName": "Stage" + } + }, + "ExplicitApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_open_api_version.json b/tests/translator/output/aws-us-gov/api_with_open_api_version.json new file mode 100644 index 000000000..0ae755c5e --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_open_api_version.json @@ -0,0 +1,190 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment5b2cb4ba8f": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 5b2cb4ba8fce8a9445b1914c6c6fbeef81a9075a", + "StageName": "Stage" + } + }, + "ExplicitApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment5b2cb4ba8f" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 6e1afe56b..43e8702ae 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -191,6 +191,7 @@ class TestTranslatorEndToEnd(TestCase): 'api_with_gateway_responses_minimal', 'api_with_gateway_responses_implicit', 'api_with_gateway_responses_string_status_code', + 'api_with_open_api_version', 'api_cache', 'api_with_access_log_setting', 'api_with_canary_setting', From 8ef6a9ef64cf30f837f89e78d78b01337dd2fea7 Mon Sep 17 00:00:00 2001 From: Praneeta Date: Tue, 21 May 2019 22:07:02 -0700 Subject: [PATCH 03/13] Remove the stage stage bug issue https://github.com/awslabs/serverless-application-model/issues/191 sim https://sim.amazon.com/issues/Squirrel-496 --- samtranslator/model/api/api_generator.py | 13 +++-- samtranslator/model/apigateway.py | 4 +- .../input/api_with_open_api_version.yaml | 9 +--- ...ror_api_with_invalid_open_api_version.yaml | 21 ++++++++ .../output/api_with_open_api_version.json | 40 ++-------------- .../aws-cn/api_with_open_api_version.json | 42 +--------------- .../aws-us-gov/api_with_open_api_version.json | 48 ++----------------- ...ror_api_with_invalid_open_api_version.json | 8 ++++ tests/translator/test_translator.py | 1 + 9 files changed, 52 insertions(+), 134 deletions(-) create mode 100644 tests/translator/input/error_api_with_invalid_open_api_version.yaml create mode 100644 tests/translator/output/error_api_with_invalid_open_api_version.json diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 36d3cb017..99d27d447 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -16,6 +16,7 @@ _CORS_WILDCARD = "'*'" CorsProperties = namedtuple("_CorsProperties", ["AllowMethods", "AllowHeaders", "AllowOrigin", "MaxAge", "AllowCredentials"]) + # Default the Cors Properties to '*' wildcard and False AllowCredentials. Other properties are actually Optional CorsProperties.__new__.__defaults__ = (None, None, _CORS_WILDCARD, None, False) @@ -23,6 +24,7 @@ AuthProperties.__new__.__defaults__ = (None, None, None) GatewayResponseProperties = ["ResponseParameters", "ResponseTemplates", "StatusCode"] +OpenApiVersionsSupported = ["2.0", "3.0"] class ApiGenerator(object): @@ -95,6 +97,10 @@ def _construct_rest_api(self): raise InvalidResourceException(self.logical_id, "Specify either 'DefinitionUri' or 'DefinitionBody' property and not both") + if self.open_api_version and self.open_api_version not in OpenApiVersionsSupported: + raise InvalidResourceException(self.logical_id, + "The OpenApiVersion value must be one of [2.0, 3.0]") + self._add_cors() self._add_auth() self._add_gateway_responses() @@ -139,7 +145,7 @@ def _construct_body_s3_dict(self): body_s3['Version'] = s3_pointer['Version'] return body_s3 - def _construct_deployment(self, rest_api): + def _construct_deployment(self, rest_api, open_api_version): """Constructs and returns the ApiGateway Deployment. :param model.apigateway.ApiGatewayRestApi rest_api: the RestApi for this Deployment @@ -149,7 +155,8 @@ def _construct_deployment(self, rest_api): deployment = ApiGatewayDeployment(self.logical_id + 'Deployment', attributes=self.passthrough_resource_attributes) deployment.RestApiId = rest_api.get_runtime_attr('rest_api_id') - deployment.StageName = 'Stage' + if not self.open_api_version: + deployment.StageName = 'Stage' return deployment @@ -191,7 +198,7 @@ def to_cloudformation(self): """ rest_api = self._construct_rest_api() - deployment = self._construct_deployment(rest_api) + deployment = self._construct_deployment(rest_api, self.open_api_version) swagger = None if rest_api.Body is not None: diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index abe1997f2..edfa9f115 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -40,7 +40,7 @@ class ApiGatewayStage(Resource): 'DeploymentId': PropertyType(True, is_str()), 'Description': PropertyType(False, is_str()), 'RestApiId': PropertyType(True, is_str()), - 'StageName': PropertyType(True, one_of(is_str(), is_type(dict))), + 'StageName': PropertyType(False, one_of(is_str(), is_type(dict))), 'TracingEnabled': PropertyType(False, is_type(bool)), 'Variables': PropertyType(False, is_type(dict)), "MethodSettings": PropertyType(False, is_type(list)) @@ -67,7 +67,7 @@ class ApiGatewayDeployment(Resource): 'Description': PropertyType(False, is_str()), 'RestApiId': PropertyType(True, is_str()), 'StageDescription': PropertyType(False, is_type(dict)), - 'StageName': PropertyType(True, is_str()) + 'StageName': PropertyType(False, is_str()) } runtime_attrs = { diff --git a/tests/translator/input/api_with_open_api_version.yaml b/tests/translator/input/api_with_open_api_version.yaml index d0b53c3b6..1590b2d48 100644 --- a/tests/translator/input/api_with_open_api_version.yaml +++ b/tests/translator/input/api_with_open_api_version.yaml @@ -14,11 +14,4 @@ Resources: Type: Api Properties: Path: / - Method: get - - ExplicitApi: - Type: AWS::Serverless::Api - Properties: - StageName: Prod - DefinitionUri: s3://sam-demo-bucket/webpage_swagger.json - OpenApiVersion: '3.0' + Method: get \ No newline at end of file diff --git a/tests/translator/input/error_api_with_invalid_open_api_version.yaml b/tests/translator/input/error_api_with_invalid_open_api_version.yaml new file mode 100644 index 000000000..f7fcb13c1 --- /dev/null +++ b/tests/translator/input/error_api_with_invalid_open_api_version.yaml @@ -0,0 +1,21 @@ +Resources: + MyApi: + Type: AWS::Serverless::Api + Properties: + DefinitionBody: {} + OpenApiVersion: '5.0' + StageName: 'prod' + Function: + Type: AWS::Serverless::Function + Properties: + Handler: lambda.handler + CodeUri: s3://bucket/api + Runtime: nodejs8.10 + Events: + ProxyApiRoot: + Type: Api + Properties: + RestApiId: + Ref: MyApi + Path: "/" + Method: ANY diff --git a/tests/translator/output/api_with_open_api_version.json b/tests/translator/output/api_with_open_api_version.json index 1892023ef..88f37ef82 100644 --- a/tests/translator/output/api_with_open_api_version.json +++ b/tests/translator/output/api_with_open_api_version.json @@ -47,16 +47,6 @@ } } }, - "ExplicitApiDeploymentf117c932f7": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", - "StageName": "Stage" - } - }, "ImplicitApiFunctionGetHtmlPermissionTest": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -99,25 +89,13 @@ } } }, - "ExplicitApi": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "BodyS3Location": { - "Bucket": "sam-demo-bucket", - "Key": "webpage_swagger.json" - } - } - }, - "ExplicitApiProdStage": { - "Type": "AWS::ApiGateway::Stage", + "ServerlessRestApiDeployment62b96c1a61": { + "Type": "AWS::ApiGateway::Deployment", "Properties": { - "DeploymentId": { - "Ref": "ExplicitApiDeploymentf117c932f7" - }, "RestApiId": { - "Ref": "ExplicitApi" + "Ref": "ServerlessRestApi" }, - "StageName": "Prod" + "Description": "RestApi deployment id: 62b96c1a611878eefb13e8ef66dbc71b9ba3dd19" } }, "ServerlessRestApiProdStage": { @@ -132,16 +110,6 @@ "StageName": "Prod" } }, - "ServerlessRestApiDeployment62b96c1a61": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: 62b96c1a611878eefb13e8ef66dbc71b9ba3dd19", - "StageName": "Stage" - } - }, "ServerlessRestApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { diff --git a/tests/translator/output/aws-cn/api_with_open_api_version.json b/tests/translator/output/aws-cn/api_with_open_api_version.json index 42ceb3026..0e8160881 100644 --- a/tests/translator/output/aws-cn/api_with_open_api_version.json +++ b/tests/translator/output/aws-cn/api_with_open_api_version.json @@ -89,35 +89,6 @@ } } }, - "ExplicitApi": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "EndpointConfiguration": { - "Types": [ - "REGIONAL" - ] - }, - "BodyS3Location": { - "Bucket": "sam-demo-bucket", - "Key": "webpage_swagger.json" - }, - "Parameters": { - "endpointConfigurationTypes": "REGIONAL" - } - } - }, - "ExplicitApiProdStage": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "DeploymentId": { - "Ref": "ExplicitApiDeploymentf117c932f7" - }, - "RestApiId": { - "Ref": "ExplicitApi" - }, - "StageName": "Prod" - } - }, "ServerlessRestApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { @@ -136,18 +107,7 @@ "RestApiId": { "Ref": "ServerlessRestApi" }, - "Description": "RestApi deployment id: cb4fb1255811b7b6a25dd35f23ee7ad133003b89", - "StageName": "Stage" - } - }, - "ExplicitApiDeploymentf117c932f7": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", - "StageName": "Stage" + "Description": "RestApi deployment id: cb4fb1255811b7b6a25dd35f23ee7ad133003b89" } }, "ServerlessRestApi": { diff --git a/tests/translator/output/aws-us-gov/api_with_open_api_version.json b/tests/translator/output/aws-us-gov/api_with_open_api_version.json index 0ae755c5e..8807293e8 100644 --- a/tests/translator/output/aws-us-gov/api_with_open_api_version.json +++ b/tests/translator/output/aws-us-gov/api_with_open_api_version.json @@ -89,31 +89,14 @@ } } }, - "ExplicitApi": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "EndpointConfiguration": { - "Types": [ - "REGIONAL" - ] - }, - "BodyS3Location": { - "Bucket": "sam-demo-bucket", - "Key": "webpage_swagger.json" - }, - "Parameters": { - "endpointConfigurationTypes": "REGIONAL" - } - } - }, - "ExplicitApiProdStage": { + "ServerlessRestApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeploymentf117c932f7" + "Ref": "ServerlessRestApiDeployment5b2cb4ba8f" }, "RestApiId": { - "Ref": "ExplicitApi" + "Ref": "ServerlessRestApi" }, "StageName": "Prod" } @@ -124,30 +107,7 @@ "RestApiId": { "Ref": "ServerlessRestApi" }, - "Description": "RestApi deployment id: 5b2cb4ba8fce8a9445b1914c6c6fbeef81a9075a", - "StageName": "Stage" - } - }, - "ExplicitApiDeploymentf117c932f7": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", - "StageName": "Stage" - } - }, - "ServerlessRestApiProdStage": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "DeploymentId": { - "Ref": "ServerlessRestApiDeployment5b2cb4ba8f" - }, - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "StageName": "Prod" + "Description": "RestApi deployment id: 5b2cb4ba8fce8a9445b1914c6c6fbeef81a9075a" } }, "ServerlessRestApi": { diff --git a/tests/translator/output/error_api_with_invalid_open_api_version.json b/tests/translator/output/error_api_with_invalid_open_api_version.json new file mode 100644 index 000000000..36478c832 --- /dev/null +++ b/tests/translator/output/error_api_with_invalid_open_api_version.json @@ -0,0 +1,8 @@ +{ + "errors": [ + { + "errorMessage": "Resource with id [MyApi] is invalid. The OpenApiVersion value must be one of [2.0, 3.0]" + } + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyApi] is invalid. The OpenApiVersion value must be one of [2.0, 3.0]" + } \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 43e8702ae..4591ad9fd 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -394,6 +394,7 @@ def _generate_new_deployment_hash(self, logical_id, dict_to_hash, rest_api_to_sw 'error_api_invalid_definitionuri', 'error_api_invalid_definitionbody', 'error_api_invalid_stagename', + 'error_api_with_invalid_open_api_version', 'error_api_invalid_restapiid', 'error_application_properties', 'error_application_does_not_exist', From 6f902137f8e28f995d961136367ef39d357f30f1 Mon Sep 17 00:00:00 2001 From: praneetap Date: Wed, 22 May 2019 22:50:02 -0700 Subject: [PATCH 04/13] Adding Globals preprocessing for OpenApiVersion 3 support. --- samtranslator/plugins/globals/globals.py | 18 ++ .../plugins/globals/globals_plugin.py | 6 + .../input/api_with_open_api_version.yaml | 4 +- .../output/api_with_open_api_version.json | 294 ++++++++++-------- .../aws-cn/api_with_open_api_version.json | 50 ++- .../aws-us-gov/api_with_open_api_version.json | 64 +++- 6 files changed, 291 insertions(+), 145 deletions(-) diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index d53185c99..6d99c3436 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -11,6 +11,8 @@ class Globals(object): # Key of the dictionary containing Globals section in SAM template _KEYWORD = "Globals" _RESOURCE_PREFIX = "AWS::Serverless::" + _OPENAPIVERSION = "OpenApiVersion" + _API_TYPE = "AWS::Serverless::Api" supported_properties = { # Everything on Serverless::Function except Role, Policies, FunctionName, Events @@ -108,6 +110,22 @@ def del_section(cls, template): if cls._KEYWORD in template: del template[cls._KEYWORD] + @classmethod + def fix_openapi_definitions(cls, template): + """ + """ + resources = template["Resources"] + + for _, resource in resources.items(): + if resource["Type"] == "AWS::Serverless::Api": + properties = resource["Properties"] + if cls._OPENAPIVERSION in properties: + if properties[cls._OPENAPIVERSION] == "3.0": + definition_body = properties['DefinitionBody'] + definition_body['openapi'] = "3.0" + if definition_body.get('swagger'): + del definition_body['swagger'] + def _parse(self, globals_dict): """ Takes a SAM template as input and parses the Globals section diff --git a/samtranslator/plugins/globals/globals_plugin.py b/samtranslator/plugins/globals/globals_plugin.py index 086bfb81b..3c4872773 100644 --- a/samtranslator/plugins/globals/globals_plugin.py +++ b/samtranslator/plugins/globals/globals_plugin.py @@ -5,6 +5,8 @@ from samtranslator.plugins.globals.globals import Globals, InvalidGlobalsSectionException +_API_RESOURCE = "AWS::Serverless::Api" + class GlobalsPlugin(BasePlugin): """ @@ -38,3 +40,7 @@ def on_before_transform_template(self, template_dict): # Remove the Globals section from template if necessary Globals.del_section(template_dict) + + # If there was a global openApiVersion flag, check and convert swagger + # to the right version + Globals.fix_openapi_definitions(template_dict) diff --git a/tests/translator/input/api_with_open_api_version.yaml b/tests/translator/input/api_with_open_api_version.yaml index 1590b2d48..84584ecca 100644 --- a/tests/translator/input/api_with_open_api_version.yaml +++ b/tests/translator/input/api_with_open_api_version.yaml @@ -1,6 +1,7 @@ Globals: Api: OpenApiVersion: '3.0' + Cors: '*' Resources: ImplicitApiFunction: @@ -14,4 +15,5 @@ Resources: Type: Api Properties: Path: / - Method: get \ No newline at end of file + Method: get + \ No newline at end of file diff --git a/tests/translator/output/api_with_open_api_version.json b/tests/translator/output/api_with_open_api_version.json index 88f37ef82..5571da894 100644 --- a/tests/translator/output/api_with_open_api_version.json +++ b/tests/translator/output/api_with_open_api_version.json @@ -1,142 +1,182 @@ { - "Resources": { - "ImplicitApiFunction": { - "Type": "AWS::Lambda::Function", - "Properties": { - "Handler": "index.gethtml", - "Code": { - "S3Bucket": "sam-demo-bucket", - "S3Key": "member_portal.zip" - }, - "Role": { - "Fn::GetAtt": [ - "ImplicitApiFunctionRole", - "Arn" - ] - }, - "Runtime": "nodejs8.10", - "Tags": [ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ { - "Value": "SAM", - "Key": "lambda:createdBy" + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } } ] } - }, - "ImplicitApiFunctionRole": { - "Type": "AWS::IAM::Role", - "Properties": { - "ManagedPolicyArns": [ - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], - "AssumeRolePolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Action": [ - "sts:AssumeRole" - ], - "Effect": "Allow", - "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] - } - } - ] - } - } - }, - "ImplicitApiFunctionGetHtmlPermissionTest": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": { - "Ref": "ImplicitApiFunction" - }, - "SourceArn": { - "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", - { - "__Stage__": "*", - "__ApiId__": { - "Ref": "ServerlessRestApi" - } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" } - ] - } + } + ] } - }, - "ImplicitApiFunctionGetHtmlPermissionProd": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "Action": "lambda:invokeFunction", - "Principal": "apigateway.amazonaws.com", - "FunctionName": { - "Ref": "ImplicitApiFunction" - }, - "SourceArn": { - "Fn::Sub": [ - "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", - { - "__Stage__": "Prod", - "__ApiId__": { - "Ref": "ServerlessRestApi" - } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" } - ] - } - } - }, - "ServerlessRestApiDeployment62b96c1a61": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: 62b96c1a611878eefb13e8ef66dbc71b9ba3dd19" + } + ] } - }, - "ServerlessRestApiProdStage": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "DeploymentId": { - "Ref": "ServerlessRestApiDeployment62b96c1a61" - }, - "RestApiId": { - "Ref": "ServerlessRestApi" + } + }, + "ServerlessRestApiDeploymentc3856307e4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: c3856307e48020ec37335539fec71b67bfdeaff6" + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentc3856307e4" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } }, - "StageName": "Prod" - } - }, - "ServerlessRestApi": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "Body": { - "info": { - "version": "1.0", - "title": { - "Ref": "AWS::StackName" - } - }, - "paths": { - "/": { - "get": { - "x-amazon-apigateway-integration": { - "httpMethod": "POST", - "type": "aws_proxy", - "uri": { - "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" - } + "paths": { + "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" }, - "responses": {} - } + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": "*", + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} } - }, - "swagger": "2.0" - } + } + }, + "openapi": "3.0" } } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_open_api_version.json b/tests/translator/output/aws-cn/api_with_open_api_version.json index 0e8160881..5a713d6ae 100644 --- a/tests/translator/output/aws-cn/api_with_open_api_version.json +++ b/tests/translator/output/aws-cn/api_with_open_api_version.json @@ -93,7 +93,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeploymentcb4fb12558" + "Ref": "ServerlessRestApiDeploymentaada0b6533" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -101,13 +101,13 @@ "StageName": "Prod" } }, - "ServerlessRestApiDeploymentcb4fb12558": { + "ServerlessRestApiDeploymentaada0b6533": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { "Ref": "ServerlessRestApi" }, - "Description": "RestApi deployment id: cb4fb1255811b7b6a25dd35f23ee7ad133003b89" + "Description": "RestApi deployment id: aada0b6533734d1934b71842c2828f111d441fc1" } }, "ServerlessRestApi": { @@ -122,6 +122,46 @@ }, "paths": { "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": "*", + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, "get": { "x-amazon-apigateway-integration": { "httpMethod": "POST", @@ -134,7 +174,7 @@ } } }, - "swagger": "2.0" + "openapi": "3.0" }, "EndpointConfiguration": { "Types": [ @@ -147,4 +187,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/api_with_open_api_version.json b/tests/translator/output/aws-us-gov/api_with_open_api_version.json index 8807293e8..815ac7ac0 100644 --- a/tests/translator/output/aws-us-gov/api_with_open_api_version.json +++ b/tests/translator/output/aws-us-gov/api_with_open_api_version.json @@ -47,6 +47,15 @@ } } }, + "ServerlessRestApiDeployment9bdc4ed430": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 9bdc4ed430c09a5c332bdd62654d27d54fd60001" + } + }, "ImplicitApiFunctionGetHtmlPermissionTest": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -93,7 +102,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeployment5b2cb4ba8f" + "Ref": "ServerlessRestApiDeployment9bdc4ed430" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -101,15 +110,6 @@ "StageName": "Prod" } }, - "ServerlessRestApiDeployment5b2cb4ba8f": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: 5b2cb4ba8fce8a9445b1914c6c6fbeef81a9075a" - } - }, "ServerlessRestApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -122,6 +122,46 @@ }, "paths": { "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": "*", + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, "get": { "x-amazon-apigateway-integration": { "httpMethod": "POST", @@ -134,7 +174,7 @@ } } }, - "swagger": "2.0" + "openapi": "3.0" }, "EndpointConfiguration": { "Types": [ @@ -147,4 +187,4 @@ } } } -} \ No newline at end of file +} From 190bdb61a5cd691fc9c65e31de81d2c6d9d967b0 Mon Sep 17 00:00:00 2001 From: praneetap Date: Wed, 22 May 2019 22:51:34 -0700 Subject: [PATCH 05/13] [OAS3] Removing swagger changes in favor of postprocessing in globals plugin --- samtranslator/plugins/globals/globals.py | 6 +-- samtranslator/swagger/swagger.py | 2 +- tests/swagger/test_swagger.py | 28 ++++++++++++ .../input/api_with_open_api_version.yaml | 5 ++- .../output/api_with_open_api_version.json | 38 +++++++++++++++- .../aws-cn/api_with_open_api_version.json | 44 +++++++++++++++++++ .../aws-us-gov/api_with_open_api_version.json | 44 +++++++++++++++++++ 7 files changed, 161 insertions(+), 6 deletions(-) diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 6d99c3436..222d4845c 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -117,10 +117,10 @@ def fix_openapi_definitions(cls, template): resources = template["Resources"] for _, resource in resources.items(): - if resource["Type"] == "AWS::Serverless::Api": + if ("Type" in resource) and (resource["Type"] == "AWS::Serverless::Api"): properties = resource["Properties"] - if cls._OPENAPIVERSION in properties: - if properties[cls._OPENAPIVERSION] == "3.0": + if (cls._OPENAPIVERSION in properties) and (properties[cls._OPENAPIVERSION] == "3.0"): + if "DefinitionBody" in properties: definition_body = properties['DefinitionBody'] definition_body['openapi'] = "3.0" if definition_body.get('swagger'): diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index dc9549285..c9b458751 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -556,7 +556,7 @@ def is_valid(data): """ return bool(data) and \ isinstance(data, dict) and \ - bool(data.get("swagger")) and \ + (bool(data.get("swagger")) or bool(data.get("openapi"))) and \ isinstance(data.get('paths'), dict) @staticmethod diff --git a/tests/swagger/test_swagger.py b/tests/swagger/test_swagger.py index 388209213..7aefa5b5b 100644 --- a/tests/swagger/test_swagger.py +++ b/tests/swagger/test_swagger.py @@ -33,6 +33,34 @@ def test_must_succeed_on_valid_swagger(self): self.assertEqual(editor.paths, {"/foo": {}, "/bar": {}}) + def test_must_succeed_on_valid_openapi(self): + valid_swagger = { + "openapi": "2.0", + "paths": { + "/foo": {}, + "/bar": {} + } + } + + editor = SwaggerEditor(valid_swagger) + self.assertIsNotNone(editor) + + self.assertEqual(editor.paths, {"/foo": {}, "/bar": {}}) + + def test_must_succeed_on_valid_openapi3(self): + valid_swagger = { + "openapi": "3.0", + "paths": { + "/foo": {}, + "/bar": {} + } + } + + editor = SwaggerEditor(valid_swagger) + self.assertIsNotNone(editor) + + self.assertEqual(editor.paths, {"/foo": {}, "/bar": {}}) + class TestSwaggerEditor_has_path(TestCase): diff --git a/tests/translator/input/api_with_open_api_version.yaml b/tests/translator/input/api_with_open_api_version.yaml index 84584ecca..ffa31e09a 100644 --- a/tests/translator/input/api_with_open_api_version.yaml +++ b/tests/translator/input/api_with_open_api_version.yaml @@ -16,4 +16,7 @@ Resources: Properties: Path: / Method: get - \ No newline at end of file + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod diff --git a/tests/translator/output/api_with_open_api_version.json b/tests/translator/output/api_with_open_api_version.json index 5571da894..a4b0b0884 100644 --- a/tests/translator/output/api_with_open_api_version.json +++ b/tests/translator/output/api_with_open_api_version.json @@ -98,6 +98,33 @@ "Description": "RestApi deployment id: c3856307e48020ec37335539fec71b67bfdeaff6" } }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "openapi": "3.0" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment783c7f37fe" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, "ServerlessRestApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { @@ -110,6 +137,15 @@ "StageName": "Prod" } }, + "ExplicitApiDeployment783c7f37fe": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 783c7f37fe04219a0cd2252fd5e83d4d48836e50" + } + }, "ServerlessRestApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -179,4 +215,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-cn/api_with_open_api_version.json b/tests/translator/output/aws-cn/api_with_open_api_version.json index 5a713d6ae..25c5a3770 100644 --- a/tests/translator/output/aws-cn/api_with_open_api_version.json +++ b/tests/translator/output/aws-cn/api_with_open_api_version.json @@ -89,6 +89,41 @@ } } }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment783c7f37fe" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, "ServerlessRestApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { @@ -101,6 +136,15 @@ "StageName": "Prod" } }, + "ExplicitApiDeployment783c7f37fe": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 783c7f37fe04219a0cd2252fd5e83d4d48836e50" + } + }, "ServerlessRestApiDeploymentaada0b6533": { "Type": "AWS::ApiGateway::Deployment", "Properties": { diff --git a/tests/translator/output/aws-us-gov/api_with_open_api_version.json b/tests/translator/output/aws-us-gov/api_with_open_api_version.json index 815ac7ac0..8ea0d739c 100644 --- a/tests/translator/output/aws-us-gov/api_with_open_api_version.json +++ b/tests/translator/output/aws-us-gov/api_with_open_api_version.json @@ -98,6 +98,41 @@ } } }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment783c7f37fe" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, "ServerlessRestApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { @@ -110,6 +145,15 @@ "StageName": "Prod" } }, + "ExplicitApiDeployment783c7f37fe": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 783c7f37fe04219a0cd2252fd5e83d4d48836e50" + } + }, "ServerlessRestApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { From 3a3170a10717edbddcac0090c0e5d404da1e8275 Mon Sep 17 00:00:00 2001 From: praneetap Date: Thu, 23 May 2019 17:42:54 -0700 Subject: [PATCH 06/13] Added some tests and cleanup --- samtranslator/model/api/api_generator.py | 1 - samtranslator/plugins/globals/globals.py | 5 + samtranslator/swagger/swagger.py | 11 +- tests/model/test_sam_resources.py | 51 +++++++++ tests/plugins/globals/test_globals.py | 126 +++++++++++++++++++++++ tests/swagger/test_swagger.py | 12 +-- 6 files changed, 194 insertions(+), 12 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 99d27d447..ee386b5e6 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -16,7 +16,6 @@ _CORS_WILDCARD = "'*'" CorsProperties = namedtuple("_CorsProperties", ["AllowMethods", "AllowHeaders", "AllowOrigin", "MaxAge", "AllowCredentials"]) - # Default the Cors Properties to '*' wildcard and False AllowCredentials. Other properties are actually Optional CorsProperties.__new__.__defaults__ = (None, None, _CORS_WILDCARD, None, False) diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 222d4845c..ec03a56de 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -113,6 +113,11 @@ def del_section(cls, template): @classmethod def fix_openapi_definitions(cls, template): """ + Helper method to postprocess the resources to make sure the swagger doc version matches + the one specified on the resource with flag OpenApiVersion + + :param dict template: SAM template + :return: Modified SAM template with corrected swagger doc matching the OpenApiVersion. """ resources = template["Resources"] diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index c9b458751..bb2439000 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -554,10 +554,13 @@ def is_valid(data): :param dict data: Data to be validated :return: True, if data is a Swagger """ - return bool(data) and \ - isinstance(data, dict) and \ - (bool(data.get("swagger")) or bool(data.get("openapi"))) and \ - isinstance(data.get('paths'), dict) + if bool(data) and isinstance(data, dict) and isinstance(data.get('paths'), dict): + if bool(data.get("swagger")): + return True + elif bool(data.get("openapi")): + return "3.0" in data["openapi"] + return False + return False @staticmethod def gen_skeleton(): diff --git a/tests/model/test_sam_resources.py b/tests/model/test_sam_resources.py index 73cfdd263..ff59a063e 100644 --- a/tests/model/test_sam_resources.py +++ b/tests/model/test_sam_resources.py @@ -5,7 +5,10 @@ from samtranslator.intrinsics.resolver import IntrinsicsResolver from samtranslator.model import InvalidResourceException from samtranslator.model.lambda_ import LambdaFunction, LambdaVersion +from samtranslator.model.apigateway import ApiGatewayRestApi +from samtranslator.model.apigateway import ApiGatewayDeployment from samtranslator.model.sam_resources import SamFunction +from samtranslator.model.sam_resources import SamApi class TestCodeUri(TestCase): @@ -70,3 +73,51 @@ def test_with_version_description(self): cfnResources = function.to_cloudformation(**self.kwargs) generateFunctionVersion = [x for x in cfnResources if isinstance(x, LambdaVersion)] self.assertEqual(generateFunctionVersion[0].Description, test_description) + +class TestOpenApi(TestCase): + kwargs = { + 'intrinsics_resolver': IntrinsicsResolver({}), + 'event_resources': [], + 'managed_policy_map': { + "foo": "bar" + } + } + + @patch('boto3.session.Session.region_name', 'ap-southeast-1') + def test_with_open_api_3_no_stage(self): + api = SamApi("foo") + api.OpenApiVersion = "3.0" + + resources = api.to_cloudformation(**self.kwargs) + deployment = [x for x in resources if isinstance(x, ApiGatewayDeployment)] + + self.assertEqual(deployment.__len__(), 1) + self.assertEqual(deployment[0].StageName, None) + + @patch('boto3.session.Session.region_name', 'ap-southeast-1') + def test_with_open_api_2_no_stage(self): + api = SamApi("foo") + api.OpenApiVersion = "3.0" + + resources = api.to_cloudformation(**self.kwargs) + deployment = [x for x in resources if isinstance(x, ApiGatewayDeployment)] + + self.assertEqual(deployment.__len__(), 1) + self.assertEqual(deployment[0].StageName, None) + + @patch('boto3.session.Session.region_name', 'ap-southeast-1') + def test_with_open_api_bad_value(self): + api = SamApi("foo") + api.OpenApiVersion = "5.0" + with pytest.raises(InvalidResourceException): + api.to_cloudformation(**self.kwargs) + + @patch('boto3.session.Session.region_name', 'ap-southeast-1') + def test_with_swagger_no_stage(self): + api = SamApi("foo") + + resources = api.to_cloudformation(**self.kwargs) + deployment = [x for x in resources if isinstance(x, ApiGatewayDeployment)] + + self.assertEqual(deployment.__len__(), 1) + self.assertEqual(deployment[0].StageName, "Stage") diff --git a/tests/plugins/globals/test_globals.py b/tests/plugins/globals/test_globals.py index 00e30fbb5..19b0c4dd0 100644 --- a/tests/plugins/globals/test_globals.py +++ b/tests/plugins/globals/test_globals.py @@ -657,3 +657,129 @@ def test_merge_end_to_end_unknown_type(self): result = globals.merge(type, properties) self.assertEqual(expected, result) + +class TestGlobalsOpenApi(TestCase): + template = { + "Globals": { + "Api": { + "OpenApiVersion": "3.0" + } + } + } + + table_driven = [ + { + "name": "happy case", + "input": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "3.0", + "DefinitionBody": { + "swagger": "2.0" + } + } + } + } + }, + "expected": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "3.0", + "DefinitionBody": { + "openapi": "3.0" + } + } + } + } + } + }, + { + "name": "no openapi", + "input": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "DefinitionBody": { + "swagger": "2.0" + } + } + } + } + }, + "expected": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "DefinitionBody": { + "swagger": "2.0" + } + } + } + } + } + }, + { + "name": "Openapi set to 2.0", + "input": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "2.0", + "DefinitionBody": { + "swagger": "2.0" + } + } + } + } + }, + "expected": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "2.0", + "DefinitionBody": { + "swagger": "2.0" + } + } + } + } + } + }, + { + "name": "No definition body", + "input": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "3.0" + } + } + } + }, + "expected": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "3.0" + } + } + } + } + } + ] + + def test_openapi_postprocess(self): + for test in self.table_driven: + global_obj = Globals(self.template) + global_obj.fix_openapi_definitions(test["input"]) + self.assertEqual(test["input"], test["expected"], test["name"]) diff --git a/tests/swagger/test_swagger.py b/tests/swagger/test_swagger.py index 7aefa5b5b..223e2b045 100644 --- a/tests/swagger/test_swagger.py +++ b/tests/swagger/test_swagger.py @@ -33,8 +33,8 @@ def test_must_succeed_on_valid_swagger(self): self.assertEqual(editor.paths, {"/foo": {}, "/bar": {}}) - def test_must_succeed_on_valid_openapi(self): - valid_swagger = { + def test_must_fail_on_invalid_openapi_version(self): + invalid_swagger = { "openapi": "2.0", "paths": { "/foo": {}, @@ -42,14 +42,12 @@ def test_must_succeed_on_valid_openapi(self): } } - editor = SwaggerEditor(valid_swagger) - self.assertIsNotNone(editor) - - self.assertEqual(editor.paths, {"/foo": {}, "/bar": {}}) + with self.assertRaises(ValueError): + SwaggerEditor(invalid_swagger) def test_must_succeed_on_valid_openapi3(self): valid_swagger = { - "openapi": "3.0", + "openapi": "3.0.1", "paths": { "/foo": {}, "/bar": {} From d8ddfab0f5b31d932de0cb170bdf95084bc1b393 Mon Sep 17 00:00:00 2001 From: praneetap Date: Thu, 23 May 2019 17:42:54 -0700 Subject: [PATCH 07/13] Added some tests and cleanup --- .../input/api_with_cors_openapi_3.yaml | 82 +++ ..._with_gateway_responses_all_openapi_3.yaml | 38 ++ .../output/api_with_cors_openapi_3.json | 543 +++++++++++++++++ ..._with_gateway_responses_all_openapi_3.json | 162 +++++ .../aws-cn/api_with_cors_openapi_3.json | 559 ++++++++++++++++++ ..._with_gateway_responses_all_openapi_3.json | 170 ++++++ .../aws-us-gov/api_with_cors_openapi_3.json | 559 ++++++++++++++++++ ..._with_gateway_responses_all_openapi_3.json | 170 ++++++ ...api_with_serverless_rest_api_resource.json | 6 +- tests/translator/test_translator.py | 2 + 10 files changed, 2288 insertions(+), 3 deletions(-) create mode 100644 tests/translator/input/api_with_cors_openapi_3.yaml create mode 100644 tests/translator/input/api_with_gateway_responses_all_openapi_3.yaml create mode 100644 tests/translator/output/api_with_cors_openapi_3.json create mode 100644 tests/translator/output/api_with_gateway_responses_all_openapi_3.json create mode 100644 tests/translator/output/aws-cn/api_with_cors_openapi_3.json create mode 100644 tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json create mode 100644 tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json create mode 100644 tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json diff --git a/tests/translator/input/api_with_cors_openapi_3.yaml b/tests/translator/input/api_with_cors_openapi_3.yaml new file mode 100644 index 000000000..7465b9ee7 --- /dev/null +++ b/tests/translator/input/api_with_cors_openapi_3.yaml @@ -0,0 +1,82 @@ +Globals: + Api: + Cors: { + "Fn::Join": [",", ["www.amazon.com", "www.google.com"]] + } + OpenApiVersion: '3.0' + + +Resources: + ImplicitApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + Path: / + Method: get + AnyApi: + Type: Api + Properties: + Path: /foo + Method: any + RestApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.handler + Runtime: nodejs8.10 + GetHtmlFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.handler + Runtime: nodejs8.10 + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionBody: { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/add": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RestApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + }, + "/{proxy+}": { + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetHtmlFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0" + } + Cors: + AllowMethods: "methods" + AllowHeaders: "headers" + AllowOrigin: "origins" + AllowCredentials: true diff --git a/tests/translator/input/api_with_gateway_responses_all_openapi_3.yaml b/tests/translator/input/api_with_gateway_responses_all_openapi_3.yaml new file mode 100644 index 000000000..fe88f63d5 --- /dev/null +++ b/tests/translator/input/api_with_gateway_responses_all_openapi_3.yaml @@ -0,0 +1,38 @@ +Resources: + Function: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + Path: / + Method: get + RestApiId: !Ref ExplicitApi + + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + OpenApiVersion: '3.0' + GatewayResponses: + UNAUTHORIZED: + StatusCode: 401 + ResponseParameters: + Headers: + Access-Control-Expose-Headers: "'WWW-Authenticate'" + Access-Control-Allow-Origin: "'*'" + WWW-Authenticate: >- + 'Bearer realm="admin"' + Paths: + PathKey: "'path-value'" + QueryStrings: + QueryStringKey: "'query-string-value'" + QUOTA_EXCEEDED: + StatusCode: 429 + ResponseParameters: + Headers: + Retry-After: "'31536000'" diff --git a/tests/translator/output/api_with_cors_openapi_3.json b/tests/translator/output/api_with_cors_openapi_3.json new file mode 100644 index 000000000..51b660674 --- /dev/null +++ b/tests/translator/output/api_with_cors_openapi_3.json @@ -0,0 +1,543 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionAnyApiPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/foo", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/add": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RestApiFunction.Arn}/invocations" + } + }, + "responses": {} + }, + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Headers": "headers", + "method.response.header.Access-Control-Allow-Origin": "origins", + "method.response.header.Access-Control-Allow-Methods": "methods", + "method.response.header.Access-Control-Allow-Credentials": "'true'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Headers": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + }, + "Access-Control-Allow-Credentials": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + } + }, + "/{proxy+}": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Headers": "headers", + "method.response.header.Access-Control-Allow-Origin": "origins", + "method.response.header.Access-Control-Allow-Methods": "methods", + "method.response.header.Access-Control-Allow-Credentials": "'true'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Headers": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + }, + "Access-Control-Allow-Credentials": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetHtmlFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0" + } + } + }, + "GetHtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment6034be6517" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment724a726704" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "RestApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ServerlessRestApiDeployment6034be6517": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 6034be6517d176422fda08141fe2881e7cb599b9" + } + }, + "RestApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "RestApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ExplicitApiDeployment724a726704": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 724a7267040d90d6d894a7617c0b0823b83f4169" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/foo": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": { + "Fn::Join": [ + ",", + [ + "www.amazon.com", + "www.google.com" + ] + ] + }, + "method.response.header.Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + }, + "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": { + "Fn::Join": [ + ",", + [ + "www.amazon.com", + "www.google.com" + ] + ] + }, + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0" + } + } + }, + "GetHtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "GetHtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionAnyApiPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/foo", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/api_with_gateway_responses_all_openapi_3.json b/tests/translator/output/api_with_gateway_responses_all_openapi_3.json new file mode 100644 index 000000000..c40f912f3 --- /dev/null +++ b/tests/translator/output/api_with_gateway_responses_all_openapi_3.json @@ -0,0 +1,162 @@ +{ + "Resources": { + "Function": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "FunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ExplicitApiDeployment6562809316": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 65628093164c8089c396f609d3400b333b08266d" + } + }, + "FunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Function.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0", + "x-amazon-apigateway-gateway-responses": { + "QUOTA_EXCEEDED": { + "responseParameters": { + "gatewayresponse.header.Retry-After": "'31536000'" + }, + "responseTemplates": {}, + "statusCode": "429" + }, + "UNAUTHORIZED": { + "responseParameters": { + "gatewayresponse.header.WWW-Authenticate": "'Bearer realm=\"admin\"'", + "gatewayresponse.header.Access-Control-Expose-Headers": "'WWW-Authenticate'", + "gatewayresponse.header.Access-Control-Allow-Origin": "'*'", + "gatewayresponse.path.PathKey": "'path-value'", + "gatewayresponse.querystring.QueryStringKey": "'query-string-value'" + }, + "responseTemplates": {}, + "statusCode": "401" + } + } + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment6562809316" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "FunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "Function" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ExplicitApi" + } + } + ] + } + } + }, + "FunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "Function" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ExplicitApi" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_cors_openapi_3.json b/tests/translator/output/aws-cn/api_with_cors_openapi_3.json new file mode 100644 index 000000000..855e4e336 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_cors_openapi_3.json @@ -0,0 +1,559 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionAnyApiPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/foo", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/add": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RestApiFunction.Arn}/invocations" + } + }, + "responses": {} + }, + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Headers": "headers", + "method.response.header.Access-Control-Allow-Origin": "origins", + "method.response.header.Access-Control-Allow-Methods": "methods", + "method.response.header.Access-Control-Allow-Credentials": "'true'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Headers": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + }, + "Access-Control-Allow-Credentials": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + } + }, + "/{proxy+}": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Headers": "headers", + "method.response.header.Access-Control-Allow-Origin": "origins", + "method.response.header.Access-Control-Allow-Methods": "methods", + "method.response.header.Access-Control-Allow-Credentials": "'true'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Headers": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + }, + "Access-Control-Allow-Credentials": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetHtmlFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "GetHtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment81b1814112" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment81b1814112": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 81b1814112fa93ec61491309881dad8b0cc8dfaf" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment724a726704" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "RestApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "RestApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "RestApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ExplicitApiDeployment724a726704": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 724a7267040d90d6d894a7617c0b0823b83f4169" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/foo": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": { + "Fn::Join": [ + ",", + [ + "www.amazon.com", + "www.google.com" + ] + ] + }, + "method.response.header.Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + }, + "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": { + "Fn::Join": [ + ",", + [ + "www.amazon.com", + "www.google.com" + ] + ] + }, + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "GetHtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "GetHtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionAnyApiPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/foo", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json b/tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json new file mode 100644 index 000000000..77cd75d6d --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json @@ -0,0 +1,170 @@ +{ + "Resources": { + "Function": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "FunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "FunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Function.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0", + "x-amazon-apigateway-gateway-responses": { + "QUOTA_EXCEEDED": { + "responseParameters": { + "gatewayresponse.header.Retry-After": "'31536000'" + }, + "responseTemplates": {}, + "statusCode": "429" + }, + "UNAUTHORIZED": { + "responseParameters": { + "gatewayresponse.header.WWW-Authenticate": "'Bearer realm=\"admin\"'", + "gatewayresponse.header.Access-Control-Expose-Headers": "'WWW-Authenticate'", + "gatewayresponse.header.Access-Control-Allow-Origin": "'*'", + "gatewayresponse.path.PathKey": "'path-value'", + "gatewayresponse.querystring.QueryStringKey": "'query-string-value'" + }, + "responseTemplates": {}, + "statusCode": "401" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiDeploymentf5768abea2": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: f5768abea2db17f06ce98bcd1771216e8c6e5c0a" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymentf5768abea2" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "FunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "Function" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ExplicitApi" + } + } + ] + } + } + }, + "FunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "Function" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ExplicitApi" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json b/tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json new file mode 100644 index 000000000..3c762e12b --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json @@ -0,0 +1,559 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionAnyApiPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/foo", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/add": { + "post": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RestApiFunction.Arn}/invocations" + } + }, + "responses": {} + }, + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Headers": "headers", + "method.response.header.Access-Control-Allow-Origin": "origins", + "method.response.header.Access-Control-Allow-Methods": "methods", + "method.response.header.Access-Control-Allow-Credentials": "'true'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Headers": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + }, + "Access-Control-Allow-Credentials": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + } + }, + "/{proxy+}": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Headers": "headers", + "method.response.header.Access-Control-Allow-Origin": "origins", + "method.response.header.Access-Control-Allow-Methods": "methods", + "method.response.header.Access-Control-Allow-Credentials": "'true'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Headers": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + }, + "Access-Control-Allow-Credentials": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetHtmlFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "GetHtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment75043f18da" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment724a726704" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeployment75043f18da": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 75043f18dafc631dfaf58fcfc876783f9210c4b0" + } + }, + "RestApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "RestApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "RestApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ExplicitApiDeployment724a726704": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 724a7267040d90d6d894a7617c0b0823b83f4169" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/foo": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": { + "Fn::Join": [ + ",", + [ + "www.amazon.com", + "www.google.com" + ] + ] + }, + "method.response.header.Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "x-amazon-apigateway-any-method": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + }, + "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": { + "Fn::Join": [ + ",", + [ + "www.amazon.com", + "www.google.com" + ] + ] + }, + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "GetHtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.handler", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "GetHtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionAnyApiPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*/foo", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json b/tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json new file mode 100644 index 000000000..76d1b705d --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json @@ -0,0 +1,170 @@ +{ + "Resources": { + "Function": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "FunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ExplicitApiDeploymentb21ac3ed02": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: b21ac3ed028d284eb717be1ccbcbf1b5a298e91a" + } + }, + "FunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Function.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "openapi": "3.0", + "x-amazon-apigateway-gateway-responses": { + "QUOTA_EXCEEDED": { + "responseParameters": { + "gatewayresponse.header.Retry-After": "'31536000'" + }, + "responseTemplates": {}, + "statusCode": "429" + }, + "UNAUTHORIZED": { + "responseParameters": { + "gatewayresponse.header.WWW-Authenticate": "'Bearer realm=\"admin\"'", + "gatewayresponse.header.Access-Control-Expose-Headers": "'WWW-Authenticate'", + "gatewayresponse.header.Access-Control-Allow-Origin": "'*'", + "gatewayresponse.path.PathKey": "'path-value'", + "gatewayresponse.querystring.QueryStringKey": "'query-string-value'" + }, + "responseTemplates": {}, + "statusCode": "401" + } + } + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeploymentb21ac3ed02" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "FunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "Function" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ExplicitApi" + } + } + ] + } + } + }, + "FunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "Function" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ExplicitApi" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/implicit_api_with_serverless_rest_api_resource.json b/tests/translator/output/aws-us-gov/implicit_api_with_serverless_rest_api_resource.json index e8a85e047..8484b1d55 100644 --- a/tests/translator/output/aws-us-gov/implicit_api_with_serverless_rest_api_resource.json +++ b/tests/translator/output/aws-us-gov/implicit_api_with_serverless_rest_api_resource.json @@ -155,11 +155,11 @@ "GetHtmlFunction": { "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "index.gethtml", "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, - "Handler": "index.gethtml", "Role": { "Fn::GetAtt": [ "GetHtmlFunctionRole", @@ -224,11 +224,11 @@ "RestApiFunction": { "Type": "AWS::Lambda::Function", "Properties": { + "Handler": "index.restapi", "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, - "Handler": "index.restapi", "Role": { "Fn::GetAtt": [ "RestApiFunctionRole", @@ -359,4 +359,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 406e9cdda..4f5b35040 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -180,6 +180,7 @@ class TestTranslatorEndToEnd(TestCase): 'api_with_minimum_compression_size', 'api_with_resource_refs', 'api_with_cors', + 'api_with_cors_openapi_3', 'api_with_cors_and_only_methods', 'api_with_cors_and_only_headers', 'api_with_cors_and_only_origins', @@ -188,6 +189,7 @@ class TestTranslatorEndToEnd(TestCase): 'api_with_cors_no_definitionbody', 'api_with_gateway_responses', 'api_with_gateway_responses_all', + 'api_with_gateway_responses_all_openapi_3', 'api_with_gateway_responses_minimal', 'api_with_gateway_responses_implicit', 'api_with_gateway_responses_string_status_code', From e30fd151ed28ae8053ddfec48b08c7ae6bd88db2 Mon Sep 17 00:00:00 2001 From: praneetap Date: Thu, 23 May 2019 17:42:54 -0700 Subject: [PATCH 08/13] Added some tests and cleanup --- .../input/explicit_api_openapi_3.yaml | 50 +++++ .../output/aws-cn/explicit_api_openapi_3.json | 195 ++++++++++++++++++ .../aws-us-gov/explicit_api_openapi_3.json | 195 ++++++++++++++++++ .../output/explicit_api_openapi_3.json | 179 ++++++++++++++++ tests/translator/test_translator.py | 1 + 5 files changed, 620 insertions(+) create mode 100644 tests/translator/input/explicit_api_openapi_3.yaml create mode 100644 tests/translator/output/aws-cn/explicit_api_openapi_3.json create mode 100644 tests/translator/output/aws-us-gov/explicit_api_openapi_3.json create mode 100644 tests/translator/output/explicit_api_openapi_3.json diff --git a/tests/translator/input/explicit_api_openapi_3.yaml b/tests/translator/input/explicit_api_openapi_3.yaml new file mode 100644 index 000000000..2a1bc936d --- /dev/null +++ b/tests/translator/input/explicit_api_openapi_3.yaml @@ -0,0 +1,50 @@ +Parameters: + MyStageName: + Type: String + Default: Production + something: + Type: String + Default: something + +Resources: + GetHtmlFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: + Bucket: sam-demo-bucket + Key: webpage.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Policies: AmazonDynamoDBReadOnlyAccess + Events: + GetHtml: + Type: Api + Properties: + RestApiId: + Ref: GetHtmlApi + Path: / + Method: get + + GetHtmlApi: + Type: AWS::Serverless::Api + Properties: + Name: MyGetApi + StageName: + Ref: MyStageName + DefinitionUri: + Bucket: sam-demo-bucket + Key: webpage_swagger.json + Variables: + EndpointUri: + Ref: something + EndpointUri2: http://example.com + + ApiWithInlineSwagger: + Type: AWS::Serverless::Api + Properties: + StageName: + Ref: MyStageName + OpenApiVersion: '3.0' + DefinitionBody: + "this": "is" + "a": "inline swagger" diff --git a/tests/translator/output/aws-cn/explicit_api_openapi_3.json b/tests/translator/output/aws-cn/explicit_api_openapi_3.json new file mode 100644 index 000000000..2e99fa824 --- /dev/null +++ b/tests/translator/output/aws-cn/explicit_api_openapi_3.json @@ -0,0 +1,195 @@ +{ + "Parameters": { + "something": { + "Default": "something", + "Type": "String" + }, + "MyStageName": { + "Default": "Production", + "Type": "String" + } + }, + "Resources": { + "GetHtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "webpage.zip" + }, + "Role": { + "Fn::GetAtt": [ + "GetHtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ApiWithInlineSwaggerStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ApiWithInlineSwaggerDeploymentf98588d7ff" + }, + "RestApiId": { + "Ref": "ApiWithInlineSwagger" + }, + "StageName": { + "Ref": "MyStageName" + } + } + }, + "GetHtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "GetHtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "GetHtmlApi" + } + } + ] + } + } + }, + "GetHtmlApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "GetHtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Variables": { + "EndpointUri": { + "Ref": "something" + }, + "EndpointUri2": "http://example.com" + }, + "StageName": { + "Ref": "MyStageName" + } + } + }, + "GetHtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "GetHtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-cn:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ApiWithInlineSwagger": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "this": "is", + "a": "inline swagger", + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "GetHtmlFunctionGetHtmlPermissionStage": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "GetHtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": { + "Ref": "MyStageName" + }, + "__ApiId__": { + "Ref": "GetHtmlApi" + } + } + ] + } + } + }, + "GetHtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "MyGetApi", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + } + } + }, + "ApiWithInlineSwaggerDeploymentf98588d7ff": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ApiWithInlineSwagger" + }, + "Description": "RestApi deployment id: f98588d7ff10d9add9be1344fbe7daff2e100b78" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/explicit_api_openapi_3.json b/tests/translator/output/aws-us-gov/explicit_api_openapi_3.json new file mode 100644 index 000000000..1dbc4a782 --- /dev/null +++ b/tests/translator/output/aws-us-gov/explicit_api_openapi_3.json @@ -0,0 +1,195 @@ +{ + "Parameters": { + "something": { + "Default": "something", + "Type": "String" + }, + "MyStageName": { + "Default": "Production", + "Type": "String" + } + }, + "Resources": { + "GetHtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "webpage.zip" + }, + "Role": { + "Fn::GetAtt": [ + "GetHtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ApiWithInlineSwaggerStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ApiWithInlineSwaggerDeploymentf98588d7ff" + }, + "RestApiId": { + "Ref": "ApiWithInlineSwagger" + }, + "StageName": { + "Ref": "MyStageName" + } + } + }, + "GetHtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "GetHtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "GetHtmlApi" + } + } + ] + } + } + }, + "GetHtmlApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "GetHtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Variables": { + "EndpointUri": { + "Ref": "something" + }, + "EndpointUri2": "http://example.com" + }, + "StageName": { + "Ref": "MyStageName" + } + } + }, + "GetHtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "GetHtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws-us-gov:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ApiWithInlineSwagger": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "this": "is", + "a": "inline swagger", + "openapi": "3.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "GetHtmlFunctionGetHtmlPermissionStage": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "GetHtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": { + "Ref": "MyStageName" + }, + "__ApiId__": { + "Ref": "GetHtmlApi" + } + } + ] + } + } + }, + "GetHtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "MyGetApi", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + }, + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + } + } + }, + "ApiWithInlineSwaggerDeploymentf98588d7ff": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ApiWithInlineSwagger" + }, + "Description": "RestApi deployment id: f98588d7ff10d9add9be1344fbe7daff2e100b78" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/explicit_api_openapi_3.json b/tests/translator/output/explicit_api_openapi_3.json new file mode 100644 index 000000000..d8ecaf072 --- /dev/null +++ b/tests/translator/output/explicit_api_openapi_3.json @@ -0,0 +1,179 @@ +{ + "Parameters": { + "something": { + "Default": "something", + "Type": "String" + }, + "MyStageName": { + "Default": "Production", + "Type": "String" + } + }, + "Resources": { + "GetHtmlFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "webpage.zip" + }, + "Role": { + "Fn::GetAtt": [ + "GetHtmlFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs4.3", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ApiWithInlineSwaggerStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ApiWithInlineSwaggerDeploymentf98588d7ff" + }, + "RestApiId": { + "Ref": "ApiWithInlineSwagger" + }, + "StageName": { + "Ref": "MyStageName" + } + } + }, + "GetHtmlFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "GetHtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "GetHtmlApi" + } + } + ] + } + } + }, + "GetHtmlApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "GetHtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Variables": { + "EndpointUri": { + "Ref": "something" + }, + "EndpointUri2": "http://example.com" + }, + "StageName": { + "Ref": "MyStageName" + } + } + }, + "GetHtmlApiDeploymentf117c932f7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Description": "RestApi deployment id: f117c932f75cfa87d23dfed64e9430d0081ef289", + "StageName": "Stage" + } + }, + "GetHtmlFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ApiWithInlineSwagger": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "this": "is", + "a": "inline swagger", + "openapi": "3.0" + } + } + }, + "GetHtmlFunctionGetHtmlPermissionStage": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "GetHtmlFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": { + "Ref": "MyStageName" + }, + "__ApiId__": { + "Ref": "GetHtmlApi" + } + } + ] + } + } + }, + "GetHtmlApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "MyGetApi", + "BodyS3Location": { + "Bucket": "sam-demo-bucket", + "Key": "webpage_swagger.json" + } + } + }, + "ApiWithInlineSwaggerDeploymentf98588d7ff": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ApiWithInlineSwagger" + }, + "Description": "RestApi deployment id: f98588d7ff10d9add9be1344fbe7daff2e100b78" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 4f5b35040..a31e0a64c 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -168,6 +168,7 @@ class TestTranslatorEndToEnd(TestCase): 'simpletable_with_sse', 'implicit_api', 'explicit_api', + 'explicit_api_openapi_3', 'api_endpoint_configuration', 'api_with_auth_all_maximum', 'api_with_auth_all_minimum', From 2641d153062d29f0b1d377f2dac8bb64205240ae Mon Sep 17 00:00:00 2001 From: praneetap Date: Thu, 23 May 2019 17:42:54 -0700 Subject: [PATCH 09/13] Added some tests and cleanup --- samtranslator/plugins/globals/globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index ec03a56de..d71a116d9 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -122,7 +122,7 @@ def fix_openapi_definitions(cls, template): resources = template["Resources"] for _, resource in resources.items(): - if ("Type" in resource) and (resource["Type"] == "AWS::Serverless::Api"): + if ("Type" in resource) and (resource["Type"] == cls._API_TYPE): properties = resource["Properties"] if (cls._OPENAPIVERSION in properties) and (properties[cls._OPENAPIVERSION] == "3.0"): if "DefinitionBody" in properties: From 10eabede0d590fd107d0400b372447921c2a804f Mon Sep 17 00:00:00 2001 From: praneetap Date: Tue, 28 May 2019 15:43:25 -0700 Subject: [PATCH 10/13] More tests and addressed cr comments --- samtranslator/model/api/api_generator.py | 10 +- samtranslator/model/apigateway.py | 3 +- samtranslator/plugins/globals/globals.py | 20 +- samtranslator/swagger/swagger.py | 5 +- tests/plugins/globals/test_globals.py | 38 ++- tests/swagger/test_swagger.py | 14 +- .../input/api_with_open_api_version.yaml | 2 +- .../input/api_with_open_api_version_2.yaml | 22 ++ .../output/api_with_cors_openapi_3.json | 18 +- ..._with_gateway_responses_all_openapi_3.json | 6 +- .../output/api_with_open_api_version.json | 52 ++-- .../output/api_with_open_api_version_2.json | 218 ++++++++++++++++ .../aws-cn/api_with_cors_openapi_3.json | 42 ++-- ..._with_gateway_responses_all_openapi_3.json | 20 +- .../aws-cn/api_with_open_api_version.json | 52 ++-- .../aws-cn/api_with_open_api_version_2.json | 234 ++++++++++++++++++ .../output/aws-cn/explicit_api_openapi_3.json | 57 +++-- .../aws-us-gov/api_with_cors_openapi_3.json | 42 ++-- ..._with_gateway_responses_all_openapi_3.json | 8 +- .../aws-us-gov/api_with_open_api_version.json | 32 +-- .../api_with_open_api_version_2.json | 234 ++++++++++++++++++ .../aws-us-gov/explicit_api_openapi_3.json | 57 +++-- ...ror_api_with_invalid_open_api_version.json | 4 +- .../output/explicit_api_openapi_3.json | 51 ++-- tests/translator/test_translator.py | 1 + 25 files changed, 1006 insertions(+), 236 deletions(-) create mode 100644 tests/translator/input/api_with_open_api_version_2.yaml create mode 100644 tests/translator/output/api_with_open_api_version_2.json create mode 100644 tests/translator/output/aws-cn/api_with_open_api_version_2.json create mode 100644 tests/translator/output/aws-us-gov/api_with_open_api_version_2.json diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index ee386b5e6..670237f6d 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -1,5 +1,6 @@ from collections import namedtuple from six import string_types +import re from samtranslator.model.intrinsics import ref from samtranslator.model.apigateway import (ApiGatewayDeployment, ApiGatewayRestApi, @@ -23,7 +24,7 @@ AuthProperties.__new__.__defaults__ = (None, None, None) GatewayResponseProperties = ["ResponseParameters", "ResponseTemplates", "StatusCode"] -OpenApiVersionsSupported = ["2.0", "3.0"] +OpenApiVersionsSupportedRegex = r"\A[2-3](\.\d)(\.\d)?$" class ApiGenerator(object): @@ -96,9 +97,10 @@ def _construct_rest_api(self): raise InvalidResourceException(self.logical_id, "Specify either 'DefinitionUri' or 'DefinitionBody' property and not both") - if self.open_api_version and self.open_api_version not in OpenApiVersionsSupported: - raise InvalidResourceException(self.logical_id, - "The OpenApiVersion value must be one of [2.0, 3.0]") + if self.open_api_version: + if re.match(OpenApiVersionsSupportedRegex, self.open_api_version) is None: + raise InvalidResourceException( + self.logical_id, "The OpenApiVersion value must be of the format 2.x.x or 3.x.x") self._add_cors() self._add_auth() diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index edfa9f115..731fe039e 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -20,8 +20,7 @@ class ApiGatewayRestApi(Resource): 'Parameters': PropertyType(False, is_type(dict)), 'EndpointConfiguration': PropertyType(False, is_type(dict)), "BinaryMediaTypes": PropertyType(False, is_type(list)), - "MinimumCompressionSize": PropertyType(False, is_type(int)), - 'OpenApiVersion': PropertyType(False, is_str()) + "MinimumCompressionSize": PropertyType(False, is_type(int)) } runtime_attrs = { diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index d71a116d9..d3889b405 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -1,5 +1,6 @@ from samtranslator.public.sdk.resource import SamResourceType from samtranslator.public.intrinsics import is_intrinsics +import re class Globals(object): @@ -13,6 +14,8 @@ class Globals(object): _RESOURCE_PREFIX = "AWS::Serverless::" _OPENAPIVERSION = "OpenApiVersion" _API_TYPE = "AWS::Serverless::Api" + _MANAGE_SWAGGER = "__MANAGE_SWAGGER" + _OPENAPIVERSION_REGEX = r"\A3(\.\d)(\.\d)?$" supported_properties = { # Everything on Serverless::Function except Role, Policies, FunctionName, Events @@ -71,7 +74,7 @@ def __init__(self, template): :param dict template: SAM template to be parsed """ self.supported_resource_section_names = ([x.replace(self._RESOURCE_PREFIX, "") - for x in self.supported_properties.keys()]) + for x in self.supported_properties.keys()]) # Sort the names for stability in list ordering self.supported_resource_section_names.sort() @@ -114,7 +117,14 @@ def del_section(cls, template): def fix_openapi_definitions(cls, template): """ Helper method to postprocess the resources to make sure the swagger doc version matches - the one specified on the resource with flag OpenApiVersion + the one specified on the resource with flag OpenApiVersion. + + This is done postprocess in globals because, the implicit api plugin runs before globals, \ + and at that point the global flags aren't applied on each resource, so we do not know \ + whether OpenApiVersion flag is specified. Running the globals plugin before implicit api \ + was a risky change, so we decided to postprocess the openapi version here. + + To make sure we don't modify customer defined swagger, we also check for __MANAGE_SWAGGER flag. :param dict template: SAM template :return: Modified SAM template with corrected swagger doc matching the OpenApiVersion. @@ -124,10 +134,11 @@ def fix_openapi_definitions(cls, template): for _, resource in resources.items(): if ("Type" in resource) and (resource["Type"] == cls._API_TYPE): properties = resource["Properties"] - if (cls._OPENAPIVERSION in properties) and (properties[cls._OPENAPIVERSION] == "3.0"): + if (cls._OPENAPIVERSION in properties) and (cls._MANAGE_SWAGGER in properties) and \ + (re.match(cls._OPENAPIVERSION_REGEX, properties[cls._OPENAPIVERSION]) is not None): if "DefinitionBody" in properties: definition_body = properties['DefinitionBody'] - definition_body['openapi'] = "3.0" + definition_body['openapi'] = properties[cls._OPENAPIVERSION] if definition_body.get('swagger'): del definition_body['swagger'] @@ -422,6 +433,7 @@ class InvalidGlobalsSectionException(Exception): Attributes: message -- explanation of the error """ + def __init__(self, logical_id, message): self._logical_id = logical_id self._message = message diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index bb2439000..11b0704ca 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -1,4 +1,5 @@ import copy +import re from six import string_types from samtranslator.model.intrinsics import ref @@ -554,11 +555,13 @@ def is_valid(data): :param dict data: Data to be validated :return: True, if data is a Swagger """ + openapi_version_supported_regex = r"\A3(\.\d)(\.\d)?$" + if bool(data) and isinstance(data, dict) and isinstance(data.get('paths'), dict): if bool(data.get("swagger")): return True elif bool(data.get("openapi")): - return "3.0" in data["openapi"] + return re.search(openapi_version_supported_regex, data["openapi"]) is not None return False return False diff --git a/tests/plugins/globals/test_globals.py b/tests/plugins/globals/test_globals.py index 19b0c4dd0..5d233f128 100644 --- a/tests/plugins/globals/test_globals.py +++ b/tests/plugins/globals/test_globals.py @@ -675,6 +675,7 @@ class TestGlobalsOpenApi(TestCase): "MyApi": { "Type": "AWS::Serverless::Api", "Properties": { + "__MANAGE_SWAGGER": True, "OpenApiVersion": "3.0", "DefinitionBody": { "swagger": "2.0" @@ -688,6 +689,7 @@ class TestGlobalsOpenApi(TestCase): "MyApi": { "Type": "AWS::Serverless::Api", "Properties": { + "__MANAGE_SWAGGER": True, "OpenApiVersion": "3.0", "DefinitionBody": { "openapi": "3.0" @@ -731,6 +733,7 @@ class TestGlobalsOpenApi(TestCase): "MyApi": { "Type": "AWS::Serverless::Api", "Properties": { + "__MANAGE_SWAGGER": True, "OpenApiVersion": "2.0", "DefinitionBody": { "swagger": "2.0" @@ -744,6 +747,7 @@ class TestGlobalsOpenApi(TestCase): "MyApi": { "Type": "AWS::Serverless::Api", "Properties": { + "__MANAGE_SWAGGER": True, "OpenApiVersion": "2.0", "DefinitionBody": { "swagger": "2.0" @@ -760,6 +764,7 @@ class TestGlobalsOpenApi(TestCase): "MyApi": { "Type": "AWS::Serverless::Api", "Properties": { + "__MANAGE_SWAGGER": True, "OpenApiVersion": "3.0" } } @@ -770,12 +775,43 @@ class TestGlobalsOpenApi(TestCase): "MyApi": { "Type": "AWS::Serverless::Api", "Properties": { + "__MANAGE_SWAGGER": True, "OpenApiVersion": "3.0" } } } } - } + }, + { + "name": "ignore customer defined swagger", + "input": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "3.0", + "DefinitionBody": { + "swagger": "2.0" + } + } + } + } + }, + "expected": { + "Resources": { + "MyApi": { + "Type": "AWS::Serverless::Api", + "Properties": { + "OpenApiVersion": "3.0", + "DefinitionBody": { + "swagger": "2.0" + } + } + } + } + } + }, + ] def test_openapi_postprocess(self): diff --git a/tests/swagger/test_swagger.py b/tests/swagger/test_swagger.py index 223e2b045..d7277bb51 100644 --- a/tests/swagger/test_swagger.py +++ b/tests/swagger/test_swagger.py @@ -35,7 +35,19 @@ def test_must_succeed_on_valid_swagger(self): def test_must_fail_on_invalid_openapi_version(self): invalid_swagger = { - "openapi": "2.0", + "openapi": "2.3.0", + "paths": { + "/foo": {}, + "/bar": {} + } + } + + with self.assertRaises(ValueError): + SwaggerEditor(invalid_swagger) + + def test_must_fail_on_invalid_openapi_version_2(self): + invalid_swagger = { + "openapi": "3.1.1.1", "paths": { "/foo": {}, "/bar": {} diff --git a/tests/translator/input/api_with_open_api_version.yaml b/tests/translator/input/api_with_open_api_version.yaml index ffa31e09a..dd91b26c9 100644 --- a/tests/translator/input/api_with_open_api_version.yaml +++ b/tests/translator/input/api_with_open_api_version.yaml @@ -1,6 +1,6 @@ Globals: Api: - OpenApiVersion: '3.0' + OpenApiVersion: '3.0.1' Cors: '*' Resources: diff --git a/tests/translator/input/api_with_open_api_version_2.yaml b/tests/translator/input/api_with_open_api_version_2.yaml new file mode 100644 index 000000000..b31fc72b9 --- /dev/null +++ b/tests/translator/input/api_with_open_api_version_2.yaml @@ -0,0 +1,22 @@ +Globals: + Api: + OpenApiVersion: '2.0' + Cors: '*' + +Resources: + ImplicitApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs8.10 + Events: + GetHtml: + Type: Api + Properties: + Path: / + Method: get + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod diff --git a/tests/translator/output/api_with_cors_openapi_3.json b/tests/translator/output/api_with_cors_openapi_3.json index 51b660674..02d888397 100644 --- a/tests/translator/output/api_with_cors_openapi_3.json +++ b/tests/translator/output/api_with_cors_openapi_3.json @@ -221,7 +221,7 @@ } } }, - "openapi": "3.0" + "swagger": "2.0" } } }, @@ -253,7 +253,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeployment6034be6517" + "Ref": "ServerlessRestApiDeployment36174ded39" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -265,7 +265,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeployment724a726704" + "Ref": "ExplicitApiDeployment3a5a78688c" }, "RestApiId": { "Ref": "ExplicitApi" @@ -318,13 +318,13 @@ } } }, - "ServerlessRestApiDeployment6034be6517": { + "ExplicitApiDeployment3a5a78688c": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "ServerlessRestApi" + "Ref": "ExplicitApi" }, - "Description": "RestApi deployment id: 6034be6517d176422fda08141fe2881e7cb599b9" + "Description": "RestApi deployment id: 3a5a78688c9bc377d53aa4153a11f0c4f6e7364c" } }, "RestApiFunction": { @@ -350,13 +350,13 @@ ] } }, - "ExplicitApiDeployment724a726704": { + "ServerlessRestApiDeployment36174ded39": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "ExplicitApi" + "Ref": "ServerlessRestApi" }, - "Description": "RestApi deployment id: 724a7267040d90d6d894a7617c0b0823b83f4169" + "Description": "RestApi deployment id: 36174ded3978092f96669107074db6caeaaafddd" } }, "ServerlessRestApi": { diff --git a/tests/translator/output/api_with_gateway_responses_all_openapi_3.json b/tests/translator/output/api_with_gateway_responses_all_openapi_3.json index c40f912f3..357ad0e91 100644 --- a/tests/translator/output/api_with_gateway_responses_all_openapi_3.json +++ b/tests/translator/output/api_with_gateway_responses_all_openapi_3.json @@ -23,13 +23,13 @@ ] } }, - "ExplicitApiDeployment6562809316": { + "ExplicitApiDeployment47d77987a3": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { "Ref": "ExplicitApi" }, - "Description": "RestApi deployment id: 65628093164c8089c396f609d3400b333b08266d" + "Description": "RestApi deployment id: 47d77987a3152a97c89d794f2682485b9dafde5d" } }, "FunctionRole": { @@ -108,7 +108,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeployment6562809316" + "Ref": "ExplicitApiDeployment47d77987a3" }, "RestApiId": { "Ref": "ExplicitApi" diff --git a/tests/translator/output/api_with_open_api_version.json b/tests/translator/output/api_with_open_api_version.json index a4b0b0884..1224c7059 100644 --- a/tests/translator/output/api_with_open_api_version.json +++ b/tests/translator/output/api_with_open_api_version.json @@ -68,6 +68,15 @@ } } }, + "ExplicitApiDeployment01dd43a75f": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 01dd43a75fc0e125c678d20749bacde95d723928" + } + }, "ImplicitApiFunctionGetHtmlPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -89,15 +98,6 @@ } } }, - "ServerlessRestApiDeploymentc3856307e4": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: c3856307e48020ec37335539fec71b67bfdeaff6" - } - }, "ExplicitApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -109,41 +109,32 @@ } }, "paths": {}, - "openapi": "3.0" + "openapi": "3.0.1" } } }, - "ExplicitApiProdStage": { + "ServerlessRestApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeployment783c7f37fe" + "Ref": "ServerlessRestApiDeployment82c7b2e316" }, "RestApiId": { - "Ref": "ExplicitApi" + "Ref": "ServerlessRestApi" }, "StageName": "Prod" } }, - "ServerlessRestApiProdStage": { + "ExplicitApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeploymentc3856307e4" - }, - "RestApiId": { - "Ref": "ServerlessRestApi" + "Ref": "ExplicitApiDeployment01dd43a75f" }, - "StageName": "Prod" - } - }, - "ExplicitApiDeployment783c7f37fe": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { "RestApiId": { "Ref": "ExplicitApi" }, - "Description": "RestApi deployment id: 783c7f37fe04219a0cd2252fd5e83d4d48836e50" + "StageName": "Prod" } }, "ServerlessRestApi": { @@ -210,9 +201,18 @@ } } }, - "openapi": "3.0" + "openapi": "3.0.1" } } + }, + "ServerlessRestApiDeployment82c7b2e316": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 82c7b2e3162ebd01c9b3ccaa1fafa5cc1df94a68" + } } } } diff --git a/tests/translator/output/api_with_open_api_version_2.json b/tests/translator/output/api_with_open_api_version_2.json new file mode 100644 index 000000000..ba6e1a5fb --- /dev/null +++ b/tests/translator/output/api_with_open_api_version_2.json @@ -0,0 +1,218 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0" + } + } + }, + "ServerlessRestApiDeploymentb9bf7835be": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: b9bf7835be8ea0cb2c188b846e03ff6f79f4d330" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentb9bf7835be" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": "*", + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0" + } + } + }, + "ExplicitApiDeployment5332c373d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/api_with_cors_openapi_3.json b/tests/translator/output/aws-cn/api_with_cors_openapi_3.json index 855e4e336..77acdd9cd 100644 --- a/tests/translator/output/aws-cn/api_with_cors_openapi_3.json +++ b/tests/translator/output/aws-cn/api_with_cors_openapi_3.json @@ -221,7 +221,7 @@ } } }, - "openapi": "3.0" + "swagger": "2.0" }, "EndpointConfiguration": { "Types": [ @@ -261,7 +261,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeployment81b1814112" + "Ref": "ServerlessRestApiDeployment5f2f2e0731" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -269,20 +269,11 @@ "StageName": "Prod" } }, - "ServerlessRestApiDeployment81b1814112": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: 81b1814112fa93ec61491309881dad8b0cc8dfaf" - } - }, "ExplicitApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeployment724a726704" + "Ref": "ExplicitApiDeployment3a5a78688c" }, "RestApiId": { "Ref": "ExplicitApi" @@ -290,6 +281,15 @@ "StageName": "Prod" } }, + "ServerlessRestApiDeployment5f2f2e0731": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 5f2f2e07317e5f71e17f2a1f0cb2c1833f881340" + } + }, "RestApiFunctionRole": { "Type": "AWS::IAM::Role", "Properties": { @@ -335,6 +335,15 @@ } } }, + "ExplicitApiDeployment3a5a78688c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 3a5a78688c9bc377d53aa4153a11f0c4f6e7364c" + } + }, "RestApiFunction": { "Type": "AWS::Lambda::Function", "Properties": { @@ -358,15 +367,6 @@ ] } }, - "ExplicitApiDeployment724a726704": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: 724a7267040d90d6d894a7617c0b0823b83f4169" - } - }, "ServerlessRestApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { diff --git a/tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json b/tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json index 77cd75d6d..8da7e78f0 100644 --- a/tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json +++ b/tests/translator/output/aws-cn/api_with_gateway_responses_all_openapi_3.json @@ -103,20 +103,11 @@ } } }, - "ExplicitApiDeploymentf5768abea2": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: f5768abea2db17f06ce98bcd1771216e8c6e5c0a" - } - }, "ExplicitApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeploymentf5768abea2" + "Ref": "ExplicitApiDeployment4c4177079d" }, "RestApiId": { "Ref": "ExplicitApi" @@ -145,6 +136,15 @@ } } }, + "ExplicitApiDeployment4c4177079d": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 4c4177079dd342a2b71978bd25721b7b774295ad" + } + }, "FunctionGetHtmlPermissionTest": { "Type": "AWS::Lambda::Permission", "Properties": { diff --git a/tests/translator/output/aws-cn/api_with_open_api_version.json b/tests/translator/output/aws-cn/api_with_open_api_version.json index 25c5a3770..647d4ae32 100644 --- a/tests/translator/output/aws-cn/api_with_open_api_version.json +++ b/tests/translator/output/aws-cn/api_with_open_api_version.json @@ -68,6 +68,15 @@ } } }, + "ExplicitApiDeployment01dd43a75f": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 01dd43a75fc0e125c678d20749bacde95d723928" + } + }, "ImplicitApiFunctionGetHtmlPermissionProd": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -100,7 +109,7 @@ } }, "paths": {}, - "openapi": "3.0" + "openapi": "3.0.1" }, "EndpointConfiguration": { "Types": [ @@ -112,46 +121,28 @@ } } }, - "ExplicitApiProdStage": { + "ServerlessRestApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeployment783c7f37fe" + "Ref": "ServerlessRestApiDeploymentb86b9dad9d" }, "RestApiId": { - "Ref": "ExplicitApi" + "Ref": "ServerlessRestApi" }, "StageName": "Prod" } }, - "ServerlessRestApiProdStage": { + "ExplicitApiProdStage": { "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeploymentaada0b6533" + "Ref": "ExplicitApiDeployment01dd43a75f" }, - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "StageName": "Prod" - } - }, - "ExplicitApiDeployment783c7f37fe": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { "RestApiId": { "Ref": "ExplicitApi" }, - "Description": "RestApi deployment id: 783c7f37fe04219a0cd2252fd5e83d4d48836e50" - } - }, - "ServerlessRestApiDeploymentaada0b6533": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: aada0b6533734d1934b71842c2828f111d441fc1" + "StageName": "Prod" } }, "ServerlessRestApi": { @@ -218,7 +209,7 @@ } } }, - "openapi": "3.0" + "openapi": "3.0.1" }, "EndpointConfiguration": { "Types": [ @@ -229,6 +220,15 @@ "endpointConfigurationTypes": "REGIONAL" } } + }, + "ServerlessRestApiDeploymentb86b9dad9d": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: b86b9dad9d2fd5286c7b355dbd5350987cf492c1" + } } } } diff --git a/tests/translator/output/aws-cn/api_with_open_api_version_2.json b/tests/translator/output/aws-cn/api_with_open_api_version_2.json new file mode 100644 index 000000000..a49aa983b --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_open_api_version_2.json @@ -0,0 +1,234 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-cn:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeploymentc444e5d902" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiDeploymentc444e5d902": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: c444e5d902971761ced658a7ce701149743eb376" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": "*", + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiDeployment5332c373d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/explicit_api_openapi_3.json b/tests/translator/output/aws-cn/explicit_api_openapi_3.json index 2e99fa824..d98d610a6 100644 --- a/tests/translator/output/aws-cn/explicit_api_openapi_3.json +++ b/tests/translator/output/aws-cn/explicit_api_openapi_3.json @@ -37,7 +37,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ApiWithInlineSwaggerDeploymentf98588d7ff" + "Ref": "ApiWithInlineSwaggerDeployment09cda3d97b" }, "RestApiId": { "Ref": "ApiWithInlineSwagger" @@ -68,26 +68,6 @@ } } }, - "GetHtmlApiStage": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "DeploymentId": { - "Ref": "GetHtmlApiDeploymentf117c932f7" - }, - "RestApiId": { - "Ref": "GetHtmlApi" - }, - "Variables": { - "EndpointUri": { - "Ref": "something" - }, - "EndpointUri2": "http://example.com" - }, - "StageName": { - "Ref": "MyStageName" - } - } - }, "GetHtmlApiDeploymentf117c932f7": { "Type": "AWS::ApiGateway::Deployment", "Properties": { @@ -128,8 +108,7 @@ "Properties": { "Body": { "this": "is", - "a": "inline swagger", - "openapi": "3.0" + "a": "inline swagger" }, "EndpointConfiguration": { "Types": [ @@ -172,23 +151,43 @@ "REGIONAL" ] }, - "Name": "MyGetApi", - "Parameters": { - "endpointConfigurationTypes": "REGIONAL" - }, "BodyS3Location": { "Bucket": "sam-demo-bucket", "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + }, + "Name": "MyGetApi" + } + }, + "GetHtmlApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "GetHtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Variables": { + "EndpointUri": { + "Ref": "something" + }, + "EndpointUri2": "http://example.com" + }, + "StageName": { + "Ref": "MyStageName" } } }, - "ApiWithInlineSwaggerDeploymentf98588d7ff": { + "ApiWithInlineSwaggerDeployment09cda3d97b": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { "Ref": "ApiWithInlineSwagger" }, - "Description": "RestApi deployment id: f98588d7ff10d9add9be1344fbe7daff2e100b78" + "Description": "RestApi deployment id: 09cda3d97b008bed7bd4ebb1b5304ed622492941" } } } diff --git a/tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json b/tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json index 3c762e12b..9a66ac27d 100644 --- a/tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json +++ b/tests/translator/output/aws-us-gov/api_with_cors_openapi_3.json @@ -221,7 +221,7 @@ } } }, - "openapi": "3.0" + "swagger": "2.0" }, "EndpointConfiguration": { "Types": [ @@ -261,7 +261,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeployment75043f18da" + "Ref": "ServerlessRestApiDeployment2cd28b2066" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -273,7 +273,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeployment724a726704" + "Ref": "ExplicitApiDeployment3a5a78688c" }, "RestApiId": { "Ref": "ExplicitApi" @@ -281,15 +281,6 @@ "StageName": "Prod" } }, - "ServerlessRestApiDeployment75043f18da": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: 75043f18dafc631dfaf58fcfc876783f9210c4b0" - } - }, "RestApiFunctionRole": { "Type": "AWS::IAM::Role", "Properties": { @@ -335,6 +326,24 @@ } } }, + "ServerlessRestApiDeployment2cd28b2066": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 2cd28b2066d69ecfb44eb7e024734cab2f3f9dac" + } + }, + "ExplicitApiDeployment3a5a78688c": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 3a5a78688c9bc377d53aa4153a11f0c4f6e7364c" + } + }, "RestApiFunction": { "Type": "AWS::Lambda::Function", "Properties": { @@ -358,15 +367,6 @@ ] } }, - "ExplicitApiDeployment724a726704": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ExplicitApi" - }, - "Description": "RestApi deployment id: 724a7267040d90d6d894a7617c0b0823b83f4169" - } - }, "ServerlessRestApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { diff --git a/tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json b/tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json index 76d1b705d..8b758bbd4 100644 --- a/tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json +++ b/tests/translator/output/aws-us-gov/api_with_gateway_responses_all_openapi_3.json @@ -23,13 +23,13 @@ ] } }, - "ExplicitApiDeploymentb21ac3ed02": { + "ExplicitApiDeployment3a19adf892": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { "Ref": "ExplicitApi" }, - "Description": "RestApi deployment id: b21ac3ed028d284eb717be1ccbcbf1b5a298e91a" + "Description": "RestApi deployment id: 3a19adf892fbe70d360659eb3660359ade61913b" } }, "FunctionRole": { @@ -116,7 +116,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeploymentb21ac3ed02" + "Ref": "ExplicitApiDeployment3a19adf892" }, "RestApiId": { "Ref": "ExplicitApi" @@ -167,4 +167,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/api_with_open_api_version.json b/tests/translator/output/aws-us-gov/api_with_open_api_version.json index 8ea0d739c..5cd2019b4 100644 --- a/tests/translator/output/aws-us-gov/api_with_open_api_version.json +++ b/tests/translator/output/aws-us-gov/api_with_open_api_version.json @@ -47,15 +47,6 @@ } } }, - "ServerlessRestApiDeployment9bdc4ed430": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "RestApiId": { - "Ref": "ServerlessRestApi" - }, - "Description": "RestApi deployment id: 9bdc4ed430c09a5c332bdd62654d27d54fd60001" - } - }, "ImplicitApiFunctionGetHtmlPermissionTest": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -109,7 +100,7 @@ } }, "paths": {}, - "openapi": "3.0" + "openapi": "3.0.1" }, "EndpointConfiguration": { "Types": [ @@ -125,7 +116,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ExplicitApiDeployment783c7f37fe" + "Ref": "ExplicitApiDeployment01dd43a75f" }, "RestApiId": { "Ref": "ExplicitApi" @@ -137,7 +128,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ServerlessRestApiDeployment9bdc4ed430" + "Ref": "ServerlessRestApiDeployment3f1d889857" }, "RestApiId": { "Ref": "ServerlessRestApi" @@ -145,13 +136,13 @@ "StageName": "Prod" } }, - "ExplicitApiDeployment783c7f37fe": { + "ServerlessRestApiDeployment3f1d889857": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { - "Ref": "ExplicitApi" + "Ref": "ServerlessRestApi" }, - "Description": "RestApi deployment id: 783c7f37fe04219a0cd2252fd5e83d4d48836e50" + "Description": "RestApi deployment id: 3f1d889857c22227451ab7a02be7ea74b2e9d5b4" } }, "ServerlessRestApi": { @@ -218,7 +209,7 @@ } } }, - "openapi": "3.0" + "openapi": "3.0.1" }, "EndpointConfiguration": { "Types": [ @@ -229,6 +220,15 @@ "endpointConfigurationTypes": "REGIONAL" } } + }, + "ExplicitApiDeployment01dd43a75f": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 01dd43a75fc0e125c678d20749bacde95d723928" + } } } } diff --git a/tests/translator/output/aws-us-gov/api_with_open_api_version_2.json b/tests/translator/output/aws-us-gov/api_with_open_api_version_2.json new file mode 100644 index 000000000..466cc8527 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_open_api_version_2.json @@ -0,0 +1,234 @@ +{ + "Resources": { + "ImplicitApiFunction": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Handler": "index.gethtml", + "Code": { + "S3Bucket": "sam-demo-bucket", + "S3Key": "member_portal.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ImplicitApiFunctionRole", + "Arn" + ] + }, + "Runtime": "nodejs8.10", + "Tags": [ + { + "Value": "SAM", + "Key": "lambda:createdBy" + } + ] + } + }, + "ImplicitApiFunctionRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "sts:AssumeRole" + ], + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionTest": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "*", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ImplicitApiFunctionGetHtmlPermissionProd": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:invokeFunction", + "Principal": "apigateway.amazonaws.com", + "FunctionName": { + "Ref": "ImplicitApiFunction" + }, + "SourceArn": { + "Fn::Sub": [ + "arn:aws-us-gov:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/", + { + "__Stage__": "Prod", + "__ApiId__": { + "Ref": "ServerlessRestApi" + } + } + ] + } + } + }, + "ExplicitApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ServerlessRestApiDeployment3d22acdeb7": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "Description": "RestApi deployment id: 3d22acdeb7a3302c0b978e3dbb15c149380fbe77" + } + }, + "ExplicitApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ExplicitApiDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ExplicitApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApiProdStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "ServerlessRestApiDeployment3d22acdeb7" + }, + "RestApiId": { + "Ref": "ServerlessRestApi" + }, + "StageName": "Prod" + } + }, + "ServerlessRestApi": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Body": { + "info": { + "version": "1.0", + "title": { + "Ref": "AWS::StackName" + } + }, + "paths": { + "/": { + "options": { + "x-amazon-apigateway-integration": { + "type": "mock", + "requestTemplates": { + "application/json": "{\n \"statusCode\" : 200\n}\n" + }, + "responses": { + "default": { + "statusCode": "200", + "responseTemplates": { + "application/json": "{}\n" + }, + "responseParameters": { + "method.response.header.Access-Control-Allow-Origin": "*", + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'" + } + } + } + }, + "consumes": [ + "application/json" + ], + "summary": "CORS support", + "responses": { + "200": { + "headers": { + "Access-Control-Allow-Origin": { + "type": "string" + }, + "Access-Control-Allow-Methods": { + "type": "string" + } + }, + "description": "Default response for CORS method" + } + }, + "produces": [ + "application/json" + ] + }, + "get": { + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations" + } + }, + "responses": {} + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + } + }, + "ExplicitApiDeployment5332c373d4": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "RestApiId": { + "Ref": "ExplicitApi" + }, + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7" + } + } + } +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/explicit_api_openapi_3.json b/tests/translator/output/aws-us-gov/explicit_api_openapi_3.json index 1dbc4a782..307a76ae2 100644 --- a/tests/translator/output/aws-us-gov/explicit_api_openapi_3.json +++ b/tests/translator/output/aws-us-gov/explicit_api_openapi_3.json @@ -37,7 +37,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ApiWithInlineSwaggerDeploymentf98588d7ff" + "Ref": "ApiWithInlineSwaggerDeployment09cda3d97b" }, "RestApiId": { "Ref": "ApiWithInlineSwagger" @@ -68,26 +68,6 @@ } } }, - "GetHtmlApiStage": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "DeploymentId": { - "Ref": "GetHtmlApiDeploymentf117c932f7" - }, - "RestApiId": { - "Ref": "GetHtmlApi" - }, - "Variables": { - "EndpointUri": { - "Ref": "something" - }, - "EndpointUri2": "http://example.com" - }, - "StageName": { - "Ref": "MyStageName" - } - } - }, "GetHtmlApiDeploymentf117c932f7": { "Type": "AWS::ApiGateway::Deployment", "Properties": { @@ -128,8 +108,7 @@ "Properties": { "Body": { "this": "is", - "a": "inline swagger", - "openapi": "3.0" + "a": "inline swagger" }, "EndpointConfiguration": { "Types": [ @@ -172,23 +151,43 @@ "REGIONAL" ] }, - "Name": "MyGetApi", - "Parameters": { - "endpointConfigurationTypes": "REGIONAL" - }, "BodyS3Location": { "Bucket": "sam-demo-bucket", "Key": "webpage_swagger.json" + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + }, + "Name": "MyGetApi" + } + }, + "GetHtmlApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "GetHtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Variables": { + "EndpointUri": { + "Ref": "something" + }, + "EndpointUri2": "http://example.com" + }, + "StageName": { + "Ref": "MyStageName" } } }, - "ApiWithInlineSwaggerDeploymentf98588d7ff": { + "ApiWithInlineSwaggerDeployment09cda3d97b": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { "Ref": "ApiWithInlineSwagger" }, - "Description": "RestApi deployment id: f98588d7ff10d9add9be1344fbe7daff2e100b78" + "Description": "RestApi deployment id: 09cda3d97b008bed7bd4ebb1b5304ed622492941" } } } diff --git a/tests/translator/output/error_api_with_invalid_open_api_version.json b/tests/translator/output/error_api_with_invalid_open_api_version.json index 36478c832..451e7373e 100644 --- a/tests/translator/output/error_api_with_invalid_open_api_version.json +++ b/tests/translator/output/error_api_with_invalid_open_api_version.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "Resource with id [MyApi] is invalid. The OpenApiVersion value must be one of [2.0, 3.0]" + "errorMessage": "Resource with id [MyApi] is invalid. The OpenApiVersion value must be of the format 2.x.x or 3.x.x" } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyApi] is invalid. The OpenApiVersion value must be one of [2.0, 3.0]" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyApi] is invalid. The OpenApiVersion value must be of the format 2.x.x or 3.x.x" } \ No newline at end of file diff --git a/tests/translator/output/explicit_api_openapi_3.json b/tests/translator/output/explicit_api_openapi_3.json index d8ecaf072..327871d4d 100644 --- a/tests/translator/output/explicit_api_openapi_3.json +++ b/tests/translator/output/explicit_api_openapi_3.json @@ -37,7 +37,7 @@ "Type": "AWS::ApiGateway::Stage", "Properties": { "DeploymentId": { - "Ref": "ApiWithInlineSwaggerDeploymentf98588d7ff" + "Ref": "ApiWithInlineSwaggerDeployment09cda3d97b" }, "RestApiId": { "Ref": "ApiWithInlineSwagger" @@ -68,26 +68,6 @@ } } }, - "GetHtmlApiStage": { - "Type": "AWS::ApiGateway::Stage", - "Properties": { - "DeploymentId": { - "Ref": "GetHtmlApiDeploymentf117c932f7" - }, - "RestApiId": { - "Ref": "GetHtmlApi" - }, - "Variables": { - "EndpointUri": { - "Ref": "something" - }, - "EndpointUri2": "http://example.com" - }, - "StageName": { - "Ref": "MyStageName" - } - } - }, "GetHtmlApiDeploymentf117c932f7": { "Type": "AWS::ApiGateway::Deployment", "Properties": { @@ -128,8 +108,7 @@ "Properties": { "Body": { "this": "is", - "a": "inline swagger", - "openapi": "3.0" + "a": "inline swagger" } } }, @@ -159,20 +138,40 @@ "GetHtmlApi": { "Type": "AWS::ApiGateway::RestApi", "Properties": { - "Name": "MyGetApi", "BodyS3Location": { "Bucket": "sam-demo-bucket", "Key": "webpage_swagger.json" + }, + "Name": "MyGetApi" + } + }, + "GetHtmlApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "DeploymentId": { + "Ref": "GetHtmlApiDeploymentf117c932f7" + }, + "RestApiId": { + "Ref": "GetHtmlApi" + }, + "Variables": { + "EndpointUri": { + "Ref": "something" + }, + "EndpointUri2": "http://example.com" + }, + "StageName": { + "Ref": "MyStageName" } } }, - "ApiWithInlineSwaggerDeploymentf98588d7ff": { + "ApiWithInlineSwaggerDeployment09cda3d97b": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "RestApiId": { "Ref": "ApiWithInlineSwagger" }, - "Description": "RestApi deployment id: f98588d7ff10d9add9be1344fbe7daff2e100b78" + "Description": "RestApi deployment id: 09cda3d97b008bed7bd4ebb1b5304ed622492941" } } } diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index 329cc0a33..20f9df676 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -197,6 +197,7 @@ class TestTranslatorEndToEnd(TestCase): 'api_with_gateway_responses_implicit', 'api_with_gateway_responses_string_status_code', 'api_with_open_api_version', + 'api_with_open_api_version_2', 'api_cache', 'api_with_access_log_setting', 'api_with_canary_setting', From c27ef23673afa7d36fcf4aecb60dd9a3cbe82bcc Mon Sep 17 00:00:00 2001 From: praneetap Date: Tue, 28 May 2019 16:09:00 -0700 Subject: [PATCH 11/13] Addressing stage stage cr comment --- samtranslator/model/apigateway.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index 731fe039e..37347ebdc 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -39,7 +39,7 @@ class ApiGatewayStage(Resource): 'DeploymentId': PropertyType(True, is_str()), 'Description': PropertyType(False, is_str()), 'RestApiId': PropertyType(True, is_str()), - 'StageName': PropertyType(False, one_of(is_str(), is_type(dict))), + 'StageName': PropertyType(True, one_of(is_str(), is_type(dict))), 'TracingEnabled': PropertyType(False, is_type(bool)), 'Variables': PropertyType(False, is_type(dict)), "MethodSettings": PropertyType(False, is_type(list)) From dcc3619f9c577eb0a1a9d43bb19592936da2127b Mon Sep 17 00:00:00 2001 From: praneetap Date: Wed, 29 May 2019 15:14:38 -0700 Subject: [PATCH 12/13] Addressing cr comments --- docs/cloudformation_compatibility.rst | 2 +- samtranslator/model/api/api_generator.py | 5 ++--- samtranslator/plugins/globals/globals.py | 5 +++-- samtranslator/swagger/swagger.py | 13 +++++++++++-- .../error_api_with_invalid_open_api_version.json | 4 ++-- 5 files changed, 19 insertions(+), 10 deletions(-) diff --git a/docs/cloudformation_compatibility.rst b/docs/cloudformation_compatibility.rst index 89daa985a..9118c3395 100644 --- a/docs/cloudformation_compatibility.rst +++ b/docs/cloudformation_compatibility.rst @@ -171,7 +171,7 @@ BinaryMediaTypes All MinimumCompressionSize All Cors All TracingEnabled All -OpenApiVersion All +OpenApiVersion None ================================== ======================== ======================== diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 670237f6d..cf4aee032 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -24,7 +24,6 @@ AuthProperties.__new__.__defaults__ = (None, None, None) GatewayResponseProperties = ["ResponseParameters", "ResponseTemplates", "StatusCode"] -OpenApiVersionsSupportedRegex = r"\A[2-3](\.\d)(\.\d)?$" class ApiGenerator(object): @@ -98,9 +97,9 @@ def _construct_rest_api(self): "Specify either 'DefinitionUri' or 'DefinitionBody' property and not both") if self.open_api_version: - if re.match(OpenApiVersionsSupportedRegex, self.open_api_version) is None: + if re.match(SwaggerEditor.get_openapi_versions_supported_regex(), self.open_api_version) is None: raise InvalidResourceException( - self.logical_id, "The OpenApiVersion value must be of the format 2.x.x or 3.x.x") + self.logical_id, "The OpenApiVersion value must be 3.0.0") self._add_cors() self._add_auth() diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index d3889b405..1e5702ccc 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -1,5 +1,6 @@ from samtranslator.public.sdk.resource import SamResourceType from samtranslator.public.intrinsics import is_intrinsics +from samtranslator.swagger.swagger import SwaggerEditor import re @@ -15,7 +16,6 @@ class Globals(object): _OPENAPIVERSION = "OpenApiVersion" _API_TYPE = "AWS::Serverless::Api" _MANAGE_SWAGGER = "__MANAGE_SWAGGER" - _OPENAPIVERSION_REGEX = r"\A3(\.\d)(\.\d)?$" supported_properties = { # Everything on Serverless::Function except Role, Policies, FunctionName, Events @@ -135,7 +135,8 @@ def fix_openapi_definitions(cls, template): if ("Type" in resource) and (resource["Type"] == cls._API_TYPE): properties = resource["Properties"] if (cls._OPENAPIVERSION in properties) and (cls._MANAGE_SWAGGER in properties) and \ - (re.match(cls._OPENAPIVERSION_REGEX, properties[cls._OPENAPIVERSION]) is not None): + (re.match(SwaggerEditor.get_openapi_version_3_regex(), + properties[cls._OPENAPIVERSION]) is not None): if "DefinitionBody" in properties: definition_body = properties['DefinitionBody'] definition_body['openapi'] = properties[cls._OPENAPIVERSION] diff --git a/samtranslator/swagger/swagger.py b/samtranslator/swagger/swagger.py index 11b0704ca..8421cc6d2 100644 --- a/samtranslator/swagger/swagger.py +++ b/samtranslator/swagger/swagger.py @@ -555,13 +555,12 @@ def is_valid(data): :param dict data: Data to be validated :return: True, if data is a Swagger """ - openapi_version_supported_regex = r"\A3(\.\d)(\.\d)?$" if bool(data) and isinstance(data, dict) and isinstance(data.get('paths'), dict): if bool(data.get("swagger")): return True elif bool(data.get("openapi")): - return re.search(openapi_version_supported_regex, data["openapi"]) is not None + return re.search(SwaggerEditor.get_openapi_version_3_regex(), data["openapi"]) is not None return False return False @@ -601,3 +600,13 @@ def _normalize_method_name(method): return SwaggerEditor._X_ANY_METHOD else: return method + + @staticmethod + def get_openapi_versions_supported_regex(): + openapi_version_supported_regex = r"\A[2-3](\.\d)(\.\d)?$" + return openapi_version_supported_regex + + @staticmethod + def get_openapi_version_3_regex(): + openapi_version_3_regex = r"\A3(\.\d)(\.\d)?$" + return openapi_version_3_regex diff --git a/tests/translator/output/error_api_with_invalid_open_api_version.json b/tests/translator/output/error_api_with_invalid_open_api_version.json index 451e7373e..9f91f1c33 100644 --- a/tests/translator/output/error_api_with_invalid_open_api_version.json +++ b/tests/translator/output/error_api_with_invalid_open_api_version.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "Resource with id [MyApi] is invalid. The OpenApiVersion value must be of the format 2.x.x or 3.x.x" + "errorMessage": "Resource with id [MyApi] is invalid. The OpenApiVersion value must be 3.0.0" } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyApi] is invalid. The OpenApiVersion value must be of the format 2.x.x or 3.x.x" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyApi] is invalid. The OpenApiVersion value must be 3.0.0" } \ No newline at end of file From 3a8719f5c5b7fc746c8c1eeb4c5c5f916bdd6ed9 Mon Sep 17 00:00:00 2001 From: praneetap Date: Wed, 29 May 2019 20:02:18 -0700 Subject: [PATCH 13/13] Addressed cr comments --- samtranslator/model/api/api_generator.py | 2 +- .../output/error_api_with_invalid_open_api_version.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index cf4aee032..be60b0d5a 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -99,7 +99,7 @@ def _construct_rest_api(self): if self.open_api_version: if re.match(SwaggerEditor.get_openapi_versions_supported_regex(), self.open_api_version) is None: raise InvalidResourceException( - self.logical_id, "The OpenApiVersion value must be 3.0.0") + self.logical_id, "The OpenApiVersion value must be of the format 3.0.0") self._add_cors() self._add_auth() diff --git a/tests/translator/output/error_api_with_invalid_open_api_version.json b/tests/translator/output/error_api_with_invalid_open_api_version.json index 9f91f1c33..8bac5a42d 100644 --- a/tests/translator/output/error_api_with_invalid_open_api_version.json +++ b/tests/translator/output/error_api_with_invalid_open_api_version.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "Resource with id [MyApi] is invalid. The OpenApiVersion value must be 3.0.0" + "errorMessage": "Resource with id [MyApi] is invalid. The OpenApiVersion value must be of the format 3.0.0" } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyApi] is invalid. The OpenApiVersion value must be 3.0.0" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [MyApi] is invalid. The OpenApiVersion value must be of the format 3.0.0" } \ No newline at end of file