I have below Terraform code which creates multiple resources using for_each. I wrote the code by referencing many for_each examples but still getting error. Can someone please verify the code and help.
variables.tf
variable "user_ds" {
default = ["a-b", "c-d", "d-e", "f-g"]
}
main.tf
resource "aws_sagemaker_notebook_instance_lifecycle_configuration" "life_cycle" {
for_each = toset(var.users)
name = "lifecycle-${var.users[each.key]}"
on_start = var.on_start
on_create = var.on_create
}
resource "aws_sagemaker_notebook_instance" "sagemaker" {
for_each = toset(var.users)
name = "${var.notebook_prefix}-${var.users[each.key]}-notebook"
role_arn = length(var.role_arn) > 1 ? element(var.role_arn, [each.key]) : ""
instance_type = var.instance_type
kms_key_id = var.kms_key_id
direct_internet_access = "Disabled"
subnet_id = var.subnet_id
security_groups = var.security_groups
lifecycle_config_name = "lifecycle-${var.users[each.key]}"
tags = {
Name = "${var.notebook_prefix}-${var.users[each.key]}-notebook"
aws-glue-dev-endpoint = var.glue_endpoint
}
}
When I run terraform apply, I am getting below error :-
on ../../../modules/sagemaker-new/main.tf line 8, in resource "aws_sagemaker_notebook_instance_lifecycle_configuration" "life_cycle":
8: name = "lifecycle-${var.users[each.key]}"
|----------------
| each.key is "a-b"
| var.users is list of string with 4 elements
The given key does not identify an element in this collection value: a number
is required.
on ../../../modules/sagemaker-new/main.tf line 15, in resource "aws_sagemaker_notebook_instance" "sagemaker":
15: name = "${var.notebook_prefix}-${var.users[each.key]}-notebook"
|----------------
| each.key is "a-b"
| var.users is list of string with 4 elements
The given key does not identify an element in this collection value: a number
is required.
on ../../../modules/sagemaker-new/main.tf line 16, in resource "aws_sagemaker_notebook_instance" "sagemaker":
16: role_arn = length(var.role_arn) > 1 ? element(var.role_arn, [each.key]) : ""
|----------------
| each.key is "a-b"
Invalid value for "index" parameter: number required.
on ../../../modules/sagemaker-new/main.tf line 22, in resource "aws_sagemaker_notebook_instance" "sagemaker":
22: lifecycle_config_name = "lifecycle-${var.users[each.key]}"
|----------------
| each.key is "a-b"
| var.users is list of string with 4 elements
The given key does not identify an element in this collection value: a number
is required.
25: Name = "${var.notebook_prefix}-${var.users[each.key]}-notebook"
|----------------
| each.key is "a-b"
| var.users is list of string with 4 elements
The given key does not identify an element in this collection value: a number
is required.
Any help to the above code will be appreciated.
Thanks in advance
Related
i was trying to create a efs server and mount and facing some error there. Below is the code which i am using -
variable "subnets_nodes" {}
variable "security_group_nodes" {}
resource "aws_efs_mount_target" "efs-mt" {
count = length(var.subnets_nodes)
file_system_id = aws_efs_file_system.efs.id
subnet_id = "${var.subnets_nodes[count.index].id}"
security_groups = ["${var.security_group_nodes.id}"]
}
Error that i am getting is -
Error: Invalid index
on ../modules/ops_bootstrap/modules/fluentd/main.tf line 44, in resource "aws_efs_mount_target" "efs-mt":
44: subnet_id = var.subnets_nodes[count.index].id
|----------------
| count.index is 1
| var.subnets_nodes is object with 3 attributes
The given key does not identify an element in this collection value.
Error: Invalid index
on ../modules/ops_bootstrap/modules/fluentd/main.tf line 44, in resource "aws_efs_mount_target" "efs-mt":
44: subnet_id = var.subnets_nodes[count.index].id
|----------------
| count.index is 0
| var.subnets_nodes is object with 3 attributes
The given key does not identify an element in this collection value.
Error: Invalid index
on ../modules/ops_bootstrap/modules/fluentd/main.tf line 44, in resource "aws_efs_mount_target" "efs-mt":
44: subnet_id = var.subnets_nodes[count.index].id
|----------------
| count.index is 2
| var.subnets_nodes is object with 3 attributes
The given key does not identify an element in this collection value.
any help will be appreciated ? (edited)
Your variable subnet_nodes, is in the format of an object which cannot be accessed by an index. Objects and maps use key-value pairings rather than indices to reference elements. I presume the variable is something like:
subnets_nodes = {
node_1 = {
id = "some-id"
}
node_2 = {
id = "some-id"
}
node_3 = {
id = "some-id"
}
}
So the first id in this example would be accessed by var.subnets_nodes["node_1"].id, not var.subnets_nodes[0].id.
It is recommended to use for_each for this use case, as it will iterate through the objects, where you can access the values using each.value.
This is preferred over the use of count as if the order of values changes when using count, resources will be forced to recreate. This is not an issue with for_each. (An article explaining this)
So you would want to do something like this:
resource "aws_efs_mount_target" "efs-mt" {
for_each = var.subnets_nodes
file_system_id = aws_efs_file_system.efs.id
subnet_id = each.value.id
security_groups = ["${var.security_group_nodes.id}"]
}
i have varible which is a map
variable ltm-datagroups = {
"0" = {
datagroup_name = "abc"
datagroup_type = "ip"
datagroup_addresses = ["10.0.0.0/8", "172.16.1.0/24"]
}
"1" = {
datagroup_name = "def"
datagroup_type = "ip"
datagroup_addresses = ""
}
}
i pass this map to a module, which looks up the value for "datagroup_addresses". from that i want to create multiple entries, based on length of the list.
resource "bigip_ltm_datagroup" "datagroup" {
for_each = var.ltm-datagroups
name = lookup(var.ltm-datagroups[each.key], "datagroup_name")
type = lookup(var.ltm-datagroups[each.key], "datagroup_type")
dynamic "record" {
for_each = lookup(var.ltm-datagroups[each.key], "datagroup_addresses") != "" ? ["${length(lookup(var.ltm-datagroups[each.key], "datagroup_addresses"))}"] : []
content {
name = lookup(var.ltm-datagroups[each.key], "datagroup_addresses")
}
}
}
this is the error i see
Error: Incorrect attribute value type
on modules/ltm-datagroup/main.tf line 8, in resource "bigip_ltm_datagroup" "datagroup":
8: name = lookup(var.ltm-datagroups[each.key], "datagroup_addresses")
|----------------
| each.key is "0"
| var.ltm-datagroups is object with 2 attributes
Inappropriate value for attribute "name": string required.
Error: Incorrect attribute value type
on modules/ltm-datagroup/main.tf line 8, in resource "bigip_ltm_datagroup" "datagroup":
8: name = lookup(var.ltm-datagroups[each.key], "datagroup_addresses")
|----------------
| each.key is "1"
| var.ltm-datagroups is object with 2 attributes
Inappropriate value for attribute "name": string required.
i am stuck on the last part. how to run the dynamic block multiple times? while iterating through the entries in the list?
Not sure I fully understand your desired outcome, but if you want to create record dynamically, then it should be:
dynamic "record" {
for_each = lookup(var.ltm-datagroups[each.key], "datagroup_addresses") != "" ? toset(lookup(var.ltm-datagroups[each.key], "datagroup_addresses")) : []
content {
name = record.value
}
}
I'm trying to reference a value within a list from a map but can't seem to get terraform to recognize that its a string.
Below is my module that I'm working on along with the variable defined.
resource "aws_transfer_user" "aws_transfer_users" {
for_each = var.transfer_users_and_keys
server_id = aws_transfer_server.aws_transfer_service.id
user_name = each.key
role = aws_iam_role.aws_transfer_role.arn
home_directory = format("/%s/%s",var.transfer_users_and_keys[each.value[1]],var.transfer_users_and_keys[each.key])
tags = {
Name = each.key
Project = var.product_name
Terraform = true
}
}
variable "transfer_users_and_keys" {
type = map(list(string))
}
For some reason when I call the value from the list it gives me the following error:
on main.tf line 38, in resource "aws_transfer_user" "aws_transfer_users":
38: home_directory = format("/%s/%s",var.transfer_users_and_keys[each.value[1]],var.tran
sfer_users_and_keys[each.key])
|----------------
| each.value[1] is "bucket-dev-client"
| var.transfer_users_and_keys is map of list of string with 2 elements
The given key does not identify an element in this collection value.
Here is my variable that I'm creating:
transfer_users_and_keys = {
format("key-%s",local.environment) = ["value.pub",tostring(local.sftp_bucket[0])]
format("key-%s02",local.environment) = ["value02.pub",local.sftp_bucket]
}
sftp_bucket = [format("bucket-%s-client",local.environment)]
The goal here is to build out the home_directory based on the 2nd value in the "transfer_users_and_keys" variable (tostring(local.sftp_bucket[0])).
When using for_each, you don't need to keep referencing the variable and indexing it. Change:
home_directory = format("/%s/%s",var.transfer_users_and_keys[each.value[1]],var.transfer_users_and_keys[each.key])
to simply
home_directory = format("/%s/%s", each.value[1], each.key)
I am trying examples from this module
https://registry.terraform.io/modules/terraform-aws-modules/security-group/aws/3.10.0
The main.tf:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "${var.environment}-project-vpc"
cidr = "10.0.0.0/16"
#
# Important!
# https://github.com/terraform-aws-modules/terraform-aws-vpc/issues/403
# Only append or delete from the end of the list
#
azs = ["us-east-2a", "us-east-2b", "us-east-2c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
one_nat_gateway_per_az = false
enable_dns_hostnames = true
enable_dns_support = true
tags = module.project_config.tags
}
module "bastion_sg" {
source = "terraform-aws-modules/security-group/aws"
name = "bastion-service"
description = "Security group for bastion-service"
vpc_id = module.vpc.default_vpc_id
ingress_rules = ["https-443-tcp", "http-80-tcp", "ssh", "all-icmp"]
egress_rules = ["all-all"]
}
resource "aws_instance" "bastion" {
# name = "bastion"
# description = "bastion ssh host to access internals of the infrastructure by SSH"
ami = "ami-08ee2516c7709ea48"
instance_type = "t2.micro"
security_groups = [
module.bastion_sg.this_security_group_id
]
subnet_id = module.vpc.public_subnets[0]
}
and terraform apply fails with
Error: Invalid index
on .terraform/modules/bastion_sg/terraform-aws-security-group-3.10.0/main.tf line 65, in resource "aws_security_group_rule" "ingress_rules":
65: description = var.rules[var.ingress_rules[count.index]][3]
|----------------
| count.index is 2
| var.ingress_rules is list of string with 4 elements
| var.rules is map of list of string with 115 elements
The given key does not identify an element in this collection value.
Error: Invalid index
on .terraform/modules/bastion_sg/terraform-aws-security-group-3.10.0/main.tf line 67, in resource "aws_security_group_rule" "ingress_rules":
67: from_port = var.rules[var.ingress_rules[count.index]][0]
|----------------
| count.index is 2
| var.ingress_rules is list of string with 4 elements
| var.rules is map of list of string with 115 elements
The given key does not identify an element in this collection value.
Error: Invalid index
on .terraform/modules/bastion_sg/terraform-aws-security-group-3.10.0/main.tf line 68, in resource "aws_security_group_rule" "ingress_rules":
68: to_port = var.rules[var.ingress_rules[count.index]][1]
|----------------
| count.index is 2
| var.ingress_rules is list of string with 4 elements
| var.rules is map of list of string with 115 elements
The given key does not identify an element in this collection value.
Error: Invalid index
on .terraform/modules/bastion_sg/terraform-aws-security-group-3.10.0/main.tf line 69, in resource "aws_security_group_rule" "ingress_rules":
69: protocol = var.rules[var.ingress_rules[count.index]][2]
|----------------
| count.index is 2
| var.ingress_rules is list of string with 4 elements
| var.rules is map of list of string with 115 elements
The given key does not identify an element in this collection value.
What am I doing wrong?
Ok, figured this out
module "bastion_sg" {
source = "terraform-aws-modules/security-group/aws"
name = "bastion-service"
description = "Security group for bastion-service"
vpc_id = module.vpc.vpc_id
ingress_cidr_blocks = ["0.0.0.0/0", module.vpc.vpc_cidr_block]
ingress_rules = ["https-443-tcp", "http-80-tcp", "ssh-tcp", "all-icmp"]
egress_rules = ["all-all"]
}
Correct name of the rule is "ssh-tcp", not "ssh"
### variable
variable "vm-subnets" {
type = list(string)
default = ["7.0.1.0/24","7.0.2.0/24","7.0.3.0/24"]
}
### subnet
resource "azurerm_subnet" "task_subnet" {
name = "subnet-${format("%02d",count.index)}"
resource_group_name = azurerm_resource_group.task.name
virtual_network_name = azurerm_virtual_network.task_vnet.name
network_security_group_id = azurerm_network_security_group.task_nsg.id
address_prefix = var.vm-subnets[count.index]
count = length(var.vm-subnets)
}
### NIC
resource "azurerm_network_interface" "vm_nic" {
name = "nic--${format("%02d",count.index)}"
location = var.region
resource_group_name = azurerm_resource_group.task.name
count = var.vm-count
ip_configuration {
name = "${var.resource_prefix}-${format("%02d",count.index)}-ip"
subnet_id = azurerm_subnet.task_subnet.*.id[count.index]
private_ip_address_allocation = "dynamic"
public_ip_address_id = azurerm_public_ip.task_public_ip.*.id[count.index]
}<br>
}
I need to 7 VM into 3 subnet for like subnet-A = 2VMs ,subnet-B=2VMs, subnet-C = 3VMs or randomly
``
ERROR:
Error: Invalid index
on vm-network.tf line 11, in resource "azurerm_network_interface" "vm_nic":
11: subnet_id = azurerm_subnet.task_subnet.*.id[count.index]
|----------------
| azurerm_subnet.task_subnet is tuple with 3 elements
| count.index is 4
The given key does not identify an element in this collection value.
Error: Invalid index
on vm-network.tf line 11, in resource "azurerm_network_interface" "vm_nic":
11: subnet_id = azurerm_subnet.task_subnet.*.id[count.index]
|----------------
| azurerm_subnet.task_subnet is tuple with 3 elements
| count.index is 3
The given key does not identify an element in this collection value.
What modification can be done to resolve it and how can I assign different/random subnet on each vm rather then count loop.
I also try to do it using random_shuffle and set-product function but not get the desired output .. please Help
After 2 days of logical struggle i finally able to find a solution or the questions that I create : USING element function https://www.terraform.io/docs/configuration/functions/element.html
NIC
resource "azurerm_network_interface" "vm_nic" {
name = "nic--${format("%02d",count.index)}"
location = var.region
resource_group_name = azurerm_resource_group.task.name
count = var.vm-count
ip_configuration {
name = "${var.resource_prefix}-${format("%02d",count.index)}-ip"
subnet_id = element(azurerm_subnet.task_subnet.*.id, count.index)
private_ip_address_allocation = "dynamic"
public_ip_address_id = azurerm_public_ip.task_public_ip.*.id[count.index]
}
}
subnet_id = element(azurerm_subnet.task_subnet.*.id, count.index)
using element function ["7.0.1.0/24","7.0.2.0/24","7.0.3.0/24"] at vm count.index = 3 it goes back to subnet index = 0 so that how it works and tested it at vm.count = 5, 7 , 10. ✌🏻