From 0ed3a299bf82b867f3a3d812351c6af0373a8fac Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Thu, 2 Mar 2023 15:53:37 -0800 Subject: [PATCH 01/13] Add a new property IndividualRecordSet to disable merging into record set group --- .../input/individual_route53_recordset.yaml | 82 +++++ .../aws-cn/individual_route53_recordset.json | 344 ++++++++++++++++++ .../individual_route53_recordset.json | 344 ++++++++++++++++++ .../output/individual_route53_recordset.json | 344 ++++++++++++++++++ 4 files changed, 1114 insertions(+) create mode 100644 tests/translator/input/individual_route53_recordset.yaml create mode 100644 tests/translator/output/aws-cn/individual_route53_recordset.json create mode 100644 tests/translator/output/aws-us-gov/individual_route53_recordset.json create mode 100644 tests/translator/output/individual_route53_recordset.json diff --git a/tests/translator/input/individual_route53_recordset.yaml b/tests/translator/input/individual_route53_recordset.yaml new file mode 100644 index 000000000..c03d617fd --- /dev/null +++ b/tests/translator/input/individual_route53_recordset.yaml @@ -0,0 +1,82 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + apigateway-2402 + + Sample SAM Template for apigateway-2402 + +Parameters: + EnvType: + Description: Environment type. + Default: test + Type: String + AllowedValues: + - prod + - test + ConstraintDescription: must specify prod or test. +Conditions: + CreateProdResources: !Equals + - !Ref EnvType + - prod +Resources: + ApiGatewayAdminOne: + Type: AWS::Serverless::Api + Properties: + Name: App-Prod-Web + StageName: Prod + TracingEnabled: true + MethodSettings: + - LoggingLevel: Info + ResourcePath: /* + HttpMethod: '*' + Domain: + DomainName: admin.one.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + EndpointConfiguration: + Type: REGIONAL + + + ApiGatewayAdminTwo: + Type: AWS::Serverless::Api + Condition: CreateProdResources + Properties: + Name: App-Prod-Web + StageName: Prod + TracingEnabled: true + MethodSettings: + - LoggingLevel: Info + ResourcePath: /* + HttpMethod: '*' + Domain: + DomainName: admin.two.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + EndpointConfiguration: + Type: REGIONAL + IndividualRecordSet: true + + + ApiGatewayAdminThree: + Type: AWS::Serverless::Api + Properties: + Name: App-Prod-Web + StageName: Prod + TracingEnabled: true + MethodSettings: + - LoggingLevel: Info + ResourcePath: /* + HttpMethod: '*' + Domain: + DomainName: admin.three.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + EndpointConfiguration: + Type: REGIONAL + IndividualRecordSet: true diff --git a/tests/translator/output/aws-cn/individual_route53_recordset.json b/tests/translator/output/aws-cn/individual_route53_recordset.json new file mode 100644 index 000000000..c694e07d5 --- /dev/null +++ b/tests/translator/output/aws-cn/individual_route53_recordset.json @@ -0,0 +1,344 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Conditions": { + "CreateProdResources": { + "Fn::Equals": [ + { + "Ref": "EnvType" + }, + "prod" + ] + } + }, + "Description": "apigateway-2402\nSample SAM Template for apigateway-2402\n", + "Parameters": { + "EnvType": { + "AllowedValues": [ + "prod", + "test" + ], + "ConstraintDescription": "must specify prod or test.", + "Default": "test", + "Description": "Environment type.", + "Type": "String" + } + }, + "Resources": { + "ApiGatewayAdminOne": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminOneBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName5fe29fe649" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "Stage": { + "Ref": "ApiGatewayAdminOneProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminOneDeploymentdd3f545183": { + "Properties": { + "Description": "RestApi deployment id: dd3f545183668c401e771fd9a377cfeadcf88a35", + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminOneProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminOneDeploymentdd3f545183" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayAdminThree": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminThreeBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName41bfc7f9c4" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "Stage": { + "Ref": "ApiGatewayAdminThreeProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminThreeDeployment7541e97159": { + "Properties": { + "Description": "RestApi deployment id: 7541e971598cffe7cafab030d3fccc687d508f59", + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminThreeProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminThreeDeployment7541e97159" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayAdminTwo": { + "Condition": "CreateProdResources", + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminTwoBasePathMapping": { + "Condition": "CreateProdResources", + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName3fd2dbd8f8" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "Stage": { + "Ref": "ApiGatewayAdminTwoProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminTwoDeployment61887a4eed": { + "Condition": "CreateProdResources", + "Properties": { + "Description": "RestApi deployment id: 61887a4eed03102402cbaa575b5b1e398b0dc647", + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminTwoProdStage": { + "Condition": "CreateProdResources", + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminTwoDeployment61887a4eed" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayDomainName3fd2dbd8f8": { + "Condition": "CreateProdResources", + "Properties": { + "DomainName": "admin.two.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiGatewayDomainName41bfc7f9c4": { + "Properties": { + "DomainName": "admin.three.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiGatewayDomainName5fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "RecordSet81840409a4": { + "Properties": { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "HostedZoneId": "abc123456", + "Name": "admin.three.amazon.com", + "Type": "A" + }, + "Type": "AWS::Route53::RecordSet" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName5fe29fe649", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName5fe29fe649", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.one.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + }, + "RecordSetb3fa99c196": { + "Condition": "CreateProdResources", + "Properties": { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "HostedZoneId": "abc123456", + "Name": "admin.two.amazon.com", + "Type": "A" + }, + "Type": "AWS::Route53::RecordSet" + } + } +} diff --git a/tests/translator/output/aws-us-gov/individual_route53_recordset.json b/tests/translator/output/aws-us-gov/individual_route53_recordset.json new file mode 100644 index 000000000..c694e07d5 --- /dev/null +++ b/tests/translator/output/aws-us-gov/individual_route53_recordset.json @@ -0,0 +1,344 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Conditions": { + "CreateProdResources": { + "Fn::Equals": [ + { + "Ref": "EnvType" + }, + "prod" + ] + } + }, + "Description": "apigateway-2402\nSample SAM Template for apigateway-2402\n", + "Parameters": { + "EnvType": { + "AllowedValues": [ + "prod", + "test" + ], + "ConstraintDescription": "must specify prod or test.", + "Default": "test", + "Description": "Environment type.", + "Type": "String" + } + }, + "Resources": { + "ApiGatewayAdminOne": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminOneBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName5fe29fe649" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "Stage": { + "Ref": "ApiGatewayAdminOneProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminOneDeploymentdd3f545183": { + "Properties": { + "Description": "RestApi deployment id: dd3f545183668c401e771fd9a377cfeadcf88a35", + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminOneProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminOneDeploymentdd3f545183" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayAdminThree": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminThreeBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName41bfc7f9c4" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "Stage": { + "Ref": "ApiGatewayAdminThreeProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminThreeDeployment7541e97159": { + "Properties": { + "Description": "RestApi deployment id: 7541e971598cffe7cafab030d3fccc687d508f59", + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminThreeProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminThreeDeployment7541e97159" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayAdminTwo": { + "Condition": "CreateProdResources", + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminTwoBasePathMapping": { + "Condition": "CreateProdResources", + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName3fd2dbd8f8" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "Stage": { + "Ref": "ApiGatewayAdminTwoProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminTwoDeployment61887a4eed": { + "Condition": "CreateProdResources", + "Properties": { + "Description": "RestApi deployment id: 61887a4eed03102402cbaa575b5b1e398b0dc647", + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminTwoProdStage": { + "Condition": "CreateProdResources", + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminTwoDeployment61887a4eed" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayDomainName3fd2dbd8f8": { + "Condition": "CreateProdResources", + "Properties": { + "DomainName": "admin.two.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiGatewayDomainName41bfc7f9c4": { + "Properties": { + "DomainName": "admin.three.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiGatewayDomainName5fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "RecordSet81840409a4": { + "Properties": { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "HostedZoneId": "abc123456", + "Name": "admin.three.amazon.com", + "Type": "A" + }, + "Type": "AWS::Route53::RecordSet" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName5fe29fe649", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName5fe29fe649", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.one.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + }, + "RecordSetb3fa99c196": { + "Condition": "CreateProdResources", + "Properties": { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "HostedZoneId": "abc123456", + "Name": "admin.two.amazon.com", + "Type": "A" + }, + "Type": "AWS::Route53::RecordSet" + } + } +} diff --git a/tests/translator/output/individual_route53_recordset.json b/tests/translator/output/individual_route53_recordset.json new file mode 100644 index 000000000..c694e07d5 --- /dev/null +++ b/tests/translator/output/individual_route53_recordset.json @@ -0,0 +1,344 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Conditions": { + "CreateProdResources": { + "Fn::Equals": [ + { + "Ref": "EnvType" + }, + "prod" + ] + } + }, + "Description": "apigateway-2402\nSample SAM Template for apigateway-2402\n", + "Parameters": { + "EnvType": { + "AllowedValues": [ + "prod", + "test" + ], + "ConstraintDescription": "must specify prod or test.", + "Default": "test", + "Description": "Environment type.", + "Type": "String" + } + }, + "Resources": { + "ApiGatewayAdminOne": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminOneBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName5fe29fe649" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "Stage": { + "Ref": "ApiGatewayAdminOneProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminOneDeploymentdd3f545183": { + "Properties": { + "Description": "RestApi deployment id: dd3f545183668c401e771fd9a377cfeadcf88a35", + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminOneProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminOneDeploymentdd3f545183" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminOne" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayAdminThree": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminThreeBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName41bfc7f9c4" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "Stage": { + "Ref": "ApiGatewayAdminThreeProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminThreeDeployment7541e97159": { + "Properties": { + "Description": "RestApi deployment id: 7541e971598cffe7cafab030d3fccc687d508f59", + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminThreeProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminThreeDeployment7541e97159" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminThree" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayAdminTwo": { + "Condition": "CreateProdResources", + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Name": "App-Prod-Web", + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiGatewayAdminTwoBasePathMapping": { + "Condition": "CreateProdResources", + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainName3fd2dbd8f8" + }, + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "Stage": { + "Ref": "ApiGatewayAdminTwoProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiGatewayAdminTwoDeployment61887a4eed": { + "Condition": "CreateProdResources", + "Properties": { + "Description": "RestApi deployment id: 61887a4eed03102402cbaa575b5b1e398b0dc647", + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayAdminTwoProdStage": { + "Condition": "CreateProdResources", + "Properties": { + "DeploymentId": { + "Ref": "ApiGatewayAdminTwoDeployment61887a4eed" + }, + "MethodSettings": [ + { + "HttpMethod": "*", + "LoggingLevel": "Info", + "ResourcePath": "/*" + } + ], + "RestApiId": { + "Ref": "ApiGatewayAdminTwo" + }, + "StageName": "Prod", + "TracingEnabled": true + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiGatewayDomainName3fd2dbd8f8": { + "Condition": "CreateProdResources", + "Properties": { + "DomainName": "admin.two.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiGatewayDomainName41bfc7f9c4": { + "Properties": { + "DomainName": "admin.three.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiGatewayDomainName5fe29fe649": { + "Properties": { + "DomainName": "admin.one.amazon.com", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": "arn::cert::abc" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "RecordSet81840409a4": { + "Properties": { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "HostedZoneId": "abc123456", + "Name": "admin.three.amazon.com", + "Type": "A" + }, + "Type": "AWS::Route53::RecordSet" + }, + "RecordSetGroup370194ff6e": { + "Properties": { + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName5fe29fe649", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName5fe29fe649", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.one.amazon.com", + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + }, + "RecordSetb3fa99c196": { + "Condition": "CreateProdResources", + "Properties": { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "HostedZoneId": "abc123456", + "Name": "admin.two.amazon.com", + "Type": "A" + }, + "Type": "AWS::Route53::RecordSet" + } + } +} From 955a43f4c4ddb76356b8bf93b18e85441f76938a Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Thu, 2 Mar 2023 15:53:58 -0800 Subject: [PATCH 02/13] Add a new property IndividualRecordSet to disable merging into record set group --- .../schema_source/aws_serverless_api.py | 2 + samtranslator/model/api/api_generator.py | 67 +++++++++++++++++-- samtranslator/model/route53.py | 18 ++++- samtranslator/model/sam_resources.py | 6 ++ samtranslator/schema/schema.json | 4 ++ schema_source/sam.schema.json | 4 ++ 6 files changed, 94 insertions(+), 7 deletions(-) diff --git a/samtranslator/internal/schema_source/aws_serverless_api.py b/samtranslator/internal/schema_source/aws_serverless_api.py index 8b0c55dff..26fbb0e16 100644 --- a/samtranslator/internal/schema_source/aws_serverless_api.py +++ b/samtranslator/internal/schema_source/aws_serverless_api.py @@ -176,6 +176,7 @@ class EndpointConfiguration(BaseModel): TracingEnabled = Optional[PassThroughProp] OpenApiVersion = Optional[Union[float, str]] # TODO: float doesn't exist in documentation AlwaysDeploy = Optional[bool] +IndividualRecordSet = Optional[bool] class Properties(BaseModel): @@ -207,6 +208,7 @@ class Properties(BaseModel): TracingEnabled: Optional[TracingEnabled] = properties("TracingEnabled") Variables: Optional[Variables] = properties("Variables") AlwaysDeploy: Optional[AlwaysDeploy] # TODO: Add docs + IndividualRecordSet: Optional[IndividualRecordSet] # TODO: Add docs class Globals(BaseModel): diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 837ad4dd6..fb22024c6 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -23,7 +23,7 @@ ) from samtranslator.model.intrinsics import fnGetAtt, fnSub, is_intrinsic, make_or_condition, ref from samtranslator.model.lambda_ import LambdaPermission -from samtranslator.model.route53 import Route53RecordSetGroup +from samtranslator.model.route53 import Route53RecordSet, Route53RecordSetGroup from samtranslator.model.s3_utils.uri_parser import parse_s3_uri from samtranslator.model.tags.resource_tagging import get_tag_list from samtranslator.model.types import PassThrough @@ -196,6 +196,7 @@ def __init__( # noqa: too-many-arguments mode: Optional[Intrinsicable[str]] = None, api_key_source_type: Optional[Intrinsicable[str]] = None, always_deploy: Optional[bool] = False, + individual_recordset: Optional[bool] = False, ): """Constructs an API Generator class that generates API Gateway resources @@ -252,6 +253,7 @@ def __init__( # noqa: too-many-arguments self.mode = mode self.api_key_source_type = api_key_source_type self.always_deploy = always_deploy + self.individual_recordset = individual_recordset def _construct_rest_api(self) -> ApiGatewayRestApi: """Constructs and returns the ApiGateway RestApi. @@ -443,12 +445,12 @@ def _construct_stage( def _construct_api_domain( # noqa: too-many-branches self, rest_api: ApiGatewayRestApi, route53_record_set_groups: Any - ) -> Tuple[Optional[ApiGatewayDomainName], Optional[List[ApiGatewayBasePathMapping]], Any]: + ) -> Tuple[Optional[ApiGatewayDomainName], Optional[List[ApiGatewayBasePathMapping]], Any, Any]: """ Constructs and returns the ApiGateway Domain and BasepathMapping """ if self.domain is None: - return None, None, None + return None, None, None, None sam_expect(self.domain, self.logical_id, "Domain").to_be_a_map() domain_name: PassThrough = sam_expect( @@ -565,6 +567,15 @@ def _construct_api_domain( # noqa: too-many-branches logical_id = "RecordSetGroup" + logical_id_suffix record_set_group = route53_record_set_groups.get(logical_id) + + if self.individual_recordset: + return ( + domain, + basepath_resource_list, + None, + self._construct_individual_record_set(self.domain, api_domain_name, route53), + ) + if not record_set_group: record_set_group = Route53RecordSetGroup(logical_id, attributes=self.passthrough_resource_attributes) if "HostedZoneId" in route53: @@ -576,7 +587,39 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group.RecordSets += self._construct_record_sets_for_domain(self.domain, api_domain_name, route53) - return domain, basepath_resource_list, record_set_group + return domain, basepath_resource_list, record_set_group, None + + def _construct_individual_record_set( + self, domain: Dict[str, Any], api_domain_name: str, route53: Any + ) -> List[Route53RecordSet]: + logical_id_suffix = LogicalIdGenerator( + "", [route53.get("HostedZoneId") or route53.get("HostedZoneName"), domain.get("DomainName")] + ).gen() + logical_id = "RecordSet" + logical_id_suffix + logical_id_ipv6 = "RecordSetIpv6" + logical_id_suffix + + recordset_list = [] + + recordset = Route53RecordSet(logical_id, attributes=self.passthrough_resource_attributes) + recordset.Name = domain.get("DomainName") + recordset.Type = "A" + recordset.AliasTarget = self._construct_alias_target(domain, api_domain_name, route53) + + if route53.get("HostedZoneId"): + recordset.HostedZoneId = route53.get("HostedZoneId") + else: + recordset.HostedZoneName = route53.get("HostedZoneName") + + recordset_list.extend([recordset]) + + if route53.get("IpV6"): + recordset_ipv6 = Route53RecordSet(logical_id_ipv6, attributes=self.passthrough_resource_attributes) + recordset_ipv6.Name = domain.get("DomainName") + recordset_ipv6.Type = "AAAA" + recordset_ipv6.AliasTarget = self._construct_alias_target(domain, api_domain_name, route53) + recordset_list.extend([recordset_ipv6]) + + return recordset_list def _construct_record_sets_for_domain( self, custom_domain_config: Dict[str, Any], api_domain_name: str, route53_config: Dict[str, Any] @@ -633,7 +676,9 @@ def to_cloudformation(self, redeploy_restapi_parameters, route53_record_set_grou :rtype: tuple """ rest_api = self._construct_rest_api() - domain, basepath_mapping, route53 = self._construct_api_domain(rest_api, route53_record_set_groups) + domain, basepath_mapping, route53, individual_route53 = self._construct_api_domain( + rest_api, route53_record_set_groups + ) deployment = self._construct_deployment(rest_api) swagger = None @@ -646,7 +691,17 @@ def to_cloudformation(self, redeploy_restapi_parameters, route53_record_set_grou permissions = self._construct_authorizer_lambda_permission() usage_plan = self._construct_usage_plan(rest_api_stage=stage) - return rest_api, deployment, stage, permissions, domain, basepath_mapping, route53, usage_plan + return ( + rest_api, + deployment, + stage, + permissions, + domain, + basepath_mapping, + route53, + usage_plan, + individual_route53, + ) def _add_cors(self) -> None: """ diff --git a/samtranslator/model/route53.py b/samtranslator/model/route53.py index deab5c522..c3a033841 100644 --- a/samtranslator/model/route53.py +++ b/samtranslator/model/route53.py @@ -1,4 +1,4 @@ -from typing import Any, List, Optional +from typing import Any, Dict, List, Optional from samtranslator.model import GeneratedProperty, Resource from samtranslator.utils.types import Intrinsicable @@ -15,3 +15,19 @@ class Route53RecordSetGroup(Resource): HostedZoneId: Optional[Intrinsicable[str]] HostedZoneName: Optional[Intrinsicable[str]] RecordSets: Optional[List[Any]] + + +class Route53RecordSet(Resource): + resource_type = "AWS::Route53::RecordSet" + property_types = { + "HostedZoneId": GeneratedProperty(), + "HostedZoneName": GeneratedProperty(), + "AliasTarget": GeneratedProperty(), + "Name": GeneratedProperty(), + "Type": GeneratedProperty(), + } + HostedZoneId: Optional[Intrinsicable[str]] + HostedZoneName: Optional[Intrinsicable[str]] + AliasTarget: Optional[Dict[str, Any]] + Name: Optional[Intrinsicable[str]] + Type: Optional[Intrinsicable[str]] diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 63ce47f77..98ac996b6 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -1179,6 +1179,7 @@ class SamApi(SamResourceMacro): "DisableExecuteApiEndpoint": PropertyType(False, IS_BOOL), "ApiKeySourceType": PropertyType(False, IS_STR), "AlwaysDeploy": Property(False, IS_BOOL), + "IndividualRecordSet": Property(False, IS_BOOL), } Name: Optional[Intrinsicable[str]] @@ -1209,6 +1210,7 @@ class SamApi(SamResourceMacro): DisableExecuteApiEndpoint: Optional[Intrinsicable[bool]] ApiKeySourceType: Optional[Intrinsicable[str]] AlwaysDeploy: Optional[bool] + IndividualRecordSet: Optional[bool] referable_properties = { "Stage": ApiGatewayStage.resource_type, @@ -1274,6 +1276,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] mode=self.Mode, api_key_source_type=self.ApiKeySourceType, always_deploy=self.AlwaysDeploy, + individual_recordset=self.IndividualRecordSet, ) ( @@ -1285,6 +1288,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] basepath_mapping, route53, usage_plan_resources, + individual_route53, ) = api_generator.to_cloudformation(redeploy_restapi_parameters, route53_record_set_groups) resources.extend([rest_api, deployment, stage]) @@ -1298,6 +1302,8 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # contains usage plan, api key and usageplan key resources if usage_plan_resources: resources.extend(usage_plan_resources) + if individual_route53: + resources.extend(individual_route53) return resources diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index 135fd8f22..137afb523 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -197873,6 +197873,10 @@ "title": "GatewayResponses", "type": "object" }, + "IndividualRecordSet": { + "title": "Individualrecordset", + "type": "boolean" + }, "MergeDefinitions": { "title": "Mergedefinitions", "type": "boolean" diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index b45d2a069..79fdb1824 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -3596,6 +3596,10 @@ "title": "GatewayResponses", "type": "object" }, + "IndividualRecordSet": { + "title": "Individualrecordset", + "type": "boolean" + }, "MergeDefinitions": { "title": "Mergedefinitions", "type": "boolean" From cff46d69324b3324751bab4d76ff23c901c82e25 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Tue, 14 Mar 2023 15:08:08 -0700 Subject: [PATCH 03/13] rebase upstream branch to resolve conlficts --- .../schema_source/aws_serverless_api.py | 3 +- samtranslator/model/api/api_generator.py | 32 ++++++++++++------- samtranslator/model/sam_resources.py | 7 ++-- samtranslator/schema/schema.json | 8 ++--- schema_source/sam.schema.json | 8 ++--- ...t.yaml => separate_route53_recordset.yaml} | 4 +-- ...t.json => separate_route53_recordset.json} | 12 +++---- ...t.json => separate_route53_recordset.json} | 12 +++---- ...t.json => separate_route53_recordset.json} | 12 +++---- 9 files changed, 52 insertions(+), 46 deletions(-) rename tests/translator/input/{individual_route53_recordset.yaml => separate_route53_recordset.yaml} (96%) rename tests/translator/output/aws-cn/{individual_route53_recordset.json => separate_route53_recordset.json} (95%) rename tests/translator/output/aws-us-gov/{individual_route53_recordset.json => separate_route53_recordset.json} (95%) rename tests/translator/output/{individual_route53_recordset.json => separate_route53_recordset.json} (95%) diff --git a/samtranslator/internal/schema_source/aws_serverless_api.py b/samtranslator/internal/schema_source/aws_serverless_api.py index 26fbb0e16..c3eb9f6dd 100644 --- a/samtranslator/internal/schema_source/aws_serverless_api.py +++ b/samtranslator/internal/schema_source/aws_serverless_api.py @@ -134,6 +134,7 @@ class Route53(BaseModel): IpV6: Optional[bool] = route53("IpV6") SetIdentifier: Optional[PassThroughProp] # TODO: add docs Region: Optional[PassThroughProp] # TODO: add docs + SeparateRecordSets: Optional[bool] # TODO: add docs class Domain(BaseModel): @@ -176,7 +177,6 @@ class EndpointConfiguration(BaseModel): TracingEnabled = Optional[PassThroughProp] OpenApiVersion = Optional[Union[float, str]] # TODO: float doesn't exist in documentation AlwaysDeploy = Optional[bool] -IndividualRecordSet = Optional[bool] class Properties(BaseModel): @@ -208,7 +208,6 @@ class Properties(BaseModel): TracingEnabled: Optional[TracingEnabled] = properties("TracingEnabled") Variables: Optional[Variables] = properties("Variables") AlwaysDeploy: Optional[AlwaysDeploy] # TODO: Add docs - IndividualRecordSet: Optional[IndividualRecordSet] # TODO: Add docs class Globals(BaseModel): diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index fb22024c6..12d93a28b 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -1,6 +1,7 @@ import logging from collections import namedtuple -from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast +from dataclasses import dataclass +from typing import Any, Dict, List, Optional, Set, Union, cast from samtranslator.metrics.method_decorator import cw_timer from samtranslator.model.apigateway import ( @@ -67,6 +68,14 @@ GatewayResponseProperties = ["ResponseParameters", "ResponseTemplates", "StatusCode"] +@dataclass +class ApiDomainResponse: + Domain: Optional[ApiGatewayDomainName] + ApiGWBasePathMappingList: Optional[List[ApiGatewayBasePathMapping]] + RecordSetsGroup: Any + RecordSet: Optional[List[Route53RecordSet]] + + class SharedApiUsagePlan: """ Collects API information from different API resources in the same template, @@ -196,7 +205,6 @@ def __init__( # noqa: too-many-arguments mode: Optional[Intrinsicable[str]] = None, api_key_source_type: Optional[Intrinsicable[str]] = None, always_deploy: Optional[bool] = False, - individual_recordset: Optional[bool] = False, ): """Constructs an API Generator class that generates API Gateway resources @@ -253,7 +261,6 @@ def __init__( # noqa: too-many-arguments self.mode = mode self.api_key_source_type = api_key_source_type self.always_deploy = always_deploy - self.individual_recordset = individual_recordset def _construct_rest_api(self) -> ApiGatewayRestApi: """Constructs and returns the ApiGateway RestApi. @@ -445,12 +452,12 @@ def _construct_stage( def _construct_api_domain( # noqa: too-many-branches self, rest_api: ApiGatewayRestApi, route53_record_set_groups: Any - ) -> Tuple[Optional[ApiGatewayDomainName], Optional[List[ApiGatewayBasePathMapping]], Any, Any]: + ) -> ApiDomainResponse: """ Constructs and returns the ApiGateway Domain and BasepathMapping """ if self.domain is None: - return None, None, None, None + return ApiDomainResponse(None, None, None, None) sam_expect(self.domain, self.logical_id, "Domain").to_be_a_map() domain_name: PassThrough = sam_expect( @@ -568,8 +575,8 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group = route53_record_set_groups.get(logical_id) - if self.individual_recordset: - return ( + if route53.get("SeparateRecordSets"): + return ApiDomainResponse( domain, basepath_resource_list, None, @@ -587,7 +594,7 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group.RecordSets += self._construct_record_sets_for_domain(self.domain, api_domain_name, route53) - return domain, basepath_resource_list, record_set_group, None + return ApiDomainResponse(domain, basepath_resource_list, record_set_group, None) def _construct_individual_record_set( self, domain: Dict[str, Any], api_domain_name: str, route53: Any @@ -676,9 +683,12 @@ def to_cloudformation(self, redeploy_restapi_parameters, route53_record_set_grou :rtype: tuple """ rest_api = self._construct_rest_api() - domain, basepath_mapping, route53, individual_route53 = self._construct_api_domain( - rest_api, route53_record_set_groups - ) + apiDomainResponse = self._construct_api_domain(rest_api, route53_record_set_groups) + domain = apiDomainResponse.Domain + basepath_mapping = apiDomainResponse.ApiGWBasePathMappingList + route53 = apiDomainResponse.RecordSetsGroup + individual_route53 = apiDomainResponse.RecordSet + deployment = self._construct_deployment(rest_api) swagger = None diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 98ac996b6..f07eba1c9 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -1179,7 +1179,6 @@ class SamApi(SamResourceMacro): "DisableExecuteApiEndpoint": PropertyType(False, IS_BOOL), "ApiKeySourceType": PropertyType(False, IS_STR), "AlwaysDeploy": Property(False, IS_BOOL), - "IndividualRecordSet": Property(False, IS_BOOL), } Name: Optional[Intrinsicable[str]] @@ -1210,7 +1209,6 @@ class SamApi(SamResourceMacro): DisableExecuteApiEndpoint: Optional[Intrinsicable[bool]] ApiKeySourceType: Optional[Intrinsicable[str]] AlwaysDeploy: Optional[bool] - IndividualRecordSet: Optional[bool] referable_properties = { "Stage": ApiGatewayStage.resource_type, @@ -1276,7 +1274,6 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] mode=self.Mode, api_key_source_type=self.ApiKeySourceType, always_deploy=self.AlwaysDeploy, - individual_recordset=self.IndividualRecordSet, ) ( @@ -1299,11 +1296,11 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] resources.extend(basepath_mapping) if route53: resources.extend([route53]) + if individual_route53: + resources.extend(individual_route53) # contains usage plan, api key and usageplan key resources if usage_plan_resources: resources.extend(usage_plan_resources) - if individual_route53: - resources.extend(individual_route53) return resources diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index 137afb523..ed1210ccd 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -197873,10 +197873,6 @@ "title": "GatewayResponses", "type": "object" }, - "IndividualRecordSet": { - "title": "Individualrecordset", - "type": "boolean" - }, "MergeDefinitions": { "title": "Mergedefinitions", "type": "boolean" @@ -198264,6 +198260,10 @@ "Region": { "$ref": "#/definitions/PassThroughProp" }, + "SeparateRecordSets": { + "title": "Separaterecordsets", + "type": "boolean" + }, "SetIdentifier": { "$ref": "#/definitions/PassThroughProp" } diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index 79fdb1824..1d748a23f 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -3596,10 +3596,6 @@ "title": "GatewayResponses", "type": "object" }, - "IndividualRecordSet": { - "title": "Individualrecordset", - "type": "boolean" - }, "MergeDefinitions": { "title": "Mergedefinitions", "type": "boolean" @@ -3987,6 +3983,10 @@ "Region": { "$ref": "#/definitions/PassThroughProp" }, + "SeparateRecordSets": { + "title": "Separaterecordsets", + "type": "boolean" + }, "SetIdentifier": { "$ref": "#/definitions/PassThroughProp" } diff --git a/tests/translator/input/individual_route53_recordset.yaml b/tests/translator/input/separate_route53_recordset.yaml similarity index 96% rename from tests/translator/input/individual_route53_recordset.yaml rename to tests/translator/input/separate_route53_recordset.yaml index c03d617fd..e94e02dfc 100644 --- a/tests/translator/input/individual_route53_recordset.yaml +++ b/tests/translator/input/separate_route53_recordset.yaml @@ -56,9 +56,9 @@ Resources: EndpointConfiguration: REGIONAL Route53: HostedZoneId: abc123456 + SeparateRecordSets: true EndpointConfiguration: Type: REGIONAL - IndividualRecordSet: true ApiGatewayAdminThree: @@ -77,6 +77,6 @@ Resources: EndpointConfiguration: REGIONAL Route53: HostedZoneId: abc123456 + SeparateRecordSets: true EndpointConfiguration: Type: REGIONAL - IndividualRecordSet: true diff --git a/tests/translator/output/aws-cn/individual_route53_recordset.json b/tests/translator/output/aws-cn/separate_route53_recordset.json similarity index 95% rename from tests/translator/output/aws-cn/individual_route53_recordset.json rename to tests/translator/output/aws-cn/separate_route53_recordset.json index c694e07d5..e5c7e0bce 100644 --- a/tests/translator/output/aws-cn/individual_route53_recordset.json +++ b/tests/translator/output/aws-cn/separate_route53_recordset.json @@ -130,9 +130,9 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminThreeDeployment7541e97159": { + "ApiGatewayAdminThreeDeployment8072e30741": { "Properties": { - "Description": "RestApi deployment id: 7541e971598cffe7cafab030d3fccc687d508f59", + "Description": "RestApi deployment id: 8072e3074183e87bf1f82d54e544b73432f82027", "RestApiId": { "Ref": "ApiGatewayAdminThree" }, @@ -143,7 +143,7 @@ "ApiGatewayAdminThreeProdStage": { "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminThreeDeployment7541e97159" + "Ref": "ApiGatewayAdminThreeDeployment8072e30741" }, "MethodSettings": [ { @@ -200,10 +200,10 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminTwoDeployment61887a4eed": { + "ApiGatewayAdminTwoDeploymentbc167043f5": { "Condition": "CreateProdResources", "Properties": { - "Description": "RestApi deployment id: 61887a4eed03102402cbaa575b5b1e398b0dc647", + "Description": "RestApi deployment id: bc167043f5ea3d06b5c23c89d62be1cbe7734cac", "RestApiId": { "Ref": "ApiGatewayAdminTwo" }, @@ -215,7 +215,7 @@ "Condition": "CreateProdResources", "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminTwoDeployment61887a4eed" + "Ref": "ApiGatewayAdminTwoDeploymentbc167043f5" }, "MethodSettings": [ { diff --git a/tests/translator/output/aws-us-gov/individual_route53_recordset.json b/tests/translator/output/aws-us-gov/separate_route53_recordset.json similarity index 95% rename from tests/translator/output/aws-us-gov/individual_route53_recordset.json rename to tests/translator/output/aws-us-gov/separate_route53_recordset.json index c694e07d5..e5c7e0bce 100644 --- a/tests/translator/output/aws-us-gov/individual_route53_recordset.json +++ b/tests/translator/output/aws-us-gov/separate_route53_recordset.json @@ -130,9 +130,9 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminThreeDeployment7541e97159": { + "ApiGatewayAdminThreeDeployment8072e30741": { "Properties": { - "Description": "RestApi deployment id: 7541e971598cffe7cafab030d3fccc687d508f59", + "Description": "RestApi deployment id: 8072e3074183e87bf1f82d54e544b73432f82027", "RestApiId": { "Ref": "ApiGatewayAdminThree" }, @@ -143,7 +143,7 @@ "ApiGatewayAdminThreeProdStage": { "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminThreeDeployment7541e97159" + "Ref": "ApiGatewayAdminThreeDeployment8072e30741" }, "MethodSettings": [ { @@ -200,10 +200,10 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminTwoDeployment61887a4eed": { + "ApiGatewayAdminTwoDeploymentbc167043f5": { "Condition": "CreateProdResources", "Properties": { - "Description": "RestApi deployment id: 61887a4eed03102402cbaa575b5b1e398b0dc647", + "Description": "RestApi deployment id: bc167043f5ea3d06b5c23c89d62be1cbe7734cac", "RestApiId": { "Ref": "ApiGatewayAdminTwo" }, @@ -215,7 +215,7 @@ "Condition": "CreateProdResources", "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminTwoDeployment61887a4eed" + "Ref": "ApiGatewayAdminTwoDeploymentbc167043f5" }, "MethodSettings": [ { diff --git a/tests/translator/output/individual_route53_recordset.json b/tests/translator/output/separate_route53_recordset.json similarity index 95% rename from tests/translator/output/individual_route53_recordset.json rename to tests/translator/output/separate_route53_recordset.json index c694e07d5..e5c7e0bce 100644 --- a/tests/translator/output/individual_route53_recordset.json +++ b/tests/translator/output/separate_route53_recordset.json @@ -130,9 +130,9 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminThreeDeployment7541e97159": { + "ApiGatewayAdminThreeDeployment8072e30741": { "Properties": { - "Description": "RestApi deployment id: 7541e971598cffe7cafab030d3fccc687d508f59", + "Description": "RestApi deployment id: 8072e3074183e87bf1f82d54e544b73432f82027", "RestApiId": { "Ref": "ApiGatewayAdminThree" }, @@ -143,7 +143,7 @@ "ApiGatewayAdminThreeProdStage": { "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminThreeDeployment7541e97159" + "Ref": "ApiGatewayAdminThreeDeployment8072e30741" }, "MethodSettings": [ { @@ -200,10 +200,10 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminTwoDeployment61887a4eed": { + "ApiGatewayAdminTwoDeploymentbc167043f5": { "Condition": "CreateProdResources", "Properties": { - "Description": "RestApi deployment id: 61887a4eed03102402cbaa575b5b1e398b0dc647", + "Description": "RestApi deployment id: bc167043f5ea3d06b5c23c89d62be1cbe7734cac", "RestApiId": { "Ref": "ApiGatewayAdminTwo" }, @@ -215,7 +215,7 @@ "Condition": "CreateProdResources", "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminTwoDeployment61887a4eed" + "Ref": "ApiGatewayAdminTwoDeploymentbc167043f5" }, "MethodSettings": [ { From b6a7028ad7eda14e2c69aefeda0474ac636c7e07 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Tue, 14 Mar 2023 14:49:25 -0700 Subject: [PATCH 04/13] Improve code --- samtranslator/model/api/api_generator.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 12d93a28b..a2bb74968 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -1,7 +1,7 @@ import logging from collections import namedtuple from dataclasses import dataclass -from typing import Any, Dict, List, Optional, Set, Union, cast +from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast from samtranslator.metrics.method_decorator import cw_timer from samtranslator.model.apigateway import ( @@ -676,7 +676,19 @@ def _construct_alias_target(self, domain: Dict[str, Any], api_domain_name: str, return alias_target @cw_timer(prefix="Generator", name="Api") - def to_cloudformation(self, redeploy_restapi_parameters, route53_record_set_groups): # type: ignore[no-untyped-def] + def to_cloudformation( + self, redeploy_restapi_parameters: Optional[Any], route53_record_set_groups: Dict[str, Route53RecordSetGroup] + ) -> Tuple[ + ApiGatewayRestApi, + ApiGatewayDeployment, + ApiGatewayStage, + List[LambdaPermission], + Optional[ApiGatewayDomainName], + Optional[List[ApiGatewayBasePathMapping]], + Optional[Route53RecordSetGroup], + Optional[Any], + Optional[List[Route53RecordSet]], + ]: """Generates CloudFormation resources from a SAM API resource :returns: a tuple containing the RestApi, Deployment, and Stage for an empty Api. @@ -686,8 +698,8 @@ def to_cloudformation(self, redeploy_restapi_parameters, route53_record_set_grou apiDomainResponse = self._construct_api_domain(rest_api, route53_record_set_groups) domain = apiDomainResponse.Domain basepath_mapping = apiDomainResponse.ApiGWBasePathMappingList - route53 = apiDomainResponse.RecordSetsGroup - individual_route53 = apiDomainResponse.RecordSet + route53_recordsetGroup = apiDomainResponse.RecordSetsGroup + route53_recordsets = apiDomainResponse.RecordSet deployment = self._construct_deployment(rest_api) @@ -708,9 +720,9 @@ def to_cloudformation(self, redeploy_restapi_parameters, route53_record_set_grou permissions, domain, basepath_mapping, - route53, + route53_recordsetGroup, usage_plan, - individual_route53, + route53_recordsets, ) def _add_cors(self) -> None: From beee9a1678a23e6546e9a77ffa963986b32bf76e Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Tue, 14 Mar 2023 15:23:33 -0700 Subject: [PATCH 05/13] make black --- samtranslator/internal/schema_source/aws_serverless_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samtranslator/internal/schema_source/aws_serverless_api.py b/samtranslator/internal/schema_source/aws_serverless_api.py index c3eb9f6dd..fcab70585 100644 --- a/samtranslator/internal/schema_source/aws_serverless_api.py +++ b/samtranslator/internal/schema_source/aws_serverless_api.py @@ -134,7 +134,7 @@ class Route53(BaseModel): IpV6: Optional[bool] = route53("IpV6") SetIdentifier: Optional[PassThroughProp] # TODO: add docs Region: Optional[PassThroughProp] # TODO: add docs - SeparateRecordSets: Optional[bool] # TODO: add docs + SeparateRecordSets: Optional[bool] # TODO: add docs class Domain(BaseModel): From 6eae2cf1eb24870995daafe8f2cc81de72bd5460 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Wed, 15 Mar 2023 12:40:26 -0700 Subject: [PATCH 06/13] refactor --- samtranslator/model/api/api_generator.py | 40 ++++++++++-------------- samtranslator/model/sam_resources.py | 36 +++++++-------------- 2 files changed, 28 insertions(+), 48 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index a2bb74968..b5633a636 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -1,7 +1,7 @@ import logging from collections import namedtuple from dataclasses import dataclass -from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast +from typing import Any, Dict, List, Optional, Set, Union, cast from samtranslator.metrics.method_decorator import cw_timer from samtranslator.model.apigateway import ( @@ -575,7 +575,7 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group = route53_record_set_groups.get(logical_id) - if route53.get("SeparateRecordSets"): + if route53.get("SeparateRecordSets") and not is_intrinsic(route53.get("SeparateRecordSets")): return ApiDomainResponse( domain, basepath_resource_list, @@ -678,17 +678,7 @@ def _construct_alias_target(self, domain: Dict[str, Any], api_domain_name: str, @cw_timer(prefix="Generator", name="Api") def to_cloudformation( self, redeploy_restapi_parameters: Optional[Any], route53_record_set_groups: Dict[str, Route53RecordSetGroup] - ) -> Tuple[ - ApiGatewayRestApi, - ApiGatewayDeployment, - ApiGatewayStage, - List[LambdaPermission], - Optional[ApiGatewayDomainName], - Optional[List[ApiGatewayBasePathMapping]], - Optional[Route53RecordSetGroup], - Optional[Any], - Optional[List[Route53RecordSet]], - ]: + ) -> List[Any]: """Generates CloudFormation resources from a SAM API resource :returns: a tuple containing the RestApi, Deployment, and Stage for an empty Api. @@ -713,17 +703,21 @@ def to_cloudformation( permissions = self._construct_authorizer_lambda_permission() usage_plan = self._construct_usage_plan(rest_api_stage=stage) - return ( - rest_api, - deployment, - stage, - permissions, - domain, - basepath_mapping, - route53_recordsetGroup, - usage_plan, - route53_recordsets, + generated_resources: List[Any] = [] + generated_resources.extend( + [ + rest_api, + deployment, + stage, + permissions, + domain, + basepath_mapping, + route53_recordsetGroup, + usage_plan, + route53_recordsets, + ] ) + return generated_resources def _add_cors(self) -> None: """ diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index f07eba1c9..1ad4f5e9d 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -1228,7 +1228,6 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] :returns: a list of vanilla CloudFormation Resources, to which this Function expands :rtype: list """ - resources = [] intrinsics_resolver = kwargs["intrinsics_resolver"] self.BinaryMediaTypes = intrinsics_resolver.resolve_parameter_refs(self.BinaryMediaTypes) @@ -1276,31 +1275,18 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] always_deploy=self.AlwaysDeploy, ) - ( - rest_api, - deployment, - stage, - permissions, - domain, - basepath_mapping, - route53, - usage_plan_resources, - individual_route53, - ) = api_generator.to_cloudformation(redeploy_restapi_parameters, route53_record_set_groups) + generated_api_resources = api_generator.to_cloudformation( + redeploy_restapi_parameters, route53_record_set_groups + ) - resources.extend([rest_api, deployment, stage]) - resources.extend(permissions) - if domain: - resources.extend([domain]) - if basepath_mapping: - resources.extend(basepath_mapping) - if route53: - resources.extend([route53]) - if individual_route53: - resources.extend(individual_route53) - # contains usage plan, api key and usageplan key resources - if usage_plan_resources: - resources.extend(usage_plan_resources) + resources: List[Any] = [] + + for resource in generated_api_resources: + if resource: + if isinstance(resource, (list, tuple)): + resources.extend(resource) + else: + resources.extend([resource]) return resources From de252a89400bcc31c956ec0128e8c1aad18d823c Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Wed, 15 Mar 2023 12:52:24 -0700 Subject: [PATCH 07/13] add type validation --- samtranslator/model/api/api_generator.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index b5633a636..21e9b5e45 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -576,6 +576,9 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group = route53_record_set_groups.get(logical_id) if route53.get("SeparateRecordSets") and not is_intrinsic(route53.get("SeparateRecordSets")): + sam_expect( + route53.get("SeparateRecordSets"), self.logical_id, "Domain.Route53.SeparateRecordSets" + ).to_be_a_string return ApiDomainResponse( domain, basepath_resource_list, From dedabe55fffc60010e70941a4a7eb794228b5145 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Wed, 15 Mar 2023 13:38:12 -0700 Subject: [PATCH 08/13] add type to the resource list --- samtranslator/model/api/api_generator.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 21e9b5e45..445442e21 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -1,9 +1,10 @@ import logging from collections import namedtuple from dataclasses import dataclass -from typing import Any, Dict, List, Optional, Set, Union, cast +from typing import Any, Dict, List, Optional, Set, Tuple, Union, cast from samtranslator.metrics.method_decorator import cw_timer +from samtranslator.model import Resource from samtranslator.model.apigateway import ( ApiGatewayApiKey, ApiGatewayAuthorizer, @@ -706,7 +707,18 @@ def to_cloudformation( permissions = self._construct_authorizer_lambda_permission() usage_plan = self._construct_usage_plan(rest_api_stage=stage) - generated_resources: List[Any] = [] + # mypy complains if the type in List doesn't match exactly + # TODO: refactor to have a list of single resource + generated_resources: List[ + Union[ + Optional[Resource], + List[Resource], + Tuple[Resource], + List[Route53RecordSet], + List[LambdaPermission], + List[ApiGatewayBasePathMapping], + ], + ] = [] generated_resources.extend( [ rest_api, From c72e4cd7bc675dd3b6161ce240e5dc35f11f8ff4 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Wed, 15 Mar 2023 15:58:24 -0700 Subject: [PATCH 09/13] fix issues and add tests --- samtranslator/model/api/api_generator.py | 2 +- .../error_separate_route53_recordset.yaml | 82 +++++++++++++++++++ .../error_separate_route53_recordset.json | 9 ++ .../error_separate_route53_recordset.json | 9 ++ .../error_separate_route53_recordset.json | 9 ++ 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 tests/translator/input/error_separate_route53_recordset.yaml create mode 100644 tests/translator/output/aws-cn/error_separate_route53_recordset.json create mode 100644 tests/translator/output/aws-us-gov/error_separate_route53_recordset.json create mode 100644 tests/translator/output/error_separate_route53_recordset.json diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 445442e21..e6d922859 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -579,7 +579,7 @@ def _construct_api_domain( # noqa: too-many-branches if route53.get("SeparateRecordSets") and not is_intrinsic(route53.get("SeparateRecordSets")): sam_expect( route53.get("SeparateRecordSets"), self.logical_id, "Domain.Route53.SeparateRecordSets" - ).to_be_a_string + ).to_be_a_bool() return ApiDomainResponse( domain, basepath_resource_list, diff --git a/tests/translator/input/error_separate_route53_recordset.yaml b/tests/translator/input/error_separate_route53_recordset.yaml new file mode 100644 index 000000000..34ffd9c57 --- /dev/null +++ b/tests/translator/input/error_separate_route53_recordset.yaml @@ -0,0 +1,82 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + apigateway-2402 + + Sample SAM Template for apigateway-2402 + +Parameters: + EnvType: + Description: Environment type. + Default: test + Type: String + AllowedValues: + - prod + - test + ConstraintDescription: must specify prod or test. +Conditions: + CreateProdResources: !Equals + - !Ref EnvType + - prod +Resources: + ApiGatewayAdminOne: + Type: AWS::Serverless::Api + Properties: + Name: App-Prod-Web + StageName: Prod + TracingEnabled: true + MethodSettings: + - LoggingLevel: Info + ResourcePath: /* + HttpMethod: '*' + Domain: + DomainName: admin.one.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + EndpointConfiguration: + Type: REGIONAL + + + ApiGatewayAdminTwo: + Type: AWS::Serverless::Api + Condition: CreateProdResources + Properties: + Name: App-Prod-Web + StageName: Prod + TracingEnabled: true + MethodSettings: + - LoggingLevel: Info + ResourcePath: /* + HttpMethod: '*' + Domain: + DomainName: admin.two.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + SeparateRecordSets: [true] + EndpointConfiguration: + Type: REGIONAL + + + ApiGatewayAdminThree: + Type: AWS::Serverless::Api + Properties: + Name: App-Prod-Web + StageName: Prod + TracingEnabled: true + MethodSettings: + - LoggingLevel: Info + ResourcePath: /* + HttpMethod: '*' + Domain: + DomainName: admin.three.amazon.com + CertificateArn: arn::cert::abc + EndpointConfiguration: REGIONAL + Route53: + HostedZoneId: abc123456 + SeparateRecordSets: true + EndpointConfiguration: + Type: REGIONAL diff --git a/tests/translator/output/aws-cn/error_separate_route53_recordset.json b/tests/translator/output/aws-cn/error_separate_route53_recordset.json new file mode 100644 index 000000000..43f659850 --- /dev/null +++ b/tests/translator/output/aws-cn/error_separate_route53_recordset.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [ApiWithEmptyStageName] is invalid. ", + "StageName cannot be empty." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [ApiGatewayAdminTwo] is invalid. Property 'Domain.Route53.SeparateRecordSets' should be a boolean." +} diff --git a/tests/translator/output/aws-us-gov/error_separate_route53_recordset.json b/tests/translator/output/aws-us-gov/error_separate_route53_recordset.json new file mode 100644 index 000000000..43f659850 --- /dev/null +++ b/tests/translator/output/aws-us-gov/error_separate_route53_recordset.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [ApiWithEmptyStageName] is invalid. ", + "StageName cannot be empty." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [ApiGatewayAdminTwo] is invalid. Property 'Domain.Route53.SeparateRecordSets' should be a boolean." +} diff --git a/tests/translator/output/error_separate_route53_recordset.json b/tests/translator/output/error_separate_route53_recordset.json new file mode 100644 index 000000000..e9db97416 --- /dev/null +++ b/tests/translator/output/error_separate_route53_recordset.json @@ -0,0 +1,9 @@ +{ + "_autoGeneratedBreakdownErrorMessage": [ + "Invalid Serverless Application Specification document. ", + "Number of errors found: 1. ", + "Resource with id [ApiGatewayAdminTwo] is invalid. ", + "Property 'Domain.Route53.SeparateRecordSets' should be a boolean." + ], + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [ApiGatewayAdminTwo] is invalid. Property 'Domain.Route53.SeparateRecordSets' should be a boolean." +} From 4faa805ad8be68693e325b4fdd369e1e6d7c5e38 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Wed, 15 Mar 2023 17:05:04 -0700 Subject: [PATCH 10/13] refactor --- samtranslator/model/api/api_generator.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index e6d922859..771cc6390 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -576,7 +576,7 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group = route53_record_set_groups.get(logical_id) - if route53.get("SeparateRecordSets") and not is_intrinsic(route53.get("SeparateRecordSets")): + if route53.get("SeparateRecordSets"): sam_expect( route53.get("SeparateRecordSets"), self.logical_id, "Domain.Route53.SeparateRecordSets" ).to_be_a_bool() @@ -603,9 +603,10 @@ def _construct_api_domain( # noqa: too-many-branches def _construct_individual_record_set( self, domain: Dict[str, Any], api_domain_name: str, route53: Any ) -> List[Route53RecordSet]: - logical_id_suffix = LogicalIdGenerator( - "", [route53.get("HostedZoneId") or route53.get("HostedZoneName"), domain.get("DomainName")] - ).gen() + hostedZoneId = route53.get("HostedZoneId") + hostedZoneName = route53.get("HostedZoneName") + domainName = domain.get("DomainName") + logical_id_suffix = LogicalIdGenerator("", [hostedZoneId or hostedZoneName, domainName]).gen() logical_id = "RecordSet" + logical_id_suffix logical_id_ipv6 = "RecordSetIpv6" + logical_id_suffix @@ -616,16 +617,16 @@ def _construct_individual_record_set( recordset.Type = "A" recordset.AliasTarget = self._construct_alias_target(domain, api_domain_name, route53) - if route53.get("HostedZoneId"): - recordset.HostedZoneId = route53.get("HostedZoneId") + if hostedZoneId: + recordset.HostedZoneId = hostedZoneId else: - recordset.HostedZoneName = route53.get("HostedZoneName") + recordset.HostedZoneName = hostedZoneName recordset_list.extend([recordset]) if route53.get("IpV6"): recordset_ipv6 = Route53RecordSet(logical_id_ipv6, attributes=self.passthrough_resource_attributes) - recordset_ipv6.Name = domain.get("DomainName") + recordset_ipv6.Name = domainName recordset_ipv6.Type = "AAAA" recordset_ipv6.AliasTarget = self._construct_alias_target(domain, api_domain_name, route53) recordset_list.extend([recordset_ipv6]) From 6406470aaaaa270f3d5c21b42d89861501f9c247 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Thu, 16 Mar 2023 11:32:31 -0700 Subject: [PATCH 11/13] use recordset group --- .../schema_source/aws_serverless_api.py | 2 +- samtranslator/model/api/api_generator.py | 72 +++++-------- samtranslator/schema/schema.json | 4 +- schema_source/sam.schema.json | 4 +- ...ror_separate_route53_recordset_group.yaml} | 4 +- ... => separate_route53_recordset_group.yaml} | 4 +- .../error_separate_route53_recordset.json | 9 -- .../separate_route53_recordset_group.json} | 100 ++++++++++-------- .../error_separate_route53_recordset.json | 9 -- .../separate_route53_recordset_group.json} | 100 ++++++++++-------- ...ror_separate_route53_recordset_group.json} | 4 +- ... => separate_route53_recordset_group.json} | 100 ++++++++++-------- 12 files changed, 199 insertions(+), 213 deletions(-) rename tests/translator/input/{separate_route53_recordset.yaml => error_separate_route53_recordset_group.yaml} (95%) rename tests/translator/input/{error_separate_route53_recordset.yaml => separate_route53_recordset_group.yaml} (96%) delete mode 100644 tests/translator/output/aws-cn/error_separate_route53_recordset.json rename tests/translator/output/{aws-us-gov/separate_route53_recordset.json => aws-cn/separate_route53_recordset_group.json} (82%) delete mode 100644 tests/translator/output/aws-us-gov/error_separate_route53_recordset.json rename tests/translator/output/{separate_route53_recordset.json => aws-us-gov/separate_route53_recordset_group.json} (82%) rename tests/translator/output/{error_separate_route53_recordset.json => error_separate_route53_recordset_group.json} (79%) rename tests/translator/output/{aws-cn/separate_route53_recordset.json => separate_route53_recordset_group.json} (82%) diff --git a/samtranslator/internal/schema_source/aws_serverless_api.py b/samtranslator/internal/schema_source/aws_serverless_api.py index a060e5fd4..0148b9193 100644 --- a/samtranslator/internal/schema_source/aws_serverless_api.py +++ b/samtranslator/internal/schema_source/aws_serverless_api.py @@ -134,7 +134,7 @@ class Route53(BaseModel): IpV6: Optional[bool] = route53("IpV6") SetIdentifier: Optional[PassThroughProp] # TODO: add docs Region: Optional[PassThroughProp] # TODO: add docs - SeparateRecordSets: Optional[bool] # TODO: add docs + SeparateRecordSetGroup: Optional[bool] # TODO: add docs class Domain(BaseModel): diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 771cc6390..1661dca35 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -25,7 +25,7 @@ ) from samtranslator.model.intrinsics import fnGetAtt, fnSub, is_intrinsic, make_or_condition, ref from samtranslator.model.lambda_ import LambdaPermission -from samtranslator.model.route53 import Route53RecordSet, Route53RecordSetGroup +from samtranslator.model.route53 import Route53RecordSetGroup from samtranslator.model.s3_utils.uri_parser import parse_s3_uri from samtranslator.model.tags.resource_tagging import get_tag_list from samtranslator.model.types import PassThrough @@ -71,10 +71,9 @@ @dataclass class ApiDomainResponse: - Domain: Optional[ApiGatewayDomainName] - ApiGWBasePathMappingList: Optional[List[ApiGatewayBasePathMapping]] - RecordSetsGroup: Any - RecordSet: Optional[List[Route53RecordSet]] + domain: Optional[ApiGatewayDomainName] + apigw_basepath_mapping_list: Optional[List[ApiGatewayBasePathMapping]] + recordset_group: Any class SharedApiUsagePlan: @@ -458,7 +457,7 @@ def _construct_api_domain( # noqa: too-many-branches Constructs and returns the ApiGateway Domain and BasepathMapping """ if self.domain is None: - return ApiDomainResponse(None, None, None, None) + return ApiDomainResponse(None, None, None) sam_expect(self.domain, self.logical_id, "Domain").to_be_a_map() domain_name: PassThrough = sam_expect( @@ -576,15 +575,14 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group = route53_record_set_groups.get(logical_id) - if route53.get("SeparateRecordSets"): + if route53.get("SeparateRecordSetGroup"): sam_expect( - route53.get("SeparateRecordSets"), self.logical_id, "Domain.Route53.SeparateRecordSets" + route53.get("SeparateRecordSetGroup"), self.logical_id, "Domain.Route53.SeparateRecordSetGroup" ).to_be_a_bool() return ApiDomainResponse( domain, basepath_resource_list, - None, - self._construct_individual_record_set(self.domain, api_domain_name, route53), + self._construct_single_record_set_group(self.domain, api_domain_name, route53), ) if not record_set_group: @@ -598,50 +596,37 @@ def _construct_api_domain( # noqa: too-many-branches record_set_group.RecordSets += self._construct_record_sets_for_domain(self.domain, api_domain_name, route53) - return ApiDomainResponse(domain, basepath_resource_list, record_set_group, None) + return ApiDomainResponse(domain, basepath_resource_list, record_set_group) - def _construct_individual_record_set( + def _construct_single_record_set_group( self, domain: Dict[str, Any], api_domain_name: str, route53: Any - ) -> List[Route53RecordSet]: + ) -> Route53RecordSetGroup: hostedZoneId = route53.get("HostedZoneId") hostedZoneName = route53.get("HostedZoneName") domainName = domain.get("DomainName") logical_id_suffix = LogicalIdGenerator("", [hostedZoneId or hostedZoneName, domainName]).gen() - logical_id = "RecordSet" + logical_id_suffix - logical_id_ipv6 = "RecordSetIpv6" + logical_id_suffix - - recordset_list = [] - - recordset = Route53RecordSet(logical_id, attributes=self.passthrough_resource_attributes) - recordset.Name = domain.get("DomainName") - recordset.Type = "A" - recordset.AliasTarget = self._construct_alias_target(domain, api_domain_name, route53) + logical_id = "RecordSetGroup" + logical_id_suffix + record_set_group = Route53RecordSetGroup(logical_id, attributes=self.passthrough_resource_attributes) if hostedZoneId: - recordset.HostedZoneId = hostedZoneId - else: - recordset.HostedZoneName = hostedZoneName + record_set_group.HostedZoneId = hostedZoneId + if hostedZoneName: + record_set_group.HostedZoneName = hostedZoneName - recordset_list.extend([recordset]) + record_set_group.RecordSets = [] + record_set_group.RecordSets += self._construct_record_sets_for_domain(domain, api_domain_name, route53) - if route53.get("IpV6"): - recordset_ipv6 = Route53RecordSet(logical_id_ipv6, attributes=self.passthrough_resource_attributes) - recordset_ipv6.Name = domainName - recordset_ipv6.Type = "AAAA" - recordset_ipv6.AliasTarget = self._construct_alias_target(domain, api_domain_name, route53) - recordset_list.extend([recordset_ipv6]) - - return recordset_list + return record_set_group def _construct_record_sets_for_domain( self, custom_domain_config: Dict[str, Any], api_domain_name: str, route53_config: Dict[str, Any] ) -> List[Dict[str, Any]]: recordset_list = [] - + alias_target = self._construct_alias_target(custom_domain_config, api_domain_name, route53_config) recordset = {} recordset["Name"] = custom_domain_config.get("DomainName") recordset["Type"] = "A" - recordset["AliasTarget"] = self._construct_alias_target(custom_domain_config, api_domain_name, route53_config) + recordset["AliasTarget"] = alias_target self._update_route53_routing_policy_properties(route53_config, recordset) recordset_list.append(recordset) @@ -649,9 +634,7 @@ def _construct_record_sets_for_domain( recordset_ipv6 = {} recordset_ipv6["Name"] = custom_domain_config.get("DomainName") recordset_ipv6["Type"] = "AAAA" - recordset_ipv6["AliasTarget"] = self._construct_alias_target( - custom_domain_config, api_domain_name, route53_config - ) + recordset_ipv6["AliasTarget"] = alias_target self._update_route53_routing_policy_properties(route53_config, recordset_ipv6) recordset_list.append(recordset_ipv6) @@ -690,11 +673,10 @@ def to_cloudformation( :rtype: tuple """ rest_api = self._construct_rest_api() - apiDomainResponse = self._construct_api_domain(rest_api, route53_record_set_groups) - domain = apiDomainResponse.Domain - basepath_mapping = apiDomainResponse.ApiGWBasePathMappingList - route53_recordsetGroup = apiDomainResponse.RecordSetsGroup - route53_recordsets = apiDomainResponse.RecordSet + api_domain_response = self._construct_api_domain(rest_api, route53_record_set_groups) + domain = api_domain_response.domain + basepath_mapping = api_domain_response.apigw_basepath_mapping_list + route53_recordsetGroup = api_domain_response.recordset_group deployment = self._construct_deployment(rest_api) @@ -715,7 +697,6 @@ def to_cloudformation( Optional[Resource], List[Resource], Tuple[Resource], - List[Route53RecordSet], List[LambdaPermission], List[ApiGatewayBasePathMapping], ], @@ -730,7 +711,6 @@ def to_cloudformation( basepath_mapping, route53_recordsetGroup, usage_plan, - route53_recordsets, ] ) return generated_resources diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index e277ed9e4..3278c8d8d 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -198371,8 +198371,8 @@ "Region": { "$ref": "#/definitions/PassThroughProp" }, - "SeparateRecordSets": { - "title": "Separaterecordsets", + "SeparateRecordSetGroup": { + "title": "Separaterecordsetgroup", "type": "boolean" }, "SetIdentifier": { diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index 8f15f4e0b..c5458bec7 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -4094,8 +4094,8 @@ "Region": { "$ref": "#/definitions/PassThroughProp" }, - "SeparateRecordSets": { - "title": "Separaterecordsets", + "SeparateRecordSetGroup": { + "title": "Separaterecordsetgroup", "type": "boolean" }, "SetIdentifier": { diff --git a/tests/translator/input/separate_route53_recordset.yaml b/tests/translator/input/error_separate_route53_recordset_group.yaml similarity index 95% rename from tests/translator/input/separate_route53_recordset.yaml rename to tests/translator/input/error_separate_route53_recordset_group.yaml index e94e02dfc..9be24513f 100644 --- a/tests/translator/input/separate_route53_recordset.yaml +++ b/tests/translator/input/error_separate_route53_recordset_group.yaml @@ -56,7 +56,7 @@ Resources: EndpointConfiguration: REGIONAL Route53: HostedZoneId: abc123456 - SeparateRecordSets: true + SeparateRecordSetGroup: [true] EndpointConfiguration: Type: REGIONAL @@ -77,6 +77,6 @@ Resources: EndpointConfiguration: REGIONAL Route53: HostedZoneId: abc123456 - SeparateRecordSets: true + SeparateRecordSetGroup: true EndpointConfiguration: Type: REGIONAL diff --git a/tests/translator/input/error_separate_route53_recordset.yaml b/tests/translator/input/separate_route53_recordset_group.yaml similarity index 96% rename from tests/translator/input/error_separate_route53_recordset.yaml rename to tests/translator/input/separate_route53_recordset_group.yaml index 34ffd9c57..67d323987 100644 --- a/tests/translator/input/error_separate_route53_recordset.yaml +++ b/tests/translator/input/separate_route53_recordset_group.yaml @@ -56,7 +56,7 @@ Resources: EndpointConfiguration: REGIONAL Route53: HostedZoneId: abc123456 - SeparateRecordSets: [true] + SeparateRecordSetGroup: true EndpointConfiguration: Type: REGIONAL @@ -77,6 +77,6 @@ Resources: EndpointConfiguration: REGIONAL Route53: HostedZoneId: abc123456 - SeparateRecordSets: true + SeparateRecordSetGroup: true EndpointConfiguration: Type: REGIONAL diff --git a/tests/translator/output/aws-cn/error_separate_route53_recordset.json b/tests/translator/output/aws-cn/error_separate_route53_recordset.json deleted file mode 100644 index 43f659850..000000000 --- a/tests/translator/output/aws-cn/error_separate_route53_recordset.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "_autoGeneratedBreakdownErrorMessage": [ - "Invalid Serverless Application Specification document. ", - "Number of errors found: 1. ", - "Resource with id [ApiWithEmptyStageName] is invalid. ", - "StageName cannot be empty." - ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [ApiGatewayAdminTwo] is invalid. Property 'Domain.Route53.SeparateRecordSets' should be a boolean." -} diff --git a/tests/translator/output/aws-us-gov/separate_route53_recordset.json b/tests/translator/output/aws-cn/separate_route53_recordset_group.json similarity index 82% rename from tests/translator/output/aws-us-gov/separate_route53_recordset.json rename to tests/translator/output/aws-cn/separate_route53_recordset_group.json index e5c7e0bce..5575d8d71 100644 --- a/tests/translator/output/aws-us-gov/separate_route53_recordset.json +++ b/tests/translator/output/aws-cn/separate_route53_recordset_group.json @@ -130,9 +130,9 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminThreeDeployment8072e30741": { + "ApiGatewayAdminThreeDeploymentc2e9ae5463": { "Properties": { - "Description": "RestApi deployment id: 8072e3074183e87bf1f82d54e544b73432f82027", + "Description": "RestApi deployment id: c2e9ae5463d31ad96611e5aab9b4ddd4fd7bde73", "RestApiId": { "Ref": "ApiGatewayAdminThree" }, @@ -143,7 +143,7 @@ "ApiGatewayAdminThreeProdStage": { "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminThreeDeployment8072e30741" + "Ref": "ApiGatewayAdminThreeDeploymentc2e9ae5463" }, "MethodSettings": [ { @@ -200,10 +200,10 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminTwoDeploymentbc167043f5": { + "ApiGatewayAdminTwoDeployment2a68098964": { "Condition": "CreateProdResources", "Properties": { - "Description": "RestApi deployment id: bc167043f5ea3d06b5c23c89d62be1cbe7734cac", + "Description": "RestApi deployment id: 2a6809896451eb172efffcdcd18396e1a83df12a", "RestApiId": { "Ref": "ApiGatewayAdminTwo" }, @@ -215,7 +215,7 @@ "Condition": "CreateProdResources", "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminTwoDeploymentbc167043f5" + "Ref": "ApiGatewayAdminTwoDeployment2a68098964" }, "MethodSettings": [ { @@ -269,28 +269,6 @@ }, "Type": "AWS::ApiGateway::DomainName" }, - "RecordSet81840409a4": { - "Properties": { - "AliasTarget": { - "DNSName": { - "Fn::GetAtt": [ - "ApiGatewayDomainName41bfc7f9c4", - "RegionalDomainName" - ] - }, - "HostedZoneId": { - "Fn::GetAtt": [ - "ApiGatewayDomainName41bfc7f9c4", - "RegionalHostedZoneId" - ] - } - }, - "HostedZoneId": "abc123456", - "Name": "admin.three.amazon.com", - "Type": "A" - }, - "Type": "AWS::Route53::RecordSet" - }, "RecordSetGroup370194ff6e": { "Properties": { "HostedZoneId": "abc123456", @@ -317,28 +295,58 @@ }, "Type": "AWS::Route53::RecordSetGroup" }, - "RecordSetb3fa99c196": { - "Condition": "CreateProdResources", + "RecordSetGroup81840409a4": { "Properties": { - "AliasTarget": { - "DNSName": { - "Fn::GetAtt": [ - "ApiGatewayDomainName3fd2dbd8f8", - "RegionalDomainName" - ] - }, - "HostedZoneId": { - "Fn::GetAtt": [ - "ApiGatewayDomainName3fd2dbd8f8", - "RegionalHostedZoneId" - ] + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.three.amazon.com", + "Type": "A" } - }, + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + }, + "RecordSetGroupb3fa99c196": { + "Condition": "CreateProdResources", + "Properties": { "HostedZoneId": "abc123456", - "Name": "admin.two.amazon.com", - "Type": "A" + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.two.amazon.com", + "Type": "A" + } + ] }, - "Type": "AWS::Route53::RecordSet" + "Type": "AWS::Route53::RecordSetGroup" } } } diff --git a/tests/translator/output/aws-us-gov/error_separate_route53_recordset.json b/tests/translator/output/aws-us-gov/error_separate_route53_recordset.json deleted file mode 100644 index 43f659850..000000000 --- a/tests/translator/output/aws-us-gov/error_separate_route53_recordset.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "_autoGeneratedBreakdownErrorMessage": [ - "Invalid Serverless Application Specification document. ", - "Number of errors found: 1. ", - "Resource with id [ApiWithEmptyStageName] is invalid. ", - "StageName cannot be empty." - ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [ApiGatewayAdminTwo] is invalid. Property 'Domain.Route53.SeparateRecordSets' should be a boolean." -} diff --git a/tests/translator/output/separate_route53_recordset.json b/tests/translator/output/aws-us-gov/separate_route53_recordset_group.json similarity index 82% rename from tests/translator/output/separate_route53_recordset.json rename to tests/translator/output/aws-us-gov/separate_route53_recordset_group.json index e5c7e0bce..5575d8d71 100644 --- a/tests/translator/output/separate_route53_recordset.json +++ b/tests/translator/output/aws-us-gov/separate_route53_recordset_group.json @@ -130,9 +130,9 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminThreeDeployment8072e30741": { + "ApiGatewayAdminThreeDeploymentc2e9ae5463": { "Properties": { - "Description": "RestApi deployment id: 8072e3074183e87bf1f82d54e544b73432f82027", + "Description": "RestApi deployment id: c2e9ae5463d31ad96611e5aab9b4ddd4fd7bde73", "RestApiId": { "Ref": "ApiGatewayAdminThree" }, @@ -143,7 +143,7 @@ "ApiGatewayAdminThreeProdStage": { "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminThreeDeployment8072e30741" + "Ref": "ApiGatewayAdminThreeDeploymentc2e9ae5463" }, "MethodSettings": [ { @@ -200,10 +200,10 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminTwoDeploymentbc167043f5": { + "ApiGatewayAdminTwoDeployment2a68098964": { "Condition": "CreateProdResources", "Properties": { - "Description": "RestApi deployment id: bc167043f5ea3d06b5c23c89d62be1cbe7734cac", + "Description": "RestApi deployment id: 2a6809896451eb172efffcdcd18396e1a83df12a", "RestApiId": { "Ref": "ApiGatewayAdminTwo" }, @@ -215,7 +215,7 @@ "Condition": "CreateProdResources", "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminTwoDeploymentbc167043f5" + "Ref": "ApiGatewayAdminTwoDeployment2a68098964" }, "MethodSettings": [ { @@ -269,28 +269,6 @@ }, "Type": "AWS::ApiGateway::DomainName" }, - "RecordSet81840409a4": { - "Properties": { - "AliasTarget": { - "DNSName": { - "Fn::GetAtt": [ - "ApiGatewayDomainName41bfc7f9c4", - "RegionalDomainName" - ] - }, - "HostedZoneId": { - "Fn::GetAtt": [ - "ApiGatewayDomainName41bfc7f9c4", - "RegionalHostedZoneId" - ] - } - }, - "HostedZoneId": "abc123456", - "Name": "admin.three.amazon.com", - "Type": "A" - }, - "Type": "AWS::Route53::RecordSet" - }, "RecordSetGroup370194ff6e": { "Properties": { "HostedZoneId": "abc123456", @@ -317,28 +295,58 @@ }, "Type": "AWS::Route53::RecordSetGroup" }, - "RecordSetb3fa99c196": { - "Condition": "CreateProdResources", + "RecordSetGroup81840409a4": { "Properties": { - "AliasTarget": { - "DNSName": { - "Fn::GetAtt": [ - "ApiGatewayDomainName3fd2dbd8f8", - "RegionalDomainName" - ] - }, - "HostedZoneId": { - "Fn::GetAtt": [ - "ApiGatewayDomainName3fd2dbd8f8", - "RegionalHostedZoneId" - ] + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.three.amazon.com", + "Type": "A" } - }, + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + }, + "RecordSetGroupb3fa99c196": { + "Condition": "CreateProdResources", + "Properties": { "HostedZoneId": "abc123456", - "Name": "admin.two.amazon.com", - "Type": "A" + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.two.amazon.com", + "Type": "A" + } + ] }, - "Type": "AWS::Route53::RecordSet" + "Type": "AWS::Route53::RecordSetGroup" } } } diff --git a/tests/translator/output/error_separate_route53_recordset.json b/tests/translator/output/error_separate_route53_recordset_group.json similarity index 79% rename from tests/translator/output/error_separate_route53_recordset.json rename to tests/translator/output/error_separate_route53_recordset_group.json index e9db97416..ae418b685 100644 --- a/tests/translator/output/error_separate_route53_recordset.json +++ b/tests/translator/output/error_separate_route53_recordset_group.json @@ -3,7 +3,7 @@ "Invalid Serverless Application Specification document. ", "Number of errors found: 1. ", "Resource with id [ApiGatewayAdminTwo] is invalid. ", - "Property 'Domain.Route53.SeparateRecordSets' should be a boolean." + "Property 'Domain.Route53.SeparateRecordSetGroup' should be a boolean." ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [ApiGatewayAdminTwo] is invalid. Property 'Domain.Route53.SeparateRecordSets' should be a boolean." + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [ApiGatewayAdminTwo] is invalid. Property 'Domain.Route53.SeparateRecordSetGroup' should be a boolean." } diff --git a/tests/translator/output/aws-cn/separate_route53_recordset.json b/tests/translator/output/separate_route53_recordset_group.json similarity index 82% rename from tests/translator/output/aws-cn/separate_route53_recordset.json rename to tests/translator/output/separate_route53_recordset_group.json index e5c7e0bce..5575d8d71 100644 --- a/tests/translator/output/aws-cn/separate_route53_recordset.json +++ b/tests/translator/output/separate_route53_recordset_group.json @@ -130,9 +130,9 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminThreeDeployment8072e30741": { + "ApiGatewayAdminThreeDeploymentc2e9ae5463": { "Properties": { - "Description": "RestApi deployment id: 8072e3074183e87bf1f82d54e544b73432f82027", + "Description": "RestApi deployment id: c2e9ae5463d31ad96611e5aab9b4ddd4fd7bde73", "RestApiId": { "Ref": "ApiGatewayAdminThree" }, @@ -143,7 +143,7 @@ "ApiGatewayAdminThreeProdStage": { "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminThreeDeployment8072e30741" + "Ref": "ApiGatewayAdminThreeDeploymentc2e9ae5463" }, "MethodSettings": [ { @@ -200,10 +200,10 @@ }, "Type": "AWS::ApiGateway::BasePathMapping" }, - "ApiGatewayAdminTwoDeploymentbc167043f5": { + "ApiGatewayAdminTwoDeployment2a68098964": { "Condition": "CreateProdResources", "Properties": { - "Description": "RestApi deployment id: bc167043f5ea3d06b5c23c89d62be1cbe7734cac", + "Description": "RestApi deployment id: 2a6809896451eb172efffcdcd18396e1a83df12a", "RestApiId": { "Ref": "ApiGatewayAdminTwo" }, @@ -215,7 +215,7 @@ "Condition": "CreateProdResources", "Properties": { "DeploymentId": { - "Ref": "ApiGatewayAdminTwoDeploymentbc167043f5" + "Ref": "ApiGatewayAdminTwoDeployment2a68098964" }, "MethodSettings": [ { @@ -269,28 +269,6 @@ }, "Type": "AWS::ApiGateway::DomainName" }, - "RecordSet81840409a4": { - "Properties": { - "AliasTarget": { - "DNSName": { - "Fn::GetAtt": [ - "ApiGatewayDomainName41bfc7f9c4", - "RegionalDomainName" - ] - }, - "HostedZoneId": { - "Fn::GetAtt": [ - "ApiGatewayDomainName41bfc7f9c4", - "RegionalHostedZoneId" - ] - } - }, - "HostedZoneId": "abc123456", - "Name": "admin.three.amazon.com", - "Type": "A" - }, - "Type": "AWS::Route53::RecordSet" - }, "RecordSetGroup370194ff6e": { "Properties": { "HostedZoneId": "abc123456", @@ -317,28 +295,58 @@ }, "Type": "AWS::Route53::RecordSetGroup" }, - "RecordSetb3fa99c196": { - "Condition": "CreateProdResources", + "RecordSetGroup81840409a4": { "Properties": { - "AliasTarget": { - "DNSName": { - "Fn::GetAtt": [ - "ApiGatewayDomainName3fd2dbd8f8", - "RegionalDomainName" - ] - }, - "HostedZoneId": { - "Fn::GetAtt": [ - "ApiGatewayDomainName3fd2dbd8f8", - "RegionalHostedZoneId" - ] + "HostedZoneId": "abc123456", + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName41bfc7f9c4", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.three.amazon.com", + "Type": "A" } - }, + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + }, + "RecordSetGroupb3fa99c196": { + "Condition": "CreateProdResources", + "Properties": { "HostedZoneId": "abc123456", - "Name": "admin.two.amazon.com", - "Type": "A" + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainName3fd2dbd8f8", + "RegionalHostedZoneId" + ] + } + }, + "Name": "admin.two.amazon.com", + "Type": "A" + } + ] }, - "Type": "AWS::Route53::RecordSet" + "Type": "AWS::Route53::RecordSetGroup" } } } From d650868341efd94a60dda319e095a32f963eefb5 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Thu, 16 Mar 2023 13:20:13 -0700 Subject: [PATCH 12/13] address comments --- samtranslator/model/api/api_generator.py | 5 +++-- samtranslator/model/route53.py | 18 +----------------- samtranslator/model/sam_resources.py | 2 +- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 1661dca35..d57bb2f91 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -604,8 +604,9 @@ def _construct_single_record_set_group( hostedZoneId = route53.get("HostedZoneId") hostedZoneName = route53.get("HostedZoneName") domainName = domain.get("DomainName") - logical_id_suffix = LogicalIdGenerator("", [hostedZoneId or hostedZoneName, domainName]).gen() - logical_id = "RecordSetGroup" + logical_id_suffix + logical_id = logical_id = LogicalIdGenerator( + "RecordSetGroup", [hostedZoneId or hostedZoneName, domainName] + ).gen() record_set_group = Route53RecordSetGroup(logical_id, attributes=self.passthrough_resource_attributes) if hostedZoneId: diff --git a/samtranslator/model/route53.py b/samtranslator/model/route53.py index c3a033841..deab5c522 100644 --- a/samtranslator/model/route53.py +++ b/samtranslator/model/route53.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional +from typing import Any, List, Optional from samtranslator.model import GeneratedProperty, Resource from samtranslator.utils.types import Intrinsicable @@ -15,19 +15,3 @@ class Route53RecordSetGroup(Resource): HostedZoneId: Optional[Intrinsicable[str]] HostedZoneName: Optional[Intrinsicable[str]] RecordSets: Optional[List[Any]] - - -class Route53RecordSet(Resource): - resource_type = "AWS::Route53::RecordSet" - property_types = { - "HostedZoneId": GeneratedProperty(), - "HostedZoneName": GeneratedProperty(), - "AliasTarget": GeneratedProperty(), - "Name": GeneratedProperty(), - "Type": GeneratedProperty(), - } - HostedZoneId: Optional[Intrinsicable[str]] - HostedZoneName: Optional[Intrinsicable[str]] - AliasTarget: Optional[Dict[str, Any]] - Name: Optional[Intrinsicable[str]] - Type: Optional[Intrinsicable[str]] diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 1ad4f5e9d..31a09b225 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -1279,7 +1279,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] redeploy_restapi_parameters, route53_record_set_groups ) - resources: List[Any] = [] + resources: List[Resource] = [] for resource in generated_api_resources: if resource: From 364fc55e74c083faeb37ba10e8fca59a3ddff987 Mon Sep 17 00:00:00 2001 From: Xia Zhao Date: Thu, 16 Mar 2023 14:56:43 -0700 Subject: [PATCH 13/13] refactor and add type --- samtranslator/model/api/api_generator.py | 15 +++++++++++++-- samtranslator/model/sam_resources.py | 16 ++-------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index d57bb2f91..d3de468d8 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -667,7 +667,7 @@ def _construct_alias_target(self, domain: Dict[str, Any], api_domain_name: str, @cw_timer(prefix="Generator", name="Api") def to_cloudformation( self, redeploy_restapi_parameters: Optional[Any], route53_record_set_groups: Dict[str, Route53RecordSetGroup] - ) -> List[Any]: + ) -> List[Resource]: """Generates CloudFormation resources from a SAM API resource :returns: a tuple containing the RestApi, Deployment, and Stage for an empty Api. @@ -702,6 +702,7 @@ def to_cloudformation( List[ApiGatewayBasePathMapping], ], ] = [] + generated_resources.extend( [ rest_api, @@ -714,7 +715,17 @@ def to_cloudformation( usage_plan, ] ) - return generated_resources + + # Make a list of single resources + generated_resources_list: List[Resource] = [] + for resource in generated_resources: + if resource: + if isinstance(resource, (list, tuple)): + generated_resources_list.extend(resource) + else: + generated_resources_list.extend([resource]) + + return generated_resources_list def _add_cors(self) -> None: """ diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 31a09b225..4b9f372ea 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -1220,7 +1220,7 @@ class SamApi(SamResourceMacro): } @cw_timer - def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] + def to_cloudformation(self, **kwargs) -> List[Resource]: # type: ignore[no-untyped-def] """Returns the API Gateway RestApi, Deployment, and Stage to which this SAM Api corresponds. :param dict kwargs: already-converted resources that may need to be modified when converting this \ @@ -1275,19 +1275,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] always_deploy=self.AlwaysDeploy, ) - generated_api_resources = api_generator.to_cloudformation( - redeploy_restapi_parameters, route53_record_set_groups - ) - - resources: List[Resource] = [] - - for resource in generated_api_resources: - if resource: - if isinstance(resource, (list, tuple)): - resources.extend(resource) - else: - resources.extend([resource]) - return resources + return api_generator.to_cloudformation(redeploy_restapi_parameters, route53_record_set_groups) class SamHttpApi(SamResourceMacro):