Interpolation and Conditionals

Terrform provides a way of interpolating values using ${...}. We can use simple math functions, refer to other variables, or use conditional logic here. For example,

  • Variables: ${var.VARIABLE_NAME} refers to a variable.

  • Resources: ${type.resource-name.attr} refers to a resource declared.

  • Data source: ${data.type.resource-name.attr} refers to any rendered or dynamic data.

Usage of different variable types with interpolation

Name

Syntax

Example

Strings

var.name

${var.SOMETHING}

Maps

var.MAP["key"]

${var.AMIS["us-east-1"]}

${lookup(var.AMIS, var.AWS_REGION)}

Lists

var.LIST, var.LIST[i]

${var.subnets[i]}

${join(",", var.subnets)}

Usage of some other types of items with interpolation

Name

Syntax

Example

Output of a module

module.NAME.output

${module.aws_vpc.vpcid}

Count information

count.FIELD

When using the attribute count = number in a resource, we can use ${count.index}

Path information

path.TYPE

path.cwd(current directory)

path.module(module path)

path.root(root module path)

Meta information

terraform.FIELD

terraform.env shows active workspace

In addition to these, interpolation supports Add (+), Subtract (-), and Divide (/) for float types, and additionally Modulo (%) for integer types.

Conditionals

Interpolations may contain conditionals. The syntax looks like below for conditional statements.

CONDITION ? TRUE-VALUE : FALSE-VALUE

For example,

resource "aws_instance" "myinstance" {
    ...
    count = "${var.env == "prod" ? 2 : 1}"
}

I will provision an EC2 instance in the example below.

First let's start creating a file with the name vars.tf,

variable "AWS_REGION" {
  default = "eu-west-1"
}

variable "PATH_TO_PRIVATE_KEY" {
  default = "mykey"
}

variable "PATH_TO_PUBLIC_KEY" {
  default = "mykey.pub"
}

variable "ENV" {
  default = "prod"
}

Then the provider.tf,

provider "aws" {
  region = var.AWS_REGION
}

Next let's create a file for out VPCs; vpc.tf,

module "vpc-prod" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.59.0"

  name = "vpc-prod"
  cidr = "10.0.0.0/16"

  azs             = ["${var.AWS_REGION}a", "${var.AWS_REGION}b", "${var.AWS_REGION}c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = false
  enable_vpn_gateway = false

  tags = {
    Terraform   = "true"
    Environment = "prod"
  }
}

module "vpc-dev" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.59.0"

  name = "vpc-dev"
  cidr = "10.0.0.0/16"

  azs             = ["${var.AWS_REGION}a", "${var.AWS_REGION}b", "${var.AWS_REGION}c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = false
  enable_vpn_gateway = false

  tags = {
    Terraform   = "true"
    Environment = "dev"
  }
}

Two important things to notice in here are that I use interpolation to name availability zones of the VPC, and that I introduce tag with the name Environment for future use.

Next let's create a file with the name securitygroup.tf,

resource "aws_security_group" "allow-ssh-prod" {
  vpc_id      = module.vpc-prod.vpc_id
  name        = "allow-ssh"
  description = "security group that allows ssh and all egress traffic"

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow-ssh"
  }
}

resource "aws_security_group" "allow-ssh-dev" {
  vpc_id      = module.vpc-dev.vpc_id
  name        = "allow-ssh"
  description = "security group that allows ssh and all egress traffic"

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "allow-ssh"
  }
}

To keep out keys a file with the name key.tf,

resource "aws_key_pair" "mykeypair" {
  key_name   = "mykeypair"
  public_key = file(var.PATH_TO_PUBLIC_KEY)
}

Finally, instance.tf,

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "example" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"

  # the VPC subnet
  subnet_id = var.ENV == "prod" ? module.vpc-prod.public_subnets[0] : module.vpc-dev.public_subnets[0]

  # the security group
  vpc_security_group_ids = [var.ENV == "prod" ? aws_security_group.allow-ssh-prod.id : aws_security_group.allow-ssh-dev.id]

  # the public SSH key
  key_name = aws_key_pair.mykeypair.key_name
}

In here you can notice that I'm assigning subnet and security group ids based on the environment type.

Generate ssh keys,

$ ssh-keygen -f mykey

Initialize the providers,

$ terraform init

Apply the changes,

$ terraform apply

Don't forget to clean up once experiments are done,

$ terraform destroy

Last updated