Conditionals
A conditional decides whether to do something, or which of two things to do,
based on a value you already know. You use this constantly in HCL, usually
without calling it a conditional: the count = var.enabled ? 1 : 0 idiom is a
conditional wearing a resource-repetition costume. A general-purpose language
gives you the if statement directly, so you don’t have to route the decision
through a resource count.
Where you have seen this before
Pulumi YAML has no native conditional, so YAML programs work around the
absence with fn::select or by omitting a resource entirely from the file for
a given stack. Terraform HCL’s idiom is the conditional count:
resource "aws_s3_bucket" "backups" {
count = var.environment == "production" ? 1 : 0
bucket = "app-backups"
}
Everything downstream that used to reference aws_s3_bucket.backups now has to
account for it being a list of zero or one items. That’s the tell that HCL is
simulating a conditional with a loop, because it doesn’t have a real one.
The syntax
A general-purpose language has if/else directly, plus a conditional
(ternary) expression for picking between two values. Go doesn’t have a ternary
operator, so an if is the idiom there for both cases.
const instanceSize = environment === "production" ? "m5.large" : "t3.micro";
if (environment === "production") {
// ...
}
instance_size = "m5.large" if environment == "production" else "t3.micro"
if environment == "production":
...
instanceSize := "t3.micro"
if environment == "production" {
instanceSize = "m5.large"
}
var instanceSize = environment == "production" ? "m5.large" : "t3.micro";
if (environment == "production")
{
// ...
}
var instanceSize = environment.equals("production") ? "m5.large" : "t3.micro";
if (environment.equals("production")) {
// ...
}
Pulumi YAML has no if or ternary expression. fn::select picks a value out
of a list by a 0-based integer index, which stands in for a two-way choice
when that index itself comes from config:
config:
isProduction:
type: integer
variables:
instanceSize:
fn::select:
- ${isProduction}
- - t3.micro
- m5.large
There’s no way to skip creating a resource entirely from YAML; that requires a general-purpose language or a component.
HCL has a ternary expression but no if statement, so both branching on a
value and deciding whether to create a resource at all go through the
conditional expression, the second one via count:
locals {
instance_size = var.environment == "production" ? "m5.large" : "t3.micro"
}
resource "aws_s3_bucket" "backups" {
count = var.environment == "production" ? 1 : 0
bucket = "app-backups"
}
In a Pulumi program
Deciding whether to create a resource at all, such as a backup bucket that
only exists in production, is a plain if around the resource declaration.
pulumi.getStack() returns the current stack name, which is the language
equivalent of the stack-scoped variables you’d otherwise branch on in HCL:
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
if (pulumi.getStack() === "production") {
new aws.s3.Bucket("app-backups");
}
import pulumi
import pulumi_aws as aws
if pulumi.get_stack() == "production":
aws.s3.Bucket("app-backups")
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
if ctx.Stack() == "production" {
if _, err := s3.NewBucket(ctx, "app-backups", nil); err != nil {
return err
}
}
return nil
})
}
using Pulumi;
using Pulumi.Aws.S3;
return await Deployment.RunAsync(() =>
{
if (Deployment.Instance.StackName == "production")
{
var backups = new Bucket("app-backups");
}
});
import com.pulumi.Pulumi;
import com.pulumi.aws.s3.Bucket;
public class App {
public static void main(String[] args) {
Pulumi.run(ctx -> {
if (ctx.stackName().equals("production")) {
var backups = new Bucket("app-backups");
}
});
}
}
Pulumi YAML has no way to skip declaring a resource based on a condition; every resource in the file is always created. Reaching for a general-purpose language, or a component someone already wrote in one, is the way to make resource creation itself conditional.
resource "aws_s3_bucket" "backups" {
count = terraform.workspace == "production" ? 1 : 0
bucket = "app-backups"
}
What to watch out for
You can’t branch an if statement on a resource output. An output’s value
isn’t known while your program is running, so a comparison like
if (bucket.arn === "...") doesn’t do what it looks like it does. Branch on
values you actually know when the program runs: stack names, configuration,
and plain inputs. If a decision genuinely depends on a value that only exists
after a resource is created, that decision has to happen inside apply, not
in an if statement; see
working with outputs for how that
works.
Next steps
Continue to loops and iteration
to see how a for loop replaces count and for_each for creating multiple
resources.