terraformterraform-provider-aws

How to set variables in a module based on a conditional?


I would like to pass a variable that will allow me to specify the list of VPC and subnet settings for an AWS instance. There are fixed VPC and subnet settings that make sense so I just want to allow a user to pick one using a single variable, i.e. use A or B.

For instance, let's say I have two available VPCs, and these are specified in a variables.tf file for a module my_instance:

variable "a_vpc_cidr_block" { default = "105.191.44.0/22" }
variable "a_vpc_id" { default = "id_a"}
variable "a_vpc_name" { default = "vpc_a" }
variable "a_subnet_availability_zone"  { default = "us-east-1a" }
variable "a_subnet_cidr_block" { default = "105.191.25.0/25" }
variable "a_subnet_name" { default = "instance_A" }

variable "b_vpc_cidr_block" { default = "105.191.45.0/22" }
variable "b_vpc_id" { default = "id_b"}
variable "b_vpc_name" { default = "vpc_b" }
variable "b_subnet_availability_zone"  { default = "us-east-1a" }
variable "b_subnet_cidr_block" { default = "105.191.35.0/25" }
variable "b_subnet_name" { default = "instance_B" }

The my_instance module will take a single input variable that an environment will specify, with a value of either 'A' or 'B' (is there a way to limit options for a variable to a list of values such as options=['A', 'B']?), and will be called like so in the terraform.tf for a Terraform configuration with a single instance:

module "my_instance" {
    source = "../../modules/my_instance"
    option = "A"
}

I want to now implement some logic within the module's main file (modules/my_instance/my_instance.tf) where it decides on which of the two collections of VPC and subnet settings it should use from the ones in modules/my_instance/variables.tf. I want to something like this (pseudocode):

if var.option == 'A'
    vpc_cidr_block           = var.a_vpc_cidr_block
    vpc_id                   = var.a_vpc_id
    vpc_name                 = var.a_vpc_name
    subnet_availability_zone = var.a_subnet_availability_zone
    subnet_cidr_block        = var.a_subnet_cidr_block
    subnet_name              = var.a_subnet_name
else if var.option == 'B'
    vpc_cidr_block           = var.b_vpc_cidr_block
    vpc_id                   = var.b_vpc_id
    vpc_name                 = var.b_vpc_name
    subnet_availability_zone = var.b_subnet_availability_zone
    subnet_cidr_block        = var.b_subnet_cidr_block
    subnet_name              = var.b_subnet_name
else
    raise an error

# get a data resource identified by the VPC variables
data "aws_vpc" "instance_vpc" {
  cidr_block = var.vpc_cidr_block

  tags = {
    Name = var.vpc_name
  }
}

# get a data resource identified by the VPC variables
data "aws_subnet" "instance_subnet" {
  vpc_id             = var.vpc_id
  cidr_block         = var.subnet_cidr_block
  availability_zone  = var.subnet_availability_zone

  tags = {
    Name = var.subnet_name
  }
}

# create an AWS key pair resource
resource "aws_key_pair" "instance_aws_key_pair" {
  key_name    = "component_key_${terraform.workspace}"
  public_key  = file("~/.ssh/terraform.pub")
}

# create the AWS EC2 instance
resource "aws_instance" "my_aws_instance" {
  key_name        = aws_key_pair.instance_aws_key_pair.key_name
  ami             = "ami-b12345"
  instance_type   = "t2.micro"
  subnet_id       = data.aws_subnet.instance_subnet.id

  connection {
    type        = "ssh"
    user        = "terraform"
    private_key = file("~/.ssh/terraform")
    host        = self.public_ip
  }

  tags = {
    "Name"      : "my_instance_name"
    "Terraform" : "true"
  }
}

Is this a matter of somehow using a count, something like this:

count = var.option == 'A'? 1 : 0

Is there a way to do this, or is there a better approach? I am very new to Terraform so I may be missing something obvious.


Solution

  • You have a couple of questions here.

    Firstly, you should be able to use the newer, experimental custom validation rules to assert that a value is in a specific list of values.

    Secondly, for determining which set of variables to use, I'd recommend going with a good old map in a local value.

    For example,

    locals {
      vpc_info = {
        "A" = {
          vpc_cidr_block           = var.a_vpc_cidr_block
          vpc_id                   = var.a_vpc_id
          vpc_name                 = var.a_vpc_name
          subnet_availability_zone = var.a_subnet_availability_zone
          subnet_cidr_block        = var.a_subnet_cidr_block
          subnet_name              = var.a_subnet_name
        }
        "B" = {
          vpc_cidr_block           = var.b_vpc_cidr_block
          vpc_id                   = var.b_vpc_id
          vpc_name                 = var.b_vpc_name
          subnet_availability_zone = var.b_subnet_availability_zone
          subnet_cidr_block        = var.b_subnet_cidr_block
          subnet_name              = var.b_subnet_name
        }
      }
    }
    

    Then you should be able to reference a specific field, within the chose option like the following

      local.vpc_info[var.option].vpc_name
    

    Let me know if this hits all your questions.