sdot257
sdot257

Reputation: 10366

Dynamic data source for fetching AMI using Terraform

So the following data source will fetch the latest AMI with component:web tagged. Let's say I have a handful of components with their own AMI. Instead of creating this same block 5 times, is there a way to make this more dynamic where I can pass in the value of component? I can't seem to think of a unique value I can pass in. Do I need to refactor my code a bit?

data "aws_ami" "web" {
  filter {
    name   = "state"
    values = ["available"]
  }

  filter {
    name   = "tag:component"
    values = ["web"]
  }

  most_recent = true
}

I have a defaults module that acts as a metadata lookup where it fetches and outputs basic things like AMI ID and VPC IDs.

Default Module

# defaults/main.tf

data "aws_ami" "web" {
  filter {
    name   = "state"
    values = ["available"]
  }

  filter {
    name   = "tag:component"
    values = ["web"]
  }

  most_recent = true
}

output "web_ami" {
  value = "${data.aws_ami.web.id}"
}

Main code

# service_name/main.tf

module "defaults" {
  source      = "../defaults"
  region      = "${var.region}"
  environment = "${var.environment}"
}

module "ftpserver" {
  source .    = "../ec2_instance"
  ami_id      = "${module.defaults.web_ami}"
  ...
}

Upvotes: 1

Views: 5402

Answers (1)

ydaetskcoR
ydaetskcoR

Reputation: 56917

I'd move the aws_ami data source into the module and have it look up the AMI directly rather than have it passed in from outside.

So I would change the ec2_instance module to look like:

variable "ami_component" {}

data "aws_ami" "selected" {
  filter {
    name   = "state"
    values = ["available"]
  }

  filter {
    name   = "tag:component"
    values = ["${var.ami_component"]
  }

  most_recent = true
}

resource "aws_instance" "instance" {
  ami           = "${data.aws_ami.selected.id}"
  instance_type = "t2.micro"

  tags {
    Name = "HelloWorld"
  }
}

If you then felt like you needed to be able to override the AMI in the ec2_instance module you could change that to instead be:

variable "ami_component" {}

variable "override_ami" {
  default = ""
}

data "aws_ami" "selected" {
  filter {
    name   = "state"
    values = ["available"]
  }

  filter {
    name   = "tag:component"
    values = ["${var.ami_component"]
  }

  most_recent = true
}

resource "aws_instance" "instance" {
  ami           = "${var.override_ami != "" ? var.override_ami : data.aws_ami.selected.id}"
  instance_type = "t2.micro"

  tags {
    Name = "HelloWorld"
  }
}

This uses a conditional to check if the override_ami variable has been set to something else in which case it will use that, otherwise it will use the ami_component variable to look up the appropriate AMI and use that instead.

This has the benefit of moving the AMI selection logic into the Terraform module making the interface to that module much simpler.

Upvotes: 2

Related Questions