I am trying to tag the docker swarm instances using terraform I defined variable and locals as variables.tf
variable "instance_count" {
default = "3"
}
variable "instance_type" {
default = "t2.micro"
}
variable "aws_region" {
default = "us-east-1"
}
variable "ami" {
default = "ami-09e67e426f25ce0d7"
}
variable "host_name" {
type = map(number)
default = {
"Manager" = 1
"Worker" = 2
}
}
When i refer to this list's each value to assign it as a tag to ec2 instance like this ec2instance.tf
resource "aws_instance" "swarm_instance" {
count = var.instance_count
ami = var.ami
instance_type = var.instance_type
key_name = aws_key_pair.dockerswarm.key_name
tags = {
Name = "Swarm_Instance-${count.index + 1}"
}
tags = {
Name = "${local.expanded_names}"
}
locals {
expanded_names = {
for name, count in var.host_name : name => [
for i in range(count) : format("%s-%02d", name, i+1)
]
}
}
Terraform complains
local.expanded_names is object with 2 attributes
I tried with ${local.expanded_names.value}
, but then it complained object does not have an attribute named "value"
.
So how to retrieve the value from the list when value attribute is not available in terraform.
The tags should be strings, in your case I would use jsonencode
to get a string out of that object you are building, see my sample code below
variable "host_name" {
type = map(number)
default = {
"Manager" = 1
"Worker" = 2
}
}
locals {
expanded_names = jsonencode({
for name, count in var.host_name : name => [
for i in range(count) : format("%s-%02d", name, i+1)
]
})
}
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "instance" {
ami = "ami-1c761163"
instance_type = "r5.large"
tags = {
Terraformed = "true"
Name = local.expanded_names
}
}
if we run a terraform plan on that, here is what we get:
Terraform will perform the following actions:
# aws_instance.instance will be created
+ resource "aws_instance" "instance" {
+ ami = "ami-1c761163"
...
+ instance_state = (known after apply)
+ instance_type = "r5.large"
...
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = jsonencode(
{
+ Manager = [
+ "Manager-01",
]
+ Worker = [
+ "Worker-01",
+ "Worker-02",
]
}
)
+ "Terraformed" = "true"
}
Or maybe what you meant to do is create an array of names:
Then use that as the instance names... if that is the case your expanded_names should not be an object {}
but an array []
, then we use that instead of your count, see code sample below:
variable "host_name" {
type = map(number)
default = {
"Manager" = 1
"Worker" = 2
}
}
locals {
expanded_names = flatten([
for name, count in var.host_name : [
for i in range(count) : format("%s-%02d", name, i+1)
]
])
}
provider "aws" {
region = "us-east-1"
}
resource "aws_instance" "instance" {
for_each = toset(local.expanded_names)
ami = "ami-1c761163"
instance_type = "r5.large"
tags = {
Terraformed = "true"
Name = each.value
}
}
and a terraform plan on that outputs:
Terraform will perform the following actions:
# aws_instance.instance["Manager-01"] will be created
+ resource "aws_instance" "instance" {
+ ami = "ami-1c761163"
...
+ tags = {
+ "Name" = "Manager-01"
+ "Terraformed" = "true"
}
...
}
# aws_instance.instance["Worker-01"] will be created
+ resource "aws_instance" "instance" {
+ ami = "ami-1c761163"
...
+ tags = {
+ "Name" = "Worker-01"
+ "Terraformed" = "true"
}
...
}
# aws_instance.instance["Worker-02"] will be created
+ resource "aws_instance" "instance" {
+ ami = "ami-1c761163"
...
+ tags = {
+ "Name" = "Worker-02"
+ "Terraformed" = "true"
}
...
}
Plan: 3 to add, 0 to change, 0 to destroy.