From a5bd7adf09e383f6382f052eccbdd183c3a79637 Mon Sep 17 00:00:00 2001 From: Efe Karakus Date: Tue, 30 Jun 2020 11:30:14 -0700 Subject: [PATCH] fix(templates): render service cfn templates when addons have no outputs Previously, if an addon template did not output the ARN of a IAM ManagedPolicy then the service template would not render with a `ValidationError: [/Resources/TaskRole/Type/ManagedPolicyArns] 'null' values are not allowed in templates`. Fixes #1073 --- .../pkg/template/template_integration_test.go | 63 +++++++++++++++++++ templates/services/common/cf/taskrole.yml | 4 +- 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 internal/pkg/template/template_integration_test.go diff --git a/internal/pkg/template/template_integration_test.go b/internal/pkg/template/template_integration_test.go new file mode 100644 index 00000000000..ea719b27cd3 --- /dev/null +++ b/internal/pkg/template/template_integration_test.go @@ -0,0 +1,63 @@ +// +build integration + +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package template_test + +import ( + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/copilot-cli/internal/pkg/aws/session" + "github.com/aws/copilot-cli/internal/pkg/template" + "github.com/stretchr/testify/require" +) + +func TestTemplate_ParseLoadBalancedWebService(t *testing.T) { + testCases := map[string]struct { + opts template.ServiceOpts + }{ + "renders a valid template by default": { + opts: template.ServiceOpts{}, + }, + "renders a valid template with addons with no outputs": { + opts: template.ServiceOpts{ + NestedStack: &template.ServiceNestedStackOpts{ + StackName: "AddonsStack", + }, + }, + }, + "renders a valid template with addons with outputs": { + opts: template.ServiceOpts{ + NestedStack: &template.ServiceNestedStackOpts{ + StackName: "AddonsStack", + VariableOutputs: []string{"TableName"}, + SecretOutputs: []string{"TablePassword"}, + PolicyOutputs: []string{"TablePolicy"}, + }, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + // GIVEN + sess, err := session.NewProvider().Default() + require.NoError(t, err) + cfn := cloudformation.New(sess) + tpl := template.New() + + // WHEN + content, err := tpl.ParseLoadBalancedWebService(tc.opts) + require.NoError(t, err) + + // THEN + _, err = cfn.ValidateTemplate(&cloudformation.ValidateTemplateInput{ + TemplateBody: aws.String(content.String()), + }) + require.NoError(t, err, content.String()) + }) + } +} \ No newline at end of file diff --git a/templates/services/common/cf/taskrole.yml b/templates/services/common/cf/taskrole.yml index 495eaa0bf89..56edac7f677 100644 --- a/templates/services/common/cf/taskrole.yml +++ b/templates/services/common/cf/taskrole.yml @@ -1,8 +1,8 @@ TaskRole: Type: AWS::IAM::Role - Properties:{{if .NestedStack}}{{$stackName := .NestedStack.StackName}} + Properties:{{if .NestedStack}}{{$stackName := .NestedStack.StackName}}{{if gt (len .NestedStack.PolicyOutputs) 0}} ManagedPolicyArns:{{range $managedPolicy := .NestedStack.PolicyOutputs}} - - Fn::GetAtt: [{{$stackName}}, Outputs.{{$managedPolicy}}]{{end}}{{end}} + - Fn::GetAtt: [{{$stackName}}, Outputs.{{$managedPolicy}}]{{end}}{{end}}{{end}} AssumeRolePolicyDocument: Statement: - Effect: Allow