> For the complete documentation index, see [llms.txt](https://isurus.gitbook.io/infrastructure-and-platform-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://isurus.gitbook.io/infrastructure-and-platform-notes/terraform-23/terraform-basics/05-interpolation-and-conditionals.md).

# 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
```
