diff --git a/examples/python/documentation/functions.py b/examples/python/documentation/functions.py index fb6a067636..b7e9ac13ac 100644 --- a/examples/python/documentation/functions.py +++ b/examples/python/documentation/functions.py @@ -2,37 +2,50 @@ # SPDX-License-Identifier: MPL-2.0 from constructs import Construct -from cdktf import TerraformStack, App, TerraformVariable, Token +from cdktf import Op, TerraformStack, TerraformVariable, Token + # DOCS_BLOCK_START:functions-usage-example from cdktf import Fn, TerraformOutput from imports.aws.provider import AwsProvider from imports.aws.data_aws_availability_zones import DataAwsAvailabilityZones # DOCS_BLOCK_END:functions-usage-example +from imports.aws.instance import Instance + class FunctionsStack(TerraformStack): def __init__(self, scope: Construct, id: str): super().__init__(scope, id) - AwsProvider(self, "aws", + AwsProvider(self, "aws", region="us-east-1" ) # DOCS_BLOCK_START:functions-usage-example - zones = DataAwsAvailabilityZones(self, 'zones', - state="available", - ) + state="available", + ) TerraformOutput(self, 'first-zone', value=Fn.element(zones.names, 0) ) - # DOCS_BLOCK_END:functions-usage-example + # DOCS_BLOCK_START:functions-conditional + Instance( + self, + 'web', + ami='ami-2757f631', + count=Token.as_number( + Fn.conditional(Op.eq(Token.as_any('terraform.workspace'), 'prod'), 2, 1) + ), + instance_type='t2.micro', + ) + # DOCS_BLOCK_END:functions-conditional + # INTERNAL NOTE: Due to an JSII bug, we have to pass the variable as a string_value in Python # We can remove it, once https://github.com/aws/jsii/pull/4209 is released # DOCS_BLOCK_START:functions-lookup v = TerraformVariable(self, "complex-object", - type = 'object({users: list(object({name: string}))})', + type='object({users: list(object({name: string}))})', ) TerraformOutput(self, 'users', value=Fn.lookup(v.string_value, "users") @@ -50,4 +63,3 @@ def __init__(self, scope: Construct, id: str): value=Fn.raw_string('${TEMPLATE}') ) # DOCS_BLOCK_END:functions-raw-string - diff --git a/examples/typescript/documentation/functions.ts b/examples/typescript/documentation/functions.ts index b339663077..c56277ccda 100644 --- a/examples/typescript/documentation/functions.ts +++ b/examples/typescript/documentation/functions.ts @@ -5,12 +5,19 @@ import { TerraformStack, TerraformVariable } from "cdktf"; import { Construct } from "constructs"; import { AwsProvider } from "@cdktf/provider-aws/lib/aws-provider"; // DOCS_BLOCK_END:functions +// DOCS_BLOCK_START:functions-conditional +import { Token } from "cdktf"; +import { Instance } from "@cdktf/provider-aws/lib/instance"; +// DOCS_BLOCK_END:functions-conditional +// DOCS_BLOCK_START:functions-conditional,operators,functions,functions-raw +import { Fn } from "cdktf"; +// DOCS_BLOCK_END:functions-conditional,operators,functions,functions-raw // DOCS_BLOCK_START:operators,functions,functions-raw -import { Fn, TerraformOutput } from "cdktf"; +import { TerraformOutput } from "cdktf"; // DOCS_BLOCK_END:operators,functions,functions-raw -// DOCS_BLOCK_START:operators,functions-raw +// DOCS_BLOCK_START:functions-conditional,operators,functions-raw import { Op } from "cdktf"; -// DOCS_BLOCK_END:operators,functions-raw +// DOCS_BLOCK_END:functions-conditional,operators,functions-raw // DOCS_BLOCK_START:functions-raw,functions import { DataAwsAvailabilityZones } from "@cdktf/provider-aws/lib/data-aws-availability-zones"; // DOCS_BLOCK_END:functions-raw,functions @@ -37,6 +44,16 @@ export class FunctionsStack extends TerraformStack { }); // DOCS_BLOCK_END:functions + // DOCS_BLOCK_START:functions-conditional + new Instance(this, "web", { + ami: "ami-2757f631", + count: Token.asNumber( + Fn.conditional(Op.eq(Token.asAny("terraform.workspace"), "prod"), 2, 1), + ), + instanceType: "t2.micro", + }); + // DOCS_BLOCK_END:functions-conditional + // DOCS_BLOCK_START:functions-lookup const v = new TerraformVariable(this, "complex_object", { type: "object({users: list(object({name: string}))})", diff --git a/website/docs/cdktf/concepts/functions.mdx b/website/docs/cdktf/concepts/functions.mdx index 931f9615cc..a5638bd0d0 100644 --- a/website/docs/cdktf/concepts/functions.mdx +++ b/website/docs/cdktf/concepts/functions.mdx @@ -36,7 +36,8 @@ The `element` function gets the first element from the list of Availability Zone import { TerraformStack, TerraformVariable } from "cdktf"; import { Construct } from "constructs"; import { AwsProvider } from "@cdktf/provider-aws/lib/aws-provider"; -import { Fn, TerraformOutput } from "cdktf"; +import { Fn } from "cdktf"; +import { TerraformOutput } from "cdktf"; import { DataAwsAvailabilityZones } from "@cdktf/provider-aws/lib/data-aws-availability-zones"; export class FunctionsStack extends TerraformStack { constructor(scope: Construct, id: string) { @@ -79,15 +80,13 @@ import imports.aws.data_aws_availability_zones.DataAwsAvailabilityZonesConfig; from cdktf import Fn, TerraformOutput from imports.aws.provider import AwsProvider from imports.aws.data_aws_availability_zones import DataAwsAvailabilityZones - zones = DataAwsAvailabilityZones(self, 'zones', - state="available", - ) + state="available", + ) TerraformOutput(self, 'first-zone', value=Fn.element(zones.names, 0) ) - ``` ```csharp @@ -159,6 +158,15 @@ func NewFunctionsStack(scope constructs.Construct, name string) cdktf.TerraformS ## Special functions +### Conditional Expressions + +The ternary [conditional expression](/terraform/language/expressions/conditionals) is supported in CDKTF as a function. Its first argument for the condition or predicate is usually an [operator](/terraform/cdktf/concepts/functions#operators) such as `Op.eq()` to ensure a runtime comparison. Programming language operators like `==` will be evaluated at synthesis time and the result hardcoded into the generated JSON or HCL. Depending on usage, output and inputs may need their [Token](/terraform/cdktf/concepts/tokens) types specified. + + + + + + ### Property Access Helpers To access nested properties from untyped objects or other datasources that return a dynamic datatype, use the Terraform function `lookup` or, for nested access, the function "Fn.lookupNested()" which is a function offered by CDKTF that allows to avoid nesting `Fn.lookup` calls. @@ -169,6 +177,8 @@ To access nested properties from untyped objects or other datasources that retur + + ```ts const v = new TerraformVariable(this, "complex_object", { type: "object({users: list(object({name: string}))})", @@ -181,7 +191,7 @@ new TerraformOutput(this, "first_user_name", { ```python v = TerraformVariable(self, "complex-object", - type = 'object({users: list(object({name: string}))})', + type='object({users: list(object({name: string}))})', ) TerraformOutput(self, 'users', value=Fn.lookup(v.string_value, "users") @@ -230,6 +240,8 @@ cdktf.NewTerraformOutput(stack, jsii.String("first-user-name"), &cdktf.Terraform }) ``` + + ### Raw string helper Another helper function offered by CDKTF is `Fn.rawString` which can be used to escape raw strings that contain characters that CDKTF or Terraform would try to interpret otherwise. @@ -240,6 +252,8 @@ Another helper function offered by CDKTF is `Fn.rawString` which can be used to + + ```ts new TerraformOutput(this, "quotes", { value: Fn.rawString(`"b"`), @@ -287,6 +301,8 @@ cdktf.NewTerraformOutput(stack, jsii.String("template"), &cdktf.TerraformOutputC }) ``` + + ## Operators Use the `Op` object to include operators like `!`, `+`, and `-`. @@ -298,7 +314,8 @@ Use the `Op` object to include operators like `!`, `+`, and `-`. ```ts -import { Fn, TerraformOutput } from "cdktf"; +import { Fn } from "cdktf"; +import { TerraformOutput } from "cdktf"; import { Op } from "cdktf"; const zones = new DataAwsAvailabilityZones(this, "zones", { @@ -360,7 +377,8 @@ It is also possible to use all built-in Terraform functions without using CDKTF' ```ts -import { Fn, TerraformOutput } from "cdktf"; +import { Fn } from "cdktf"; +import { TerraformOutput } from "cdktf"; import { Op } from "cdktf"; import { DataAwsAvailabilityZones } from "@cdktf/provider-aws/lib/data-aws-availability-zones"; diff --git a/website/docs/cdktf/concepts/tokens.mdx b/website/docs/cdktf/concepts/tokens.mdx index 17c773d7ca..004a662def 100644 --- a/website/docs/cdktf/concepts/tokens.mdx +++ b/website/docs/cdktf/concepts/tokens.mdx @@ -21,7 +21,7 @@ You may need to use Tokens for: - [Module outputs](/terraform/cdktf/concepts/modules) for boolean, string, lists, maps, and other complex types. - Resource attributes (such as `id`). - Terraform outputs based on resource attributes. -- Using Terraforms `null` type. +- Using Terraform's `null` type and [terraform.workspace](/terraform/language/state/workspaces#current-workspace-interpolation). ### Example @@ -216,3 +216,51 @@ cdktf.Token_NullValue() ``` + +### Using `terraform.workspace` + +In the code below, the outer `Token.as_number()` avoids: + +> TypeError: type of argument count must be one of (int, float, cdktf.TerraformCount, NoneType); got jsii.\_reference_map.InterfaceDynamicProxy instead + +The inner `Token.as_any()` avoids generating extra quotes `"terraform.workspace"` and extra dollar signs `"$${terraform.workspace}"`. + + + + + +```python +Instance( + self, + 'web', + ami='ami-2757f631', + count=Token.as_number( + Fn.conditional(Op.eq(Token.as_any('terraform.workspace'), 'prod'), 2, 1) + ), + instance_type='t2.micro', +) +``` + +```ts +import { Token } from "cdktf"; +import { Instance } from "@cdktf/provider-aws/lib/instance"; +import { Fn } from "cdktf"; +import { Op } from "cdktf"; +new Instance(this, "web", { + ami: "ami-2757f631", + count: Token.asNumber( + Fn.conditional(Op.eq(Token.asAny("terraform.workspace"), "prod"), 2, 1), + ), + instanceType: "t2.micro", +}); +``` + +```terraform +resource "aws_instance" "web" { + ami = "ami-2757f631" + count = (terraform.workspace == "prod") ? 2 : 1 + instance_type = "t2.micro" +} +``` + +