Reputation: 169
I have a CloudFormation template that defines this parameter:
"AvailabilityZones" : {
"Description" : "List of Availability Zones used ... ",
"Type" : "List<AWS::EC2::AvailabilityZone::Name>"
},
I invoke the CF template like this:
resource "aws_cloudformation_stack" "xxx" {
name = "xxx-stack"
template_body = file("../cloudformation/xxx_CloudFormation_template_2.1.1.json")
parameters = {
VpcId = aws_vpc.xxxvpc.id
SubnetCidrBlock = var.aws_vpc_cidr
AvailabilityZones = var.aws_azs
InstanceType = "m5.4xlarge"
ExternalNet = "0.0.0.0/0"
....
}
on_failure = "DELETE"
}
Where:
variable "aws_azs" {
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
I get the error:
Inappropriate value for attribute "parameters": element "AvailabilityZones": string required.
I have tried many variations on this theme, but I can't see how to pass a list of AZs to the CF template from TF.
I am also more than a little puzzled by the assertion that a string is required in the error message, as the parameter type in the CF template is defined as a list.
Any ideas please?
Upvotes: 1
Views: 960
Reputation: 77
To pass a list of values from Terraform to CloudFormation you will need to join them as a comma separated list.
TL;DR
resource "aws_cloudformation_stack" "this" {
...
parameters = {
AvailabilityZones = join(",", ["us-east-1a", "us-east-1b", "us-east-1c"])
}
}
Explanation
To pass lists of things to a CloudFormation template you will have to either pass a native construct or a comma separated list of values.
https://aws.amazon.com/premiumsupport/knowledge-center/multiple-values-list-parameter-cli/
Consider we have a CloudFormation template cfn-template.yml
that requires us to pass a list of AZs as parameter:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
AvailabilityZones:
Description: List of Availability Zones used ...
Type: "List<AWS::EC2::AvailabilityZone::Name>"
Resources:
NullResource: # CF needs at least 1 resource, so we hand it a dummy
Type: "AWS::CloudFormation::WaitConditionHandle"
Outputs:
PassedAvailabilityZones:
Description: The AZs passed into the cfn template from Terraform.
Value: !Join [ ",", !Ref AvailabilityZones ]
In your terraform we will need to create a comma separated string of these values and pass them in the parameter block.
variable "aws_azs" {
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
resource "aws_cloudformation_stack" "this" {
name = "test-pass-azs"
parameters = {
AvailabilityZones = join(",", var.aws_azs)
}
template_body = file("./cfn-template.yml")
}
terraform {
required_version = "~> 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
Upvotes: 1
Reputation: 2531
I would prefer to use the templatefile
function instead of the file
you are using in the template_body
field. You can pass variables there and fill the template with passed variables with nice template engine. You can use variables, functions, statements and loops there.
Example is here https://www.terraform.io/docs/language/functions/templatefile.html
Your example
resource "aws_cloudformation_stack" "xxx" {
....
template_body = templatefile("../cloudformation/xxx_CloudFormation_template_2.1.1.json", {
aws_azs = var. aws_azs
})
....
}
and your cf file:
"AvailabilityZones" : {
"Description" : "List of Availability Zones used ${join(',', aws_azs)} ",
"Type" : "List<AWS::EC2::AvailabilityZone::Name>"
},
Upvotes: 1