Skip to content

Latest commit

 

History

History
1100 lines (930 loc) · 41.1 KB

iterators.mdx

File metadata and controls

1100 lines (930 loc) · 41.1 KB
page_title description
Iterators - CDK for Terraform
Iterators let you loop over a collection of values that are only available at runtime.

Iterators

Iterators let you loop over a collection of values. You can use them to create multiple resources of the same type based on dynamic data that is only known at runtime.

When to Use Iterators

Use iterators when you need to reference dynamic data that is not known until after Terraform applies a configuration. For example, instance IDs that cloud providers assign on creation.

When data is static or you know the values before synthesizing your code, we recommend using loops in your preferred programming language.

Define Iterators

Import the TerraformIterator class and call the .fromList() or .fromMap() static method. Then use the forEach property to pass the iterator to a resource, data source, or module. This lets you use the iterator in attributes.

The following example uses an iterator to create a unique name for each new S3 bucket.

import {
  TerraformIterator,
  TerraformLocal,
  TerraformStack,
  TerraformVariable,
  Token,
} from "cdktf";
import { Construct } from "constructs";
import { AwsProvider } from "@cdktf/provider-aws/lib/aws-provider";
import { S3Bucket } from "@cdktf/provider-aws/lib/s3-bucket";

export class IteratorsStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    new AwsProvider(this, "aws", {
      region: "us-west-2",
    });

    const list = new TerraformVariable(this, "list", {
      type: "list(string)",
    });

    const simpleIterator = TerraformIterator.fromList(list.listValue);

    new S3Bucket(this, "iterator-bucket", {
      forEach: simpleIterator,
      bucket: simpleIterator.value,
    });
  }
}
        TerraformVariable list = new TerraformVariable(this, "list", TerraformVariableConfig.builder()
                .type("list(string)")
                .build());

        TerraformIterator terraformIterator = TerraformIterator.fromList(list.getListValue());

        S3Bucket awsS3Bucket = new S3Bucket(this, "bucket", S3BucketConfig.builder()
                .forEach(terraformIterator)
                .bucket(Token.asString(terraformIterator.getString("")))
                .build());
from imports.aws.s3_bucket import S3Bucket
from cdktf import TerraformIterator, TerraformVariable, TerraformLocal

        list = TerraformVariable(self, "list",
                                 type="list(string)"
                                 )

        iterator = TerraformIterator.from_list(list=list.list_value)

        s3Bucket = S3Bucket(self, "bucket",
                            for_each=iterator,
                            bucket=Token.as_string(iterator.value)
                            )
            TerraformVariable list = new TerraformVariable(this, "list", new TerraformVariableConfig
            {
                Type = "list(string)"
            });

            ListTerraformIterator iterator = ListTerraformIterator.FromList(list.ListValue);
            S3Bucket s3Bucket = new S3Bucket(this, "value-bucket", new S3BucketConfig
            {
                ForEach = iterator,
                Bucket = Token.AsString(iterator.Value)
            });
list := cdktf.NewTerraformVariable(stack, jsii.String("list"), &cdktf.TerraformVariableConfig{
	Type: cdktf.VariableType_LIST_STRING(),
})

simpleIterator := cdktf.TerraformIterator_FromList(list.ListValue())

s3bucket.NewS3Bucket(stack, jsii.String("iterator-bucket"), &s3bucket.S3BucketConfig{
	ForEach: simpleIterator,
	Bucket:  cdktf.Token_AsString(simpleIterator.Value(), nil),
})

You cannot access the index of items when iterating over lists. This is because CDKTF implicitly converts lists to sets when iterating over them, but Terraform requires sets for iteration. This behavior prevents Terraform from accidentally deleting and recreating resources when their indices change. If you need an index, use an escape hatch with the count.index property.

Using Iterators on Complex Types

The iterator also exposes methods to access nested attributes. The following example uses the getString and getStringMap methods to access the name and tags attributes of each list item.

import {
  TerraformIterator,
  TerraformLocal,
  TerraformStack,
  TerraformVariable,
  Token,
} from "cdktf";
import { Construct } from "constructs";
import { AwsProvider } from "@cdktf/provider-aws/lib/aws-provider";
import { S3Bucket } from "@cdktf/provider-aws/lib/s3-bucket";

export class IteratorsStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    new AwsProvider(this, "aws", {
      region: "us-west-2",
    });

    const complexIterator = TerraformIterator.fromMap({
      website: {
        name: "website-static-files",
        tags: { app: "website" },
      },
      images: {
        name: "images",
        tags: { app: "image-converter" },
      },
    });

    new S3Bucket(this, "complex-iterator-bucket", {
      forEach: complexIterator,
      bucket: complexIterator.getString("name"),
      tags: complexIterator.getStringMap("tags"),
    });
  }
}
import imports.aws.s3_bucket.S3Bucket;
import imports.aws.s3_bucket.S3BucketConfig;

        TerraformLocal myComplexLocal = new TerraformLocal(this, "my-map", new HashMap() {
            {
                put("website", new HashMap() {
                    {
                        put("name", "website-static-files");
                        put("tags", new HashMap<String, String>() {
                            {
                                put("app", "website");
                            }
                        });
                    }
                });
                put("images", new HashMap() {
                    {
                        put("name", "images");
                        put("tags", new HashMap<String, String>() {
                            {
                                put("app", "image-converter");
                            }
                        });
                    }
                });
            }
        });

        TerraformIterator iterator = TerraformIterator.fromMap(myComplexLocal.getAsAnyMap());

        S3Bucket s3Bucket = new S3Bucket(this, "bucket", S3BucketConfig.builder()
                .forEach(iterator)
                .bucket(iterator.getString("name"))
                .tags(iterator.getStringMap("tags"))
                .build());
from imports.aws.s3_bucket import S3Bucket
from cdktf import TerraformIterator, TerraformVariable, TerraformLocal
        map = TerraformLocal(self, "my-map", {
            "website": {
                "name": "website-static-files",
                "tags": {"app": "website"}
            },
            "images": {
                "name": "images",
                "tags": {"app": "image-converter"}
            }
        })

        iterator = TerraformIterator.from_map(
            map=map.as_any_map
        )

        s3Bucket = S3Bucket(self, "s3-bucket",
                            for_each=iterator,
                            bucket=iterator.get_string("name"),
                            tags=iterator.get_map("tags")
                            )
// We need a local to be able to pass the list to the iterator
TerraformLocal complexLocal = new TerraformLocal(this, "complex_local", new Dictionary<string, object> {
    {
        "website ",
        new Dictionary<string, object> {
            { "name", "website-static-files" },
            { "tags", new Dictionary<string, string> {
                { "app", "website" }
            }}
        }
    },
    {
        "images",
        new Dictionary<string, object> {
            { "name", "images" },
            { "tags", new Dictionary<string, string> {
                { "app", "image-converter" }
            }}
        }
    }
});
MapTerraformIterator mapIterator = MapTerraformIterator.FromMap(complexLocal.AsAnyMap);
new S3Bucket(this, "tag-bucket", new S3BucketConfig
{
    ForEach = mapIterator,
    Bucket = mapIterator.GetString("name"),
    Tags = mapIterator.GetStringMap("tags")
});
complexList := cdktf.NewTerraformLocal(stack, jsii.String("complex-list-local"), []map[string]interface{}{
	{
		"name": "website-static-files",
		"tags": map[string]string{"app": "website"},
	},
	{
		"name": "images",
		"tags": map[string]string{"app": "image-converter"},
	},
})

complexIterator := cdktf.TerraformIterator_FromList(complexList.Expression())

s3bucket.NewS3Bucket(stack, jsii.String("complex-iterator-bucket"), &s3bucket.S3BucketConfig{
	ForEach: complexIterator,
	Bucket:  complexIterator.GetString(jsii.String("name")),
	Tags:    complexIterator.GetStringMap(jsii.String("tags")),
})

Using Iterators on Complex Lists

There are resources with attributes which are lists of objects whose properties are not all known at plan time. When trying to iterate over these directly, Terraform will error and complain about an invalid for_each argument. To workaround this problem, you can use the TerraformIterator.fromComplexList() method to create an iterator that transforms the list of objects into a map first, which has a key that is known at plan time and whose name is passed to that method. This is common for the aws_acm_certificate resource, whose domain_validation_options attribute is a list of objects with a domain_name property that is known at plan time.

The following example validates an ACM certificate through DNS validation:

const cert = new AcmCertificate(this, "cert", {
  domainName: "example.com",
  validationMethod: "DNS",
});
const dataAwsRoute53ZoneExample = new DataAwsRoute53Zone(this, "dns_zone", {
  name: "example.com",
  privateZone: false,
});

const exampleForEachIterator = TerraformIterator.fromComplexList(
  cert.domainValidationOptions,
  "domain_name"
);

const records = new Route53Record(this, "record", {
  forEach: exampleForEachIterator,
  allowOverwrite: true,
  name: exampleForEachIterator.getString("resource_record_name"),
  records: [exampleForEachIterator.getString("resource_record_value")],
  ttl: 60,
  type: exampleForEachIterator.getString("resource_record_type"),
  zoneId: dataAwsRoute53ZoneExample.zoneId,
});

const recordsIterator = TerraformIterator.fromResources(records);

new AcmCertificateValidation(this, "validation", {
  certificateArn: cert.arn,
  validationRecordFqdns: Token.asList(recordsIterator.pluckProperty("fqdn")),
});
        cert = AcmCertificate(self, "cert",
                              domain_name="example.com",
                              validation_method="DNS",
                              )
        data_aws_route53_zone_example = DataAwsRoute53Zone(self, "dns_zone",
                                                           name="example.com",
                                                           private_zone=False
                                                           )

        example_for_each_iterator = TerraformIterator.from_complex_list(
            cert.domain_validation_options,
            "domain_name"
        )

        records = Route53Record(self, "record",
                                for_each=example_for_each_iterator,
                                allow_overwrite=True,
                                name=example_for_each_iterator.get_string(
                                    "resource_record_name"),
                                records=[
                                    example_for_each_iterator.get_string("resource_record_value")],
                                ttl=60,
                                type=example_for_each_iterator.get_string(
                                    "resource_record_type"),
                                zone_id=data_aws_route53_zone_example.zone_id,
                                )

        records_iterator = TerraformIterator.from_resources(records)

        AcmCertificateValidation(self, "validation",
                                 certificate_arn=cert.arn,
                                 validation_record_fqdns=Token.as_list(
                                     records_iterator.pluck_property(
                                         "fqdn")
                                 ),
                                 )
        AcmCertificate cert = new AcmCertificate(this, "cert", AcmCertificateConfig.builder()
            .domainName("example.com")
            .validationMethod("DNS")
            .build());

        DataAwsRoute53Zone dataAwsRoute53ZoneExample = new DataAwsRoute53Zone(this, "dns_zone", DataAwsRoute53ZoneConfig.builder()
            .name("example.com")
            .privateZone(false)
            .build());

        TerraformIterator exampleForEachIterator = TerraformIterator.fromComplexList(
            cert.getDomainValidationOptions(),
            "domain_name"
        );

        Route53Record records = new Route53Record(this, "record", Route53RecordConfig.builder()
            .forEach(exampleForEachIterator)
            .allowOverwrite(true)
            .name(exampleForEachIterator.getString("resource_record_name"))
            .records(Arrays.asList(exampleForEachIterator.getString("resource_record_value")))
            .ttl(60)
            .type(exampleForEachIterator.getString("resource_record_type"))
            .zoneId(dataAwsRoute53ZoneExample.getZoneId())
            .build());

        TerraformIterator recordsIterator = TerraformIterator.fromResources(records);

        AcmCertificateValidation validation = new AcmCertificateValidation(this, "validation", AcmCertificateValidationConfig.builder()
            .certificateArn(cert.getArn())
            .validationRecordFqdns(Token.asList(
                recordsIterator.pluckProperty("fqdn")
            ))
            .build());
            var cert = new AcmCertificate(this, "cert", new AcmCertificateConfig
            {
                DomainName = "example.com",
                ValidationMethod = "DNS"
            });

            var dataAwsRoute53ZoneExample = new DataAwsRoute53Zone(this, "dns_zone", new DataAwsRoute53ZoneConfig
            {
                Name = "example.com",
                PrivateZone = false
            });

            var exampleForEachIterator = TerraformIterator.FromComplexList(cert.DomainValidationOptions, "domain_name");

            var records = new Route53Record(this, "record", new Route53RecordConfig
            {
                ForEach = exampleForEachIterator,
                AllowOverwrite = true,
                Name = exampleForEachIterator.GetString("resource_record_name"),
                Records = new string[] { exampleForEachIterator.GetString("resource_record_value") },
                Ttl = 60,
                Type = exampleForEachIterator.GetString("resource_record_type"),
                ZoneId = dataAwsRoute53ZoneExample.ZoneId
            });

            var recordsIterator = TerraformIterator.FromResources(records);

            new AcmCertificateValidation(this, "validation", new AcmCertificateValidationConfig
            {
                CertificateArn = cert.Arn,
                ValidationRecordFqdns = Token.AsList(recordsIterator.PluckProperty("fqdn"))
            });
cert := acmcertificate.NewAcmCertificate(stack, jsii.String("cert"), &acmcertificate.AcmCertificateConfig{
	DomainName:       jsii.String("example.com"),
	ValidationMethod: jsii.String("DNS"),
})

dataAwsRoute53ZoneExample := dataawsroute53zone.NewDataAwsRoute53Zone(stack, jsii.String("dns_zone"), &dataawsroute53zone.DataAwsRoute53ZoneConfig{
	Name:        jsii.String("example.com"),
	PrivateZone: jsii.Bool(false),
})

exampleForEachIterator := cdktf.TerraformIterator_FromComplexList(cert.DomainValidationOptions(), jsii.String("domain_name"))

records := route53record.NewRoute53Record(stack, jsii.String("record"), &route53record.Route53RecordConfig{
	ForEach:        exampleForEachIterator,
	AllowOverwrite: jsii.Bool(true),
	Name:           exampleForEachIterator.GetString(jsii.String("resource_record_name")),
	Records:        jsii.Strings(*exampleForEachIterator.GetString(jsii.String("resource_record_value"))),
	Ttl:            jsii.Number(60),
	Type:           exampleForEachIterator.GetString(jsii.String("resource_record_type")),
	ZoneId:         dataAwsRoute53ZoneExample.ZoneId(),
})

recordsIterator := cdktf.TerraformIterator_FromResources(records)

acmcertificatevalidation.NewAcmCertificateValidation(stack, jsii.String("validation"), &acmcertificatevalidation.AcmCertificateValidationConfig{
	CertificateArn:        cert.Arn(),
	ValidationRecordFqdns: cdktf.Token_AsList(recordsIterator.PluckProperty(jsii.String("fqdn")), nil),
})

Using Iterators for List Attributes

You can also use iterators to create a list of objects based on each item in a list and assign the result as a value to a property of a resource. This is equivalent to using Array.map in TypeScript and using dynamic blocks in a Terraform HCL configuration.

Use iterators for list attributes if the length of the list is not known before deploying. Otherwise, use native functions that are available in your language (e.g., Array.map in TypeScript).

The following examples use an iterator to create a team containing each member of an organization.

const orgName = "my-org";

new GithubProvider(this, "github", {
  organization: orgName,
});

const team = new Team(this, "core-team", {
  name: "core",
});

const orgMembers = new DataGithubOrganization(this, "org", {
  name: orgName,
});

const orgMemberIterator = TerraformIterator.fromList(orgMembers.members);

new TeamMembers(this, "members", {
  teamId: team.id,
  members: orgMemberIterator.dynamic({
    username: orgMemberIterator.value,
    role: "maintainer",
  }),
});
        org_name = "my-org"

        GithubProvider(self, "github",
                       organization=org_name
                       )

        github_team = Team(self, "core-team",
                           name="core"
                           )

        org_members = DataGithubOrganization(self, "org",
                                             name=org_name
                                             )

        org_member_iterator = TerraformIterator.from_list(org_members.members)

        TeamMembers(self, "members",
                    team_id=github_team.id,
                    members=org_member_iterator.dynamic({
                        "username": Token().as_string(org_member_iterator.value),
                        "role": "maintainer"
                    })
                    )
        String orgName = "my-org";
        new GithubProvider(this, "github", GithubProviderConfig.builder()
                .organization(orgName)
                .build());
        Team team = new Team(this, "core-team", TeamConfig.builder()
                .name("core")
                .build());

        DataGithubOrganization orgMembers = new DataGithubOrganization(this, "org",
                DataGithubOrganizationConfig.builder()
                        .name(orgName)
                        .build());

        ListTerraformIterator orgMemberIterator = TerraformIterator.fromList(orgMembers.getMembers());

        Map<String, Object> content = new HashMap<String, Object>() {
            {
                put("username", Token.asString(orgMemberIterator.getValue()));
                put("role", "maintainer");
            }
        };

        new TeamMembers(this, "members", TeamMembersConfig.builder()
                .teamId(team.getId())
                .members(orgMemberIterator.dynamic(content))
                .build());
            var orgName = "my-org";

            new GithubProvider(this, "github", new GithubProviderConfig
            {
                Organization = orgName
            });

            var team = new Team(this, "core-team", new TeamConfig
            {
                Name = "core"
            });

            var orgMembers = new DataGithubOrganization(this, "org", new DataGithubOrganizationConfig
            {
                Name = orgName
            });

            ListTerraformIterator orgMemberIterator = TerraformIterator.FromList(orgMembers.Members);

            new TeamMembers(this, "members", new TeamMembersConfig
            {
                TeamId = team.Id,
                Members = orgMemberIterator.Dynamic(new Dictionary<string, object> {
                    { "username", Token.AsString(orgMemberIterator.Value) },
                    { "role", "maintainer" }
                })
            });
orgName := "my-org"

github.NewGithubProvider(stack, jsii.String("github"), &github.GithubProviderConfig{
	Organization: &orgName,
})

team := team.NewTeam(stack, jsii.String("core-team"), &team.TeamConfig{
	Name: jsii.String("core"),
})

orgMembers := datagithuborganization.NewDataGithubOrganization(stack, jsii.String("org"), &datagithuborganization.DataGithubOrganizationConfig{
	Name: &orgName,
})

orgMemberIterator := cdktf.TerraformIterator_FromList(orgMembers.Members())

teammembers.NewTeamMembers(stack, jsii.String("members"), &teammembers.TeamMembersConfig{
	TeamId: team.Id(),
	Members: orgMemberIterator.Dynamic(&map[string]interface{}{
		"username": orgMemberIterator.Value(),
		"role":     jsii.String("maintainer"),
	}),
})

Chaining Iterators

Sometimes the need arises to loop over resources created through an iterator; commonly referred to as chaining. To chain iterators you can use the TerraformIterator.fromResources or TerraformIterator.fromDataSources methods with the resource or data source you want to chain as an argument.

const s3BucketConfigurationIterator = TerraformIterator.fromMap({
  website: {
    name: "website-static-files",
    tags: { app: "website" },
  },
  images: {
    name: "images",
    tags: { app: "image-converter" },
  },
});

const s3Buckets = new S3Bucket(this, "complex-iterator-buckets", {
  forEach: s3BucketConfigurationIterator,
  bucket: s3BucketConfigurationIterator.getString("name"),
  tags: s3BucketConfigurationIterator.getStringMap("tags"),
});

// This would be TerraformIterator.fromDataSources for data_sources
const s3BucketsIterator = TerraformIterator.fromResources(s3Buckets);
const helpFile = new TerraformAsset(this, "help", {
  path: "./help",
});
new S3BucketObject(this, "object", {
  forEach: s3BucketsIterator,
  bucket: s3BucketsIterator.getString("id"),
  key: "help",
  source: helpFile.path,
});
        map = TerraformLocal(self, "my-map", {
            "website": {
                "name": "website-static-files",
                "tags": {"app": "website"}
            },
            "images": {
                "name": "images",
                "tags": {"app": "image-converter"}
            }
        })
        s3_bucket_configuration_iterator = TerraformIterator.from_map(
            map=map.as_any_map
        )
        s3_buckets = S3Bucket(self, "complex-iterator-buckets",
                              for_each=s3_bucket_configuration_iterator,
                              bucket=s3_bucket_configuration_iterator.get_string(
                                  "name"),
                              tags=s3_bucket_configuration_iterator.get_map(
                                  "tags")
                              )

        # This would be TerraformIterator.from_data_sources for data_sources
        s3_buckets_iterator = TerraformIterator.from_resources(s3_buckets)
        help_file = TerraformAsset(self, "help",
                                   path="./help"
                                   )
        S3BucketObject(self, "object",
                       for_each=s3_buckets_iterator,
                       bucket=s3_buckets_iterator.get_string("id"),
                       key="help",
                       source=help_file.path
                       )
        TerraformLocal myComplexLocal = new TerraformLocal(this, "my-map", new HashMap() {
            {
                put("website", new HashMap() {
                    {
                        put("name", "website-static-files");
                        put("tags", new HashMap<String, String>() {
                            {
                                put("app", "website");
                            }
                        });
                    }
                });
                put("images", new HashMap() {
                    {
                        put("name", "images");
                        put("tags", new HashMap<String, String>() {
                            {
                                put("app", "image-converter");
                            }
                        });
                    }
                });
            }
        });

        TerraformIterator s3BucketConfigurationIterator = TerraformIterator.fromMap(myComplexLocal.getAsAnyMap());
        S3Bucket s3Bucket = new S3Bucket(this, "buckets", S3BucketConfig.builder()
                .forEach(s3BucketConfigurationIterator)
                .bucket(s3BucketConfigurationIterator.getString("name"))
                .tags(s3BucketConfigurationIterator.getStringMap("tags"))
                .build());

        TerraformAsset asset = new TerraformAsset(this, "help", TerraformAssetConfig.builder()
                .path(Paths.get(System.getProperty("user.dir"), "help").toString())
                .build()
        );

        // This would be TerraformIterator.fromDataSources for data_sources
        TerraformIterator s3BucketIterator = TerraformIterator.fromResources(s3Bucket);
        new S3BucketObject(this, "object", S3BucketObjectConfig.builder()
                .forEach(s3BucketIterator)
                .bucket(s3BucketIterator.getString("id"))
                .key("help")
                .source(asset.getPath())
                .build()
        );
            // We need a local to be able to pass the list to the iterator
            TerraformLocal configuration = new TerraformLocal(this, "configuration", new Dictionary<string, object> {
                {
                    "website",
                    new Dictionary<string, object> {
                        { "name", "website-static-files" },
                        { "tags", new Dictionary<string, string> {
                            { "app", "website" }
                        }}
                    }
                },
                {
                    "images",
                    new Dictionary<string, object> {
                        { "name", "images" },
                        { "tags", new Dictionary<string, string> {
                            { "app", "image-converter" }
                        }}
                    }
                }
            });
            MapTerraformIterator s3BucketConfigurationIterator = MapTerraformIterator.FromMap(configuration.AsAnyMap);
            S3Bucket s3Buckets = new S3Bucket(this, "complex-iterator-buckets", new S3BucketConfig
            {
                ForEach = s3BucketConfigurationIterator,
                Bucket = s3BucketConfigurationIterator.GetString("name"),
                Tags = mapIterator.GetStringMap("tags")
            });

            // This would be TerraformIterator.fromDataSources for data_sources
            TerraformIterator s3BucketsIterator = TerraformIterator.FromResources(s3Buckets);
            TerraformAsset helpFile = new TerraformAsset(this, "help", new TerraformAssetConfig
            {
                Path = "./help"
            });
            new S3BucketObject(this, "object", new S3BucketObjectConfig
            {
                ForEach = s3BucketsIterator,
                Bucket = s3BucketsIterator.GetString("id"),
                Key = "help",
                Source = helpFile.Path
            });
config := cdktf.NewTerraformLocal(stack, jsii.String("config-local"), []map[string]interface{}{
	{
		"name": "website-static-files",
		"tags": map[string]string{"app": "website"},
	},
	{
		"name": "images",
		"tags": map[string]string{"app": "image-converter"},
	},
})

s3BucketConfigurationIterator := cdktf.TerraformIterator_FromList(config.Expression())
s3Buckets := s3bucket.NewS3Bucket(stack, jsii.String("complex-iterator-buckets"), &s3bucket.S3BucketConfig{
	ForEach: s3BucketConfigurationIterator,
	Bucket:  s3BucketConfigurationIterator.GetString(jsii.String("name")),
	Tags:    s3BucketConfigurationIterator.GetStringMap(jsii.String("tags")),
})

s3BucketsIterator := cdktf.TerraformIterator_FromResources(s3Buckets)
helpFile := cdktf.NewTerraformAsset(stack, jsii.String("help"), &cdktf.TerraformAssetConfig{
	Path: jsii.String("./help"),
})
s3bucketobject.NewS3BucketObject(stack, jsii.String("object"), &s3bucketobject.S3BucketObjectConfig{
	ForEach: s3BucketsIterator,
	Bucket:  s3BucketsIterator.GetString(jsii.String("id")),
	Key:     jsii.String("help"),
	Source:  helpFile.Path(),
})

Using for expressions

To use the values of an iterator for example in a list attribute for a resource you can use one of the following methods (given that iterator got created through one of the static methods on TerraformIterator):

  • iterator.keys(): Results in equivalent of [for k, v in var.iteratorSource : k].
  • iterator.values(): Results in equivalent of [for k, v in var.iteratorSource : v].
  • iterator.pluckProperty("foo"): Results in equivalent of [for k, v in var.iteratorSource : v.foo].
  • iterator.forExpressionForList('uppercase(val.owner) if val.owner != ""'): Results in equivalent of [ for key, val in toset(var.list): uppercase(val.owner) if val.owner != "" ].
  • iterator.forExpressionForMap("val.teamName", join(",", val.teamMembers) if length(val.teamMembers) > 0): Results in equivalent of { for key, val in toset(var.list): val.teamName => join(",", val.teamMembers) if length(val.teamMembers) > 0 }.
const mapIterator = TerraformIterator.fromMap({
  website: {
    name: "website-static-files",
    tags: { app: "website" },
    included: true,
  },
  images: {
    name: "images",
    tags: { app: "image-converter" },
  },
});
new TerraformLocal(this, "list-of-keys", mapIterator.keys());
new TerraformLocal(this, "list-of-values", mapIterator.values());
new TerraformLocal(this, "list-of-names", mapIterator.pluckProperty("name"));
new TerraformLocal(
  this,
  "list-of-names-of-included",
  mapIterator.forExpressionForList("val.name if val.included")
);
new TerraformLocal(
  this,
  "map-with-names-as-key-and-tags-as-value-of-included",
  mapIterator.forExpressionForMap("val.name", "val.tags if val.included")
);
values = TerraformLocal(self, "map-local", {
    "website": {
        "name": "website-static-files",
        "tags": {"app": "website"}
    },
    "images": {
        "name": "images",
        "tags": {"app": "image-converter"}
    }
})
mapIterator = TerraformIterator.from_map(
    map=values.as_any_map
)
TerraformLocal(self, "list-of-keys", mapIterator.keys())
TerraformLocal(self, "list-of-values", mapIterator.values())
TerraformLocal(self, "list-of-names",
               mapIterator.pluck_property("name"))
TerraformLocal(self, "list-of-names-of-included",
               mapIterator.for_expression_for_list("val.name if val.included"))
TerraformLocal(self, "map-with-names-as-key-and-tags-as-value-of-included",
               mapIterator.for_expression_for_map("val.name", "val.tags if val.included"))
        TerraformLocal values = new TerraformLocal(this, "values", new HashMap() {
            {
                put("website", new HashMap() {
                    {
                        put("name", "website-static-files");
                        put("tags", new HashMap<String, String>() {
                            {
                                put("app", "website");
                            }
                        });
                    }
                });
                put("images", new HashMap() {
                    {
                        put("name", "images");
                        put("tags", new HashMap<String, String>() {
                            {
                                put("app", "image-converter");
                            }
                        });
                    }
                });
            }
        });

        TerraformIterator mapIterator = TerraformIterator.fromMap(values.getAsAnyMap());
        new TerraformLocal(this, "list-of-keys", mapIterator.keys());
        new TerraformLocal(this, "list-of-values", mapIterator.values());
        new TerraformLocal(this, "list-of-names", mapIterator.pluckProperty("name"));
        new TerraformLocal(this, "list-of-names-of-included", mapIterator.forExpressionForList("val.name if val.included"));
        new TerraformLocal(this, "map-with-names-as-key-and-tags-as-value-of-included", mapIterator.forExpressionForMap("val.name", "val.tags if val.included"));
TerraformLocal values = new TerraformLocal(this, "iterator-values", new Dictionary<string, object> {
    {
        "website",
        new Dictionary<string, object> {
            { "name", "website-static-files" },
            { "tags", new Dictionary<string, string> {
                { "app", "website" }
            }}
        }
    },
    {
        "images",
        new Dictionary<string, object> {
            { "name", "images" },
            { "tags", new Dictionary<string, string> {
                { "app", "image-converter" }
            }}
        }
    }
});
MapTerraformIterator mapIterator = MapTerraformIterator.FromMap(values.AsAnyMap);
new TerraformLocal(this, "list-of-keys", mapIterator.Keys());
new TerraformLocal(this, "list-of-values", mapIterator.Values());
new TerraformLocal(this, "list-of-names", mapIterator.PluckProperty("name"));
new TerraformLocal(this, "list-of-names-of-included", mapIterator.ForExpressionForList("val.name if val.included"));
new TerraformLocal(this, "map-with-names-as-key-and-tags-as-value-of-included", mapIterator.ForExpressionForMap("val.name", "val.tags if val.included"));
values := cdktf.NewTerraformLocal(stack, jsii.String("values"), []map[string]interface{}{
	{
		"name": "website-static-files",
		"tags": map[string]string{"app": "website"},
	},
	{
		"name": "images",
		"tags": map[string]string{"app": "image-converter"},
	},
})

mapIterator := cdktf.TerraformIterator_FromList(values.Expression())
cdktf.NewTerraformLocal(stack, jsii.String("list-of-keys"), mapIterator.Keys())
cdktf.NewTerraformLocal(stack, jsii.String("list-of-values"), mapIterator.Values())
cdktf.NewTerraformLocal(stack, jsii.String("list-of-names"), mapIterator.PluckProperty(jsii.String("name")))
cdktf.NewTerraformLocal(stack, jsii.String("list-of-names-of-included"), mapIterator.ForExpressionForList(jsii.String("val.name if val.included")))
cdktf.NewTerraformLocal(stack, jsii.String("map-with-names-as-key-and-tags-as-value-of-included"), mapIterator.ForExpressionForMap(jsii.String("val.name"), jsii.String("val.tags if val.included")))

Using Count

You can also use the TerraformCount class to achieve the equivalent of setting count on resources in HCL Terraform. Refer to the Terraform docs for more information on the count meta argument. This is useful when there's a numeric value that is only known at runtime that affects the amount of resources that should be created and those resources are almost identical. For most cases, however, Iterators are preferred over count. Refer to the Terraform docs for the underlying reasons.

The following examples use TerraformCount to create a specific amount of instances that is defined via a Terraform variable.

const servers = new TerraformVariable(this, "servers", {
  type: "number",
});

const count = TerraformCount.of(servers.numberValue);

new Instance(this, "server", {
  count: count,
  ami: "ami-a1b2c3d4",
  instanceType: "t2.micro",
  tags: {
    Name: "Server ${" + count.index + "}",
  },
});
        servers = TerraformVariable(self, "servers",
                                    type="number"
                                    )

        count = TerraformCount.of(servers.number_value)

        Instance(self, "server",
                 count=count,
                 ami="ami-a1b2c3d4",
                 instance_type="t2.micro",
                 tags={
                     "Name": "Server ${" + Token().as_string(count.index) + "}"
                 }
                 )
        TerraformVariable servers = TerraformVariable.Builder.create(this, "servers")
                .type(VariableType.NUMBER)
                .build();

        TerraformCount count = TerraformCount.of(servers.getNumberValue());

        new Instance(this, "server", InstanceConfig.builder()
                .count(count)
                .ami("ami-a1b2c3d4")
                .instanceType("t2.micro")
                .tags(
                        new HashMap<String, String>() {
                            {
                                put("Name", "Server ${" + count.getIndex() + "}");
                            }
                        })
                .build());
var servers = new TerraformVariable(this, "servers", new TerraformVariableConfig
{
    Type = "number"
});
var count = TerraformCount.Of(servers.NumberValue);
new Instance(this, "server", new InstanceConfig
{
    Count = count,
    Ami = "ami-a1b2c3d4",
    InstanceType = "t2.micro",
    Tags = new Dictionary<string, string> {
        { "Name", "Server ${" + count.Index + "}" }
    }
});
servers := cdktf.NewTerraformVariable(stack, jsii.String("servers"), &cdktf.TerraformVariableConfig{
	Type: cdktf.VariableType_NUMBER(),
})
count := cdktf.TerraformCount_Of(servers.NumberValue())
instance.NewInstance(stack, jsii.String("server"), &instance.InstanceConfig{
	Count:        count,
	Ami:          jsii.String("ami-a1b2c3d4"),
	InstanceType: jsii.String("t2.micro"),
	Tags: &map[string]*string{
		"Name": jsii.String("Server ${" + *cdktf.Token_AsString(count.Index(), nil) + "}"),
	},
})