Closed
Description
Source
# Summary: Uses 'dynamic' to create multiple 'ingress' blocks within an 'aws_security_group' resource.
# Documentation: https://www.terraform.io/docs/language/settings/index.html
terraform {
required_version = ">= 1.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.38"
}
}
}
# Documentation: https://www.terraform.io/docs/language/providers/requirements.html
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
cs_terraform_examples = "aws_security_group/dynamic"
}
}
}
# Documentation: https://www.terraform.io/docs/language/values/locals.html
locals {
ports = [80, 443, 8080]
}
# Documentation: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
resource "aws_security_group" "changeme_aws_security_group_dynamic" {
name = "changeme-aws-security-group-dynamic"
# Documentation: https://www.terraform.io/docs/language/expressions/dynamic-blocks.html
dynamic "ingress" {
for_each = local.ports
content {
description = "changeme-aws-security-group-dynamic-ingress-${ingress.key}"
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
Converted
The errors are included in the output, so I'm pasting them here too.
// �[91m[2023-01-26T12:19:50.402] [ERROR] default - �[39mFound a reference that is unknown: changeme-aws-security-group-dynamic-ingress-${ingress.key} has reference "ingress.key". The id was not found in ["aws","local.ports","aws_security_group.changeme_aws_security_group_dynamic","ingress"] with temporary values [].
// Please leave a comment at https://cdk.tf/bugs/convert-expressions if you run into this issue.
// �[91m[2023-01-26T12:19:50.403] [ERROR] default - �[39mFound a reference that is unknown: ${ingress.value} has reference "ingress.value". The id was not found in ["aws","local.ports","aws_security_group.changeme_aws_security_group_dynamic","ingress"] with temporary values [].
// Please leave a comment at https://cdk.tf/bugs/convert-expressions if you run into this issue.
// �[91m[2023-01-26T12:19:50.403] [ERROR] default - �[39mFound a reference that is unknown: ${ingress.value} has reference "ingress.value". The id was not found in ["aws","local.ports","aws_security_group.changeme_aws_security_group_dynamic","ingress"] with temporary values [].
// Please leave a comment at https://cdk.tf/bugs/convert-expressions if you run into this issue.
// �[91m[2023-01-26T12:19:50.408] [ERROR] default - �[39mFound a reference that is unknown: changeme-aws-security-group-dynamic-ingress-${ingress.key} has reference "ingress.key". The id was not found in ["aws","local.ports","aws_security_group.changeme_aws_security_group_dynamic"] with temporary values ["ingress"].
// Please leave a comment at https://cdk.tf/bugs/convert-expressions if you run into this issue.
// �[91m[2023-01-26T12:19:50.408] [ERROR] default - �[39mFound a reference that is unknown: ${ingress.value} has reference "ingress.value". The id was not found in ["aws","local.ports","aws_security_group.changeme_aws_security_group_dynamic"] with temporary values ["ingress"].
// Please leave a comment at https://cdk.tf/bugs/convert-expressions if you run into this issue.
// �[91m[2023-01-26T12:19:50.408] [ERROR] default - �[39mFound a reference that is unknown: ${ingress.value} has reference "ingress.value". The id was not found in ["aws","local.ports","aws_security_group.changeme_aws_security_group_dynamic"] with temporary values ["ingress"].
// Please leave a comment at https://cdk.tf/bugs/convert-expressions if you run into this issue.
import { Construct } from "constructs";
import { TerraformStack } from "cdktf";
/*Provider bindings are generated by running cdktf get.
See https://cdk.tf/provider-generation for more details.*/
import * as aws from "../../.gen/providers/aws";
export class MyStack extends TerraformStack {
constructor(scope: Construct, id: string) {
super(scope, id);
new aws.provider.AwsProvider(this, "aws", {
defaultTags: [
{
tags: {
csTerraformExamples: "aws_security_group/dynamic",
},
},
],
region: "us-east-1",
});
const ports = [80, 443, 8080];
const awsSecurityGroupChangemeAwsSecurityGroupDynamic =
new aws.securityGroup.SecurityGroup(
this,
"changeme_aws_security_group_dynamic",
{
ingress: [],
name: "changeme-aws-security-group-dynamic",
}
);
/*In most cases loops should be handled in the programming language context and
not inside of the Terraform context. If you are looping over something external, e.g. a variable or a file input
you should consider using a for loop. If you are looping over something only known to Terraform, e.g. a result of a data source
you need to keep this like it is.*/
awsSecurityGroupChangemeAwsSecurityGroupDynamic.addOverride("ingress", {
for_each: ports,
content: [
{
cidr_blocks: ["0.0.0.0/0"],
description:
"changeme-aws-security-group-dynamic-ingress-${ingress.key}",
from_port: "${ingress.value}",
protocol: "tcp",
to_port: "${ingress.value}",
},
],
});
}
}
Another example in Python:
The same example seems to work for Typescript, but does not for Python (and possibly other languages)
ports = [80, 443, 8080]
aws_security_group_changeme_aws_security_group_dynamic = aws.security_group.SecurityGroup(self, "changeme_aws_security_group_dynamic",
ingress=[],
name="changeme-aws-security-group-dynamic"
)
# In most cases loops should be handled in the programming language context and
# not inside of the Terraform context. If you are looping over something external, e.g. a variable or a file input
# you should consider using a for loop. If you are looping over something only known to Terraform, e.g. a result of a data source
# you need to keep this like it is.
aws_security_group_changeme_aws_security_group_dynamic.add_override("ingress",
for_each=ports,
content=[{
"cidr_blocks": ["0.0.0.0/0"],
"description": "changeme-aws-security-group-dynamic-ingress-${ingress.key}",
"from_port": "${ingress.value}",
"protocol": "tcp",
"to_port": "${ingress.value}"
}
]
)
Traceback (most recent call last):
File "/Users/mutahhir/src/scratchpad/terraform-convert-examples/converted-langs/python/aws/main.py", line 66, in <module>
aws_security_group_dynamic(app, "aws_security_group_dynamic")
File "/Users/mutahhir/.local/share/virtualenvs/aws-CDeXujSt/lib/python3.10/site-packages/jsii/_runtime.py", line 111, in __call__
inst = super().__call__(*args, **kwargs)
File "/Users/mutahhir/src/scratchpad/terraform-convert-examples/converted-langs/python/aws/aws_security_group/dynamic/main.py", line 43, in __init__
aws_security_group_changeme_aws_security_group_dynamic.add_override("ingress",
TypeError: TerraformElement.add_override() got an unexpected keyword argument 'for_each'
# Documentation: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
resource "aws_security_group" "changeme_aws_security_group_dynamic" {
name = "changeme-aws-security-group-dynamic"
# Documentation: https://www.terraform.io/docs/language/expressions/dynamic-blocks.html
dynamic "ingress" {
for_each = local.ports
content {
description = "changeme-aws-security-group-dynamic-ingress-${ingress.key}"
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
Solution
Converting the override to a map works well
# In most cases loops should be handled in the programming language context and
# not inside of the Terraform context. If you are looping over something external, e.g. a variable or a file input
# you should consider using a for loop. If you are looping over something only known to Terraform, e.g. a result of a data source
# you need to keep this like it is.
aws_security_group_changeme_aws_security_group_dynamic.add_override("ingress", {
"for_each": ports,
"content": [{
"cidr_blocks": ["0.0.0.0/0"],
"description": "changeme-aws-security-group-dynamic-ingress-${ingress.key}",
"from_port": "${ingress.value}",
"protocol": "tcp",
"to_port": "${ingress.value}"
}]
})