arif
arif

Reputation: 669

Terraform - How to create optional data block

I have created a few data blocks for finding the right AMIs. I have 4 data blocks to find 4 AMIs based 4 os. Example,

data "aws_ami" "centos" {
    owners = ["123456789"]
    most_recent = true
    filter {
        name = "name"
        values = ["CentOS*${var.os-version}*x86_64"]
    }
}
data "aws_ami" "suse" {
    owners = ["amazon"]
    most_recent = true
    filter {
        name = "name"
        values = ["suse-sles-${var.os-version}-sp*-v????????-hvm-ssd-x86_64"]
    }
}

I call them like the following ami_id=data.${os_name}.image-id

So what I want is to run only the data block that has been called. If the user chooses "suse" then only the suse data block will run. Not all of them. It's an issue right now because users choose versions based on the os. For example, 16.04 only works for ubuntu not any other so the other data block throws exception like the following,

Error: Your query returned no results. Please change your search criteria and try again.

  on main.tf line 79, in data "aws_ami" "suse":
  79: data "aws_ami" "suse" {

So how can I achieve it?

Upvotes: 1

Views: 6617

Answers (1)

Tyler
Tyler

Reputation: 501

An approach can be a combination of Terraform modules and count. For instance, you could structure your project like this:

Your data lookups for AMIs can be a module in a subfolder. The input to this module would be your os-version.

Inside this module you can have variable validation to validate the input OS is valid. Then, you can construct each of your data blocks. Each data block would have a count value where the lookup would either happen (a value of 1) or not (a value of 0) depending on which os-version was passed in.

I built the following as a simple example.

# Main Terraform project
module "ami" {
    source = "./ami"

    arch = "arm64"
}

output "ami_arn" { value = module.ami.arn }
# AMI module
variable "arch" {
  type = string

  validation {
    condition = (
      var.arch == "x86" || var.arch == "arm64"
    )
    error_message = "Valid architectures are 'x86' or 'arm64'."
  }
}

data "aws_ami" "aws_linux_2_x86" {
  count = var.arch == "x86" ? 1 : 0

  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "image-id"
    values = ["ami-0742b4e673072066f"]
  }
}

data "aws_ami" "aws_linux_2_arm64" {
  count = var.arch == "arm64" ? 1 : 0

  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "image-id"
    values = ["ami-015f1226b535bd02d"]
  }
}

output "arn" { value = var.arch == "x86" ? data.aws_ami.aws_linux_2_x86[0].arn : data.aws_ami.aws_linux_2_arm64[0].arn }

This example does not filter on os-version because I can't easily mock your environment. However, the implementation is the same.

The output of the AMI module is an ARN, or any other valid output you choose which you can then pass on to building your EC2 instance.

You don't necessarily have to use modules in this case and can have the same level of validation and count actions taken in your main code. I chose this approach assuming you had an EC2 module you were coding for.

Upvotes: 6

Related Questions