5
votes

I have created the VPC, subnets and security groups in one Terraform plan (let's call this Plan A). It executed well and the state is stored in the remote S3 backend as well.

Now I have a new Terraform plan (let's call this Plan B) where I need to launch an EC2 instance. For this I need to fetch the VPC, subnet ids from the Plan A Terraform output.

Is there a recommended way to do this?

2

2 Answers

6
votes

There's 2 main ways of passing outputs of things around in Terraform.

The first, and oldest, way is to use the remote state feature to fetch outputs in a different state file.

The second, newer, approach is to use your provider's data sources that expose a read only request to your provider to fetch information about a resource.

With this you would use the aws_vpc and aws_subnet_ids data sources to retrieve information about the relevant subnet IDs.

An example might look something like that given in the aws_subnet_ids docs:

variable "vpc" {}
variable "ami" {}

data "aws_vpc" "selected" {
  tags {
    Name = "${var.vpc}"
  }
}

data "aws_subnet_ids" "private" {
  vpc_id = "${data.aws_vpc.selected.id}"
  tags {
    Tier = "Private"
  }
}

resource "aws_instance" "app" {
  count         = "3"
  ami           = "${var.ami}"
  instance_type = "t2.micro"
  subnet_id     = "${element(data.aws_subnet_ids.private.ids, count.index)}"
}

This would place a single EC2 instance in each of your 3 subnets that are tagged with Tier = Private in the VPC with a Name tag value provided by the vpc variable.

Obviously you can push this further by using the aws_ami data source to also fetch the AMI ID you want to use based on some filtering criteria. This also helps to remove some of the more magic variables you might have in your Terraform code otherwise.

5
votes

If you created your Plan A vpc and subnet with a unique tag (e.g: Name) you can fetch them easily using the following example:

data "aws_vpc" "selected" {
  filter {
    name = "tag:Name"
    values = ["my_vpc_name"]
  }
}

data "aws_subnet" "selected" {
  filter {
    name = "tag:Name"
    values = ["my_subnet_name"]
  }
}

resource "aws_security_group" "sg" {
  vpc_id = data.aws_vpc.selected.id
  ...
}

resource "aws_instance" "instance" {
  vpc_security_group_ids = [ aws_security_group.sg.id ]
  subnet_id              = data.aws_subnet.selected.id
  ...
}

Note: It's easy to modify your old resources to include the Name tag (or any tag)