Reputation: 623
I am creating a module to spin up a basic web server.
I am trying to get it so that if the user does not specify an AMI then the ubuntu image for that region is used.
I have a data
block to get the AMI ID of the ubuntu 16.04 image for that region but I cannot set this as the default for a variable as interpolation does not work.
My module is as follows:-
main.tf
resource "aws_instance" "web" {
ami = "${var.aws_ami}"
instance_type = "${var.instance_type}"
security_groups = ["${aws_security_groups.web.id}"]
tags {
Name = "WEB_SERVER"
}
}
resource "aws_security_groups" "web" {
name = "WEB_SERVER-HTTP-HTTPS-SG"
ingress {
from_port = "${var.http_port}"
to_port = "${var.http_port}"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = "${var.https_port}"
to_port = "${var.https_port}"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
variables.tf
variable "instance_type" {
description = "The instance size to deploy. Defaults to t2.micro"
default = "t2.micro"
}
variable "http_port" {
description = "The port to use for HTTP traffic. Defaults to 80"
default = "80"
}
variable "https_port" {
description = "The port to use for HTTPS traffic. Defaults to 443"
default = "443"
}
data "aws_ami" "ubuntu" {
filter {
name = "state"
values = ["available"]
}
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"]
}
locals {
default_ami = "${data.aws_ami.ubuntu.id}"
}
variable aws_ami {
description = "The AMI used to launch the instance. Defaults to Ubuntu 16.04"
default = "${local.default_ami}"
}
Upvotes: 8
Views: 21302
Reputation: 2609
A similar solution to the other answers, but using the coalesce function:
variable "user_specified_ami" {
default = ""
}
resource "aws_instance" "web" {
ami = coalesce(var.user_specified_ami, data.aws_ami.ubuntu.id)
}
Upvotes: 7
Reputation: 1383
KJH's answer works great, but it felt a bit messy to me to have that logic inline, so I made an abstraction using null_data_source. Here's what that would look like:
variable "ami" {
default = ""
}
data "null_data_source" "data_variables" {
inputs = {
ami = "${var.ami == "" ? data.aws_ami.ubuntu.id : var.ami}"
}
}
resource "aws_instance" "web" {
ami = "${data.null_data_source.data_variables.outputs["ami"]}"
# ... other params omitted ....
}
Upvotes: 2
Reputation: 2430
Try using a ternary operator interpolation:
variable "user_specified_ami" {
default = "ami-12345678"
}
resource "aws_instance" "web" {
ami = "${var.user_specified_ami == "" ? data.aws_ami.ubuntu.id : var.user_specified_ami}"
# ... other params omitted ....
}
Set user_specified_ami
's default to something to use that AMI. Set it to blank to use the AMI ID Terraform gets from the AWS provider.
i.e. if user_specified_ami
is anything other blank (""), then it will be chosen for the AMI, else the AMI Terraform gets the one from AWS.
BTW, maybe you want to use the most_recent = true
param in the data "aws_ami"
resource?
Upvotes: 7