Issues using for_each for my creating names of my buckets

Issues using for_each to create names

Could anyone advise the how or why it does the following:

You have two of the same resources named different

Inside the module

resource “aws_s3_bucket” “example1” {
bucket = var.example1 # Replace with your desired bucket name
}
resource “aws_s3_bucket” “example2” {
bucket = var.example2
}
variable “example1” {
type = string
description = “S3 bucket name”
default = “example1”
}
variable “example2” {
type = string
description = “naming for s3 buckets”
}

Inside the main

module “example1” {
source = “…/…/modules/s3”
example1 = “example1”
environment = local.environment
}
module “example2” {
source = “…/…/modules/s3”
for_each = toset([“test1”, “test2”, “test3”])
example2 = “${each.key}_bucket”
environment = local.environment
}

I believe it is cause inside the main.tf it does associate with the resource but just the folder itself but unsure

Was using this documentation from terraform referencing the child module: with an additional resource in my code block The for_each Meta-Argument - Configuration Language | Terraform | HashiCorp Developer

Hi @MaxP,

I don’t think I fully understand your question, but I do notice a problem with your configuration even though I’m not sure if it relates to what you are asking:

In all instances across both of your module calls you have the example1 variable set to "example1". You have four instances of this module in total, so this is telling Terraform that four different S3 buckets should exist and should all be named "example1".

Amazon S3 requires bucket names to be unique, so the desired state described by this configuration is impossible to reach.

To achieve a working configuration you will need to set the example1 variable differently for each instance of the module.

Hi @apparentlymart ,

Should have made it a bit less confusing and hopefully this clears things up

Goal - Lessen the amount of file locations where I had to put code to name a bucket.
Currently to create multi resources. I am doing this -

  • create a resource block for each resource
  • then variable for each name
  • and in the module block add each variable

What I was hoping to do is

  • create a “static” resource block inside my modules folder. This resource block will be referenced multiple times to create buckets using the for_each function to set their name. While having a separate customizable resource blocks in the same module folder to be created individually

Original code gave me created 10 resources instead of 6. Trying to change it up put me in a rabbit hole I couldnt get out of

chrome_3Nz8faS1YS
chrome_tz6rYBl4Ee

resource “aws_s3_bucket” “testing” {
bucket = var.bucket_name # Replace with your desired bucket name
}
resource “aws_s3_bucket” “testing2” {
bucket = var.bucket_name2 # Replace with your desired bucket name
}
resource “aws_s3_bucket” “s3-acl” {
bucket = “multi-bucket-test”
}

variable “bucket_name” {
type = string
description = “S3 bucket name”
default = “test”
}
variable “bucket_name2” {
type = string
description = “second S3 bucket name”
default = “test2”
}

module “s3” {
source = “…/…/modules/s3”
bucket_name = “test”
bucket_name2 = “test2”
environment = local.environment
}
module “s3-acl” {
source = “…/…/modules/s3”
for_each = toset([“test1”, “test2”, “test30”, “test4”])
environment = local.environment
}

Edited multiple times to try to make it understandable

Hi @MaxP,

For your module to work as a multi-instance module you will need to make sure all of the buckets declared in it can have variable bucket names.

The example you shared most recently still declares a bucket with the hard-coded name "multi-bucket-test", and so there can only be one instance of this module due to the requirement for the names to be unique. If you change that third declaration to also use an input variable then it should work, as long as each instance of the module chooses a different name for the third bucket.

Alternatively, if what you are trying to describe is a variable number of testing1 and a variable number of testing2 instances, but only exactly one “s3-acl”, then it might be more appropriate to change your module so that it takes set(string) variables specifying the multiple names and then use for_each in the resource blocks inside the module instead. Then you will have only one instance of the module but a dynamic number of instances of the first and second S3 bucket resources.

Hi @apparentlymart ,

Thank you for the insight and advice. Sorry for the late reply, was doing some testing.

Removed bucket name inside the resource block. And it is creating multiple buckets now.

Issue I am running into now is that my two resource blocks are getting created over and over again.

When I try to use a set(string) I get this error.

│ Error: Incorrect attribute value type

│ on …..\modules\s3basic\main.tf line 89, in resource “aws_s3_bucket” “fill_in_name”:
│ 89: bucket = var.bucket_name
│ ├────────────────
│ │ var.bucket_name is a set of string

│ Inappropriate value for attribute “bucket”: string required.

resource “aws_s3_bucket” “fill_in_name” {
bucket = var.bucket_name
}
resource “aws_s3_bucket” “fill_in_name2” {
}
variable bucket_name {
type = set(string)
default = [“bucket1”, “bucket2”, “bucket3”]
}
module s3 {
source = “…/…/modules/s3basic”
for_each = toset([“bucket1”, “bucket2”, “bucket3”])
}

Creating a map(string) and tagging it makes 10 buckets. It is creating 5 buckets for each resource blocks.

variable “bucket_name” {
type = map(string)
default = {
1 = “bucket1”
2 = “bucket2”
3 = “bucket3”
4 = “bucket4”
5 = “bucket5”
}
}

Doesnt let me put a bool true or false. Get an argument is not expected here. At my wits end.

Don’t think it is possible to create multiple resource blocks in a module and have the module only link to one resource block there