terraform missing resource instance key,issue with for_each - amazon-web-services

resource "aws_sqs_queue" "CloudTrail_SQS"{
for_each = var.sqs_queue_names
name = each.value
visibility_timeout_seconds = var.visibility_timeout_seconds
max_message_size = var.max_message_size
message_retention_seconds = var.message_retention_seconds
delay_seconds = var.delay_seconds
receive_wait_time_seconds = var.receive_wait_time_seconds
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.CloudTrail_SQS_DLQ[each.key].arn
maxReceiveCount = var.max_receive_count
})
tags = var.default_tags
}
resource "aws_sqs_queue" "CloudTrail_SQS_DLQ"{
for_each = var.dead_queue_names
name = each.value
visibility_timeout_seconds = var.visibility_timeout_seconds
max_message_size = var.max_message_size
message_retention_seconds = var.message_retention_seconds
delay_seconds = var.delay_seconds
receive_wait_time_seconds = var.receive_wait_time_seconds
tags = var.default_tags
}
resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy" {
queue_url = aws_sqs_queue.CloudTrail_SQS[each.key].id
My terragrunt plan returns this. it complains about for_each and when i try to fix that i get another errror, but unsure what to do with it:
1.....Error: Missing resource instance key
│
│ on iam.tf line 2, in resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy":
│ 2: queue_url = aws_sqs_queue.CloudTrail_SQS.id
│
│ Because aws_sqs_queue.CloudTrail_SQS has "for_each" set, its attributes
│ must be accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ aws_sqs_queue.CloudTrail_SQS[each.key]
2...Error: Missing resource instance key
│
│ on iam.tf line 14, in resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy":
│ 14: "Resource": "${aws_sqs_queue.CloudTrail_SQS.arn}",
│
│ Because aws_sqs_queue.CloudTrail_SQS has "for_each" set, its attributes
│ must be accessed on specific instances.
│
│ For example, to correlate with indices of a referring resource, use:
│ aws_sqs_queue.CloudTrail_SQS[each.key]
3.........
Error: Reference to "each" in context without for_each
│
│ on iam.tf line 27, in resource "aws_sqs_queue_policy" "CloudTrail_SQS_DLQ":
│ 27: queue_url = aws_sqs_queue.CloudTrail_SQS_DLQ[each.key].id
│
│ The "each" object can be used only in "module" or "resource" blocks, and
│ only when the "for_each" argument is set.

There is no for_each in your Cloudtrail_SQS_Policy. Thus you can't use each.key.
Guess it should be:
resource "aws_sqs_queue_policy" "Cloudtrail_SQS_Policy" {
for_each = var.dead_queue_names
queue_url = aws_sqs_queue.CloudTrail_SQS[each.key].id

Related

Iterate On Module Instances Output When Declared With `for_each`

Description
I'm attempting to iterate on the results of a terraform module and build a set of AWS glue crawlers and IAM roles based on how many source S3 buckets are set in the terraform module
I'm specifically trying to use this line
for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.id): key=>value}
or this line
for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.*.id): key=>value}
or this line
for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.[*].id): key=>value}
but these all result in different errors such as
│ Error: Invalid function argument
│
│ on catalog.tf line 11, in resource "aws_glue_crawler" "bucket_crawlers":
│ 11: for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.id): key=>value}
│ ├────────────────
│ │ while calling setproduct(sets...)
│ │ module.crawler_source_buckets.id is a object
│
│ Invalid value for "sets" parameter: a set or a list is required.
or
│ Error: Invalid template interpolation value
│
│ on catalog.tf line 14, in resource "aws_glue_crawler" "bucket_crawlers":
│ 14: path = "s3://${each.value[1]}"
│ ├────────────────
│ │ each.value[1] is object with 2 attributes
│
│ Cannot include the given value in a string template: string required.
which is making me question if the thing I want to do is even possible. Maybe the answer in this case is that I use the base variable declarations since AWS S3 Ids and ARNs follow a known standard pattern but I would like to know how to iterate on module outputs that are declared with a for_each pattern since that seems very useful.
Code
s3.tf
locals {
bucket-names = [
"${var.env_name}-failed-stripe-payment-reports",
"${var.env_name}-fraud-log-return-responses"]
}
module "crawler_source_buckets" {
source = "../../modules/s3-bucket-v2"
for_each = toset(local.bucket-names)
bucket_name = each.value
# There's more code but I'm choosing to leave it out for clairty
]
}
s3-bucket-v2 output.tf
output "arn" {
description = "The ARN of the main bucket."
value = aws_s3_bucket.main.arn
}
output "id" {
description = "The ID (name) of the main bucket."
value = aws_s3_bucket.main.id
}
# There's an extra 60 lines I'm choosing to leave out for clarity.
catalog.tf
resource "aws_glue_catalog_database" "catalog_databases" {
name = each.value
for_each = toset(local.bucket-names)
}
resource "aws_glue_crawler" "bucket_crawlers" {
database_name = each.value[0]
name = "${each.value[0]}-crawler"
role = aws_iam_role.glue_crawler_role.arn
for_each = {for key, value in setproduct(local.bucket-names, module.crawler_source_buckets.id): key=>value}
s3_target {
path = "s3://${each.value[1]}"
}
schedule = "cron(*/15 * * * ? *)"
}
Since you are using for_each in the module you have to access it using key. For example, module.crawler_source_buckets["key"].id. To get all ids you have to use the following:
values(module.crawler_source_buckets)[*].id
So it should be:
for_each = {for key, value in setproduct(local.bucket-names, values(module.crawler_source_buckets)[*].id): key=>value}

Facing Issue with same variable name "node_config" for two different resource while creating a module

Module giving "Reference to undeclared resource" when I am creating a Google Container cluster and I am using two resources with same dynamic input value "node_config"
This is my main.tf file
resource "google_container_cluster" "primary" {
name = var.name
location = var.location
description = var.description
project = var.project
# We can't create a cluster with no node pool defined, but we want to only use
# separately managed node pools. So we create the smallest possible default
# node pool and immediately delete it.
# default_max_pods_per_node = var.default_max_pods_per_node
enable_tpu = var.enable_tpu
enable_shielded_nodes = var.enable_shielded_nodes
enable_legacy_abac = var.enable_legacy_abac
enable_kubernetes_alpha = var.enable_kubernetes_alpha
enable_intranode_visibility = var.enable_intranode_visibility
node_locations = var.node_locations
resource_labels = var.resource_labels
remove_default_node_pool = var.remove_default_node_pool
initial_node_count = var.initial_node_count
dynamic "node_config" {
for_each = var.node_config
content {
disk_size_gb = node_config.value["disk_size_gb"]
disk_type = node_config.value["disk_type"]
image_type = node_config.value["image_type"]
labels = node_config.value["labels"]
local_ssd_count = node_config.value["local_ssd_count"]
machine_type = node_config.value["machine_type"]
metadata = node_config.value["metadata"]
min_cpu_platform = node_config.value["min_cpu_platform"]
oauth_scopes = node_config.value["oauth_scopes"]
preemptible = node_config.value["preemptible"]
dynamic "shielded_instance_config" {
for_each = node_config.value.shielded_instance_config
content {
enable_integrity_monitoring = shielded_instance_config.value["enable_integrity_monitoring"]
enable_secure_boot = shielded_instance_config.value["enable_secure_boot"]
}
}
tags = node_config.value["tags"]
}
}
}
resource "google_container_node_pool" "primary_preemptible_nodes" {
name = var.nodepool_name
location = var.location
project = var.project
cluster = google_container_cluster.primary.name
node_count = var.nodepool_node_count
node_locations = var.node_locations
dynamic "node_config" {
for_each = var.ndpool_node_config
content {
disk_size_gb = ndpool_node_config.value["disk_size_gb"]
disk_type = ndpool_node_config.value["disk_type"]
preemptible = ndpool_node_config.value["preemptible"]
image_type = ndpool_node_config.value["image_type"]
machine_type = ndpool_node_config.value["machine_type"]
oauth_scopes = ndpool_node_config.value["oauth_scopes"]
}
}
}
This my module definition inside module folder
module "google_container_cluster" {
source = "../"
name = var.name
location = var.location
description = var.description
project = var.project
# We can't create a cluster with no node pool defined, but we want to only use
# separately managed node pools. So we create the smallest possible default
# node pool and immediately delete it.
# default_max_pods_per_node = var.default_max_pods_per_node
enable_tpu = var.enable_tpu
enable_shielded_nodes = var.enable_shielded_nodes
enable_legacy_abac = var.enable_legacy_abac
enable_kubernetes_alpha = var.enable_kubernetes_alpha
enable_intranode_visibility = var.enable_intranode_visibility
node_locations = var.node_locations
resource_labels = var.resource_labels
remove_default_node_pool = var.remove_default_node_pool
initial_node_count = var.initial_node_count
node_config = var.node_config
nodepool_name = var.nodepool_name
nodepool_node_count = var.nodepool_node_count
}
My terraform.tfvars are as follows
name = "tf-gcp-cluster"
location = "us-central1-c"
description = "Cluster Creation using TF"
project = "gcp-terraform-prjt"
#default_max_pods_per_node = ""
enable_tpu = false
enable_shielded_nodes = false
enable_legacy_abac = false
enable_kubernetes_alpha = false
enable_intranode_visibility = false
node_locations = []
resource_labels = {
"test" = "tftestgcp"
}
remove_default_node_pool = true
initial_node_count = 1
node_config = [{
disk_size_gb = "10"
disk_type = "pd-standard"
image_type = "cos_containerd"
labels = {
"test" = "tf-container-cluster"
}
local_ssd_count = "0"
machine_type = "e2-micro"
metadata = {
"key" = "value"
}
min_cpu_platform = ""
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
preemptible = true
shielded_instance_config = [{
enable_integrity_monitoring = false
enable_secure_boot = false
}]
tags = ["value"]
}]
nodepool_name = "tf-nodepool"
nodepool_node_count = 1
ndpool_node_config = [{
disk_size_gb = 10
disk_type = "pd-standard"
image_type = "cos_container"
machine_type = "e2-micro"
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
preemptible = false
}]
I have supplied value for both "node_config" and "ndpool_node_config" but for some reason it is giving me following error when i run terraform plan command
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 57, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 57: disk_size_gb = ndpool_node_config.value["disk_size_gb"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 58, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 58: disk_type = ndpool_node_config.value["disk_type"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 59, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 59: preemptible = ndpool_node_config.value["preemptible"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 60, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 60: image_type = ndpool_node_config.value["image_type"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 61, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 61: machine_type = ndpool_node_config.value["machine_type"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 62, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 62: oauth_scopes = ndpool_node_config.value["oauth_scopes"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
I want the value to be passed down as i have defined them, if i remove it created the node_pool with default values rather than the values defined by me.

Terraform variable error : The given value is not valid

I am trying to create a monitoring alert policy using terraform. But in the plan stage i am getting the below error on the variable. Has anyone faced a similar issue in the past ? I am new to terraform and i can trying to create a iterable resource for monitoring alert policy in gcp.
Error: Invalid value for input variable
│
│ on terraform.tfvars line 149:
│ 149: alert_policies = {
│ 150: "composer_alert" = {
│ 151: combiner = "OR"
│ 152: display_name = "Alert Strategy"
│ 153: enabled = "true"
│ 154: conditions = [
│ 155: {display_name = "Bytes used condition"
│ 156: conditions_threshold = {
│ 157: "1" = {
│ 158: comparison = "COMPARISON_GT"
│ 159: duration = "0s"
│ 160: filter = "resource.type = \"cloud_composer_environment\" AND resource.labels.project_id = \"prj-comp-01\" AND metric.type = \"composer.googleapis.com/environment/database/disk/bytes_used\""
│ 161: threshold_value = 1600000000
│ 162: alignment_period = "300s"
│ 163: cross_series_reducer = "REDUCE_NONE"
│ 164: group_by_fields = ["project_id"]
│ 165: per_series_aligner = "ALIGN_MEAN"
│ 166: trigger_count = 1
│ 167: trigger_percent = 100
│ 168: }
│ 169: }
│ 170: }
│ 171: ]
│ 172: notification_channels = [
│ 173: "projects/prj-test-01/notificationChannels/2276385315451985010"
│ 174: ]
│ 175: }
│ 176: }
│
│ The given value is not valid for variable "alert_policies": a number is
│ required.
╵
╷
│ Error: Incorrect variable type
│
│ on variables.tf line 392:
│ 392: variable "alert_policies" {
│
│ The resolved value of variable "alert_policies" is not appropriate: a
│ number is required.
Variables.tf****
variable "alert_policies" {
type = map(object({
combiner = optional(string)
display_name = optional(string)
enabled = optional(bool)
uptime_checks = optional(map(object({
duration = number
uptime_check_name = string
ssl_expiry_checks = optional(list(object({
days_left = number
})))
})))
conditions = list(object({
display_name = string
conditions_threshold = map(object({
comparison = string
duration = number
filter = string
threshold_value = number
alignment_period = number
cross_series_reducer = string
group_by_fields = list(string)
per_series_aligner = string
trigger_count = number
trigger_percent = number
}))
notification_channels = optional(list(string))
}))
}))
}
╵

Cloud Function Module Terraform

I am comparatively new to terraform and trying to create a working module which can spin up multiple cloud functions at once. The part which is throwing error for me is where i am dynamically calling event trigger. I have written a rough code below.
Can someone please suggest what i am doing wrong?
Main.tf
resource "google_cloudfunctions_function" "event-function" {
for_each = var.cloudfunctions
project = local.test_project
region = lookup(local.regions,"use1")
name = format("clf-%s-%s-use1-%s-%s", var.domain, var.env, var.use_case, each.key)
description = format("clf-%s-%s-use1-%s-%s", var.domain, var.env, var.use_case, each.key)
#source_directory = "${path.module}/${each.value}}
#bucket_force_destroy = var.bucket_force_destroy
entry_point = each.value.entry_point
runtime = each.value.runtime
#vpc_connector = "projects/${var.host_project}/locations/${var.region}/connectors/${var.vpc_connector_prefix}-${var.environment}-test"
dynamic event_trigger {
for_each = [ for i in each.value.event_trigger : lookup(local.event_trigger,i.event_name,i.resource) ]
content {
event_type = event_trigger.value.event_type
resource = event_trigger.value.resource
}
}
Variables.tf
variable "cloudfunctions" {
type = map(object({
runtime = string
event_trigger = list(object({
event_type = string
resource = string
}))
}))
default = {}
}
Locals.tf
42.event_trigger = flatten ([
43. for i,n in var.cloudfunctions :[
44. for event in n.event_trigger :{
45. event_type = event_type
46. resource = resource
}
]
])
}
Error
on locals.tf line 44, in locals:
│ 44: event_type = event_type
│
│ A reference to a resource type must be followed by at least one attribute
│ access, specifying the resource name.
╵
╷
│ Error: Invalid reference
│
│ on locals.tf line 45, in locals:
│ 45: resource = resource
│
│ The "resource" object must be followed by two attribute names: the resource
│ type and the resource name.
Your event_trigger is in n. Thus, your event_trigger should be:
event_trigger = flatten ([
for i,n in var.cloudfunctions :[
for event in n.event_trigger: {
event_type = event.event_type
resource = event.resource
}
]
])

Handling empty value in for_each and assign default value terraform

I am creating aws_workspace, In this terraform I am looping over the variables provided in the main file and assigning the values using for each loop. But the issue that I am facing is that I am trying to pass the username only as a second variable and now I am trying that for-each loop should pick the default value if the value is not given from the main.tf file but its not working. like it should pick the second username and append other values by default with it
main.tf
module "aws_workspace" {
source = "./modules/aws_workspace"
aws_workspace = {
user1 = {
user_name = "john.doe"
root_volume_encryption_enabled = true
user_volume_encryption_enabled = true
volume_encryption_key = "alias/aws/workspaces"
compute_type_name = "VALUE"
user_volume_size_gib = 10
root_volume_size_gib = 80
running_mode = "AUTO_STOP"
running_mode_auto_stop_timeout_in_minutes = 60
},
user2 = {
user_name = "james"
}
}
tags = {
Name = "cloud"
}
bundle_id = data.aws_workspaces_bundle.value_windows_10.id
directory_id = aws_workspaces_directory.example.id
}
variable.tf
variable "aws_workspace" {
default = [
{
root_volume_encryption_enabled = true
user_volume_encryption_enabled = true
volume_encryption_key = "alias/aws/workspaces"
compute_type_name = "VALUE"
user_volume_size_gib = 10
root_volume_size_gib = 80
running_mode = "AUTO_STOP"
running_mode_auto_stop_timeout_in_minutes = 60
}
]
description = "configuration of aws workspaces"
}
variable "tags" {
default = ""
description = "tags of the resources"
}
variable "directory_id" {
default = ""
description = "Id of the directory"
}
variable "bundle_id" {
default = ""
description = "id of the bundle"
}
resource.tf
resource "aws_workspaces_workspace" "example" {
directory_id = var.directory_id
bundle_id = var.bundle_id
for_each = var.aws_workspace
user_name = each.value.user_name
root_volume_encryption_enabled = each.value.root_volume_encryption_enabled
user_volume_encryption_enabled = each.value.user_volume_encryption_enabled
volume_encryption_key = each.value.volume_encryption_key
workspace_properties {
compute_type_name = each.value.compute_type_name
user_volume_size_gib = each.value.user_volume_size_gib
root_volume_size_gib = each.value.root_volume_size_gib
running_mode = each.value.running_mode
running_mode_auto_stop_timeout_in_minutes = each.value.running_mode_auto_stop_timeout_in_minutes
}
tags = var.tags
}
Error:
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 9, in resource "aws_workspaces_workspace" "example":
│ 9: root_volume_encryption_enabled = each.value.root_volume_encryption_enabled
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "root_volume_encryption_enabled".
╵
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 10, in resource "aws_workspaces_workspace" "example":
│ 10: user_volume_encryption_enabled = each.value.user_volume_encryption_enabled
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "user_volume_encryption_enabled".
╵
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 11, in resource "aws_workspaces_workspace" "example":
│ 11: volume_encryption_key = each.value.volume_encryption_key
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "volume_encryption_key".
╵
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 14, in resource "aws_workspaces_workspace" "example":
│ 14: compute_type_name = each.value.compute_type_name
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "compute_type_name".
╵
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 15, in resource "aws_workspaces_workspace" "example":
│ 15: user_volume_size_gib = each.value.user_volume_size_gib
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "user_volume_size_gib".
╵
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 16, in resource "aws_workspaces_workspace" "example":
│ 16: root_volume_size_gib = each.value.root_volume_size_gib
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "root_volume_size_gib".
╵
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 17, in resource "aws_workspaces_workspace" "example":
│ 17: running_mode = each.value.running_mode
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "running_mode".
╵
╷
│ Error: Unsupported attribute
│
│ on modules/aws_workspace/main.tf line 18, in resource "aws_workspaces_workspace" "example":
│ 18: running_mode_auto_stop_timeout_in_minutes = each.value.running_mode_auto_stop_timeout_in_minutes
│ ├────────────────
│ │ each.value is object with 1 attribute "user_name"
│
│ This object does not have an attribute named "running_mode_auto_stop_timeout_in_minutes".
You have to change your design a bit, so that default values are outside of variable. For example:
variable "aws_workspace" {
default = {
user1 = {
user_name = "john.doe"
root_volume_encryption_enabled = true
user_volume_encryption_enabled = true
volume_encryption_key = "alias/aws/workspaces"
compute_type_name = "VALUE"
user_volume_size_gib = 10
root_volume_size_gib = 80
running_mode = "AUTO_STOP"
running_mode_auto_stop_timeout_in_minutes = 60
},
user2 = {
user_name = "james"
}
}
description = "configuration of aws workspaces"
}
locals {
my_defaults = {
root_volume_encryption_enabled = true
user_volume_encryption_enabled = true
volume_encryption_key = "alias/aws/workspaces"
compute_type_name = "VALUE"
user_volume_size_gib = 10
root_volume_size_gib = 80
running_mode = "AUTO_STOP"
running_mode_auto_stop_timeout_in_minutes = 60
}
final_aws_workspace = {for k,v in var.aws_workspace:
k => merge(local.my_defaults, v)
}
}
Then you can use :
for_each = var.final_aws_workspace