Issue
I am having difficulties with defining a variable inside the ami=data.aws_ami.$var.ami_name.id
line.
I have tried ami= "${data.aws_ami.(var.ami_name).id}"
but in both cases I am getting the:
79: ami = data.aws_ami.(var.ami_name)).id
│
│ An attribute name is required after a dot.
It only works with the string value data.aws_ami.ubuntu-1804.id
.
My question is how to concat the variable to the data.aws_ami
?
The end goal is to provision based on different OS ec2 instances (Suse,Ubuntu,RHEL) All depending on the variable provided when deploying it.
variable "ami_name" {
default = "ubuntu"
}
data "aws_ami" "amazon" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm*"]
}
}
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
resource "aws_instance" "linux" {
key_name = var.ami_key_pair_name
//ami = var.ami_id
//I want this to be dynamic so I can deploy either Amazon or Ubuntu in all regions.
ami = data.aws_ami.$var.ami_name.id
//ami = data.aws_ami.ubuntu.id # this works
instance_type = "t2.micro"
tags = {
Name = var.instance_name
}
vpc_security_group_ids = [
aws_security_group.allow-ssh-http.id
]
}
I did the search but could not find anything related. I am using Terraform v0.15.4
Solution
The code you show: data.aws_ami.$var.ami_name.id
that is not valid terraform syntax.
Here is a possibility for what you are asking:
provider "aws" { region = "us-east-2" }
locals {
allowed_os = {
"amazon": {owner: "amazon", filter: "amzn2-ami-hvm*"},
"suse": {owner: "amazon", filter: "*suse*"},
"RHEL": {owner: "amazon", filter: "*RHEL*"},
"ubuntu": {owner: "099720109477", filter: "*ubuntu-bionic-18.04-amd64-*"},
}
}
variable "ami_name" {
default = "ubuntu"
validation {
condition = can(regex("amazon|suse|RHEL|ubuntu", var.ami_name))
error_message = "Invalid ami name, allowed_values = [amazon suse RHEL ubuntu]."
}
}
data "aws_ami" "os" {
for_each = local.allowed_os
most_recent = true
owners = [each.value.owner]
filter {
name = "name"
values = [each.value.filter]
}
}
resource "aws_instance" "linux" {
ami = data.aws_ami.os[var.ami_name].id
instance_type = "t2.micro"
# ... todo add arguments here
}
My approach here is to use a for_each
in the aws_ami, that will give us an array, we can consume that later in the aws_instance resource:
data.aws_ami.os["ubuntu"].id
Here we use a hardcoded value to access a specific AMI in your code.data.aws_ami.os[var.ami_name].id
Or this way with the variable that will be provided by user or a config file.
You can add more items to the array to add other operating systems, and same with the filters, you can just change the allowed_os
local variable to suit your needs.
As an extra, I added validation to your ami_name
variable to match the allowed different OS we use in the for_each, that way we prevent any issues right before they can cause errors.
Answered By - Helder Sepulveda Answer Checked By - Timothy Miller (WPSolving Admin)