I'm fighting with wired case. I need to push cloudformation stacks dynamically parameterized with terraform.
My resource looks like this.
resource "aws_cloudformation_stack" "eks-single-az" {
count = length(var.single_az_node_groups)
name = "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"
template_body = <<EOF
Description: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"
Resources:
ASG:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"
VPCZoneIdentifier: ["${var.private_subnet_ids[count.index]}"]
MinSize: "${lookup(var.single_az_node_groups[count.index], "asg_min", "0")}"
MaxSize: "${lookup(var.single_az_node_groups[count.index], "asg_max", "10")}"
HealthCheckType: EC2
TargetGroupARNs: [] < - here is error.
MixedInstancesPolicy:
InstancesDistribution:
OnDemandBaseCapacity: "0"
OnDemandPercentageAboveBaseCapacity: "${lookup(var.single_az_node_groups[count.index], "on_demand_percentage", "0")}"
LaunchTemplate:
LaunchTemplateSpecification:
LaunchTemplateId: "${aws_launch_template.eks-single-az[count.index].id}"
Version: "${aws_launch_template.eks-single-az[count.index].latest_version}"
Overrides:
-
InstanceType: m5.large
Tags:
- Key: "Name"
Value: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}"
PropagateAtLaunch: true
- Key: "kubernetes.io/cluster/${var.cluster_name}"
Value: "owned"
PropagateAtLaunch: true
- Key: "k8s.io/cluster-autoscaler/enabled"
Value: "true"
PropagateAtLaunch: true
- Key: "k8s.io/cluster-autoscaler/${var.cluster_name}"
Value: "true"
PropagateAtLaunch: true
UpdatePolicy:
AutoScalingRollingUpdate:
MinSuccessfulInstancesPercent: 80
MinInstancesInService: "${lookup(data.external.desired_capacity.result, "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}", "0")}"
PauseTime: PT4M
SuspendProcesses:
- HealthCheck
- ReplaceUnhealthy
- AZRebalance
- AlarmNotification
- ScheduledActions
WaitOnResourceSignals: true
EOF
depends_on = [
aws_launch_template.eks-single-az
]
}
I need to put target groups arn from list containing json objects:
single_az_node_groups = [
{
"name" : "workload-az1",
"instance_type" : "t2.micro",
"asg_min" : "1",
"asg_max" : "7",
"target_group_arns" : "arnA, arnB, arnC"
},
...
]
I tried everything. Problem is that i tried many terraform functions and all the time terraform is addding some double-quotes which cloudformation does not support or terraform won't process the template_body becuase of missing quotes..
Do you know meybe some sneaky trick how to achive that ?
When building strings that represent serialized data structures, it's much easier to use Terraform's built-in serialization functions to construct the result, rather than trying to produce a valid string using string templates.
In this case, we can use jsonencode
to construct a JSON string representing the template_body
from a Terraform object value, which then allows using all of the Terraform language expression features to build it:
template_body = jsonencode({
Description: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}",
Resources: {
ASG: {
Type: "AWS::AutoScaling::AutoScalingGroup",
Properties: {
AutoScalingGroupName: "eks-${var.cluster_name}-${var.single_az_node_groups[count.index].name}",
VPCZoneIdentifier: [var.private_subnet_ids[count.index]],
MinSize: lookup(var.single_az_node_groups[count.index], "asg_min", "0"),
MaxSize: lookup(var.single_az_node_groups[count.index], "asg_max", "10"),
HealthCheckType: "EC2",
TargetGroupArns: flatten([
for g in local.single_az_node_groups : [
split(", ", g.target_group_arns)
]
]),
# etc, etc
},
},
},
})
As you can see above, by using jsonencode
for the entire data structure we can then use Terraform expression operators to build the values. For TargetGroupArns
in the above example I used the flatten
function along with a for
expression to transform the nested local.single_az_node_groups
data structure into a flat list of target group ARN strings.
CloudFormation supports both JSON and YAML, and Terraform also has a yamlencode
function that you could potentially use instead of jsonencode
here. I chose jsonencode
both because yamlencode
is currently marked as experimental (the exact YAML formatting it produces may change in a later release) and because Terraform has special support for JSON formatting in the plan output where it can show a structural diff of the data structure inside, rather than a string-based diff.