Terraform error while fetching value of subnet in oci - terraform

I have this code where I am trying to fetch the id of subnet via subnet name:
The code looks like this :
resource "oci_containerengine_node_pool" "node_pool" {
for_each = var.nodepools
cluster_id = oci_containerengine_cluster.cluster[0].id
compartment_id = var.compartment_id
depends_on = [oci_containerengine_cluster.cluster]
kubernetes_version = var.cluster_kubernetes_version
name = each.value["name"]
node_config_details {
placement_configs {
availability_domain = var.availability_domain
subnet_id = oci_core_subnet.snet-workers[each.value.subnet_name].id
}
size = each.value["size"]
}
node_shape = each.value["node_shape"]
node_shape_config {
#Optional
memory_in_gbs = each.value["memory"]
ocpus = each.value["ocpus"]
}
node_source_details {
image_id = each.value["image_id"]
source_type = "IMAGE"
}
ssh_public_key = file(var.ssh_public_key_path)
}
My subnet code looks like:
resource "oci_core_subnet" "snet-workers" {
cidr_block = lookup(var.subnets["snet-workers"], "subnet_cidr")
compartment_id = var.compartment_id
vcn_id = oci_core_virtual_network.base_vcn.id
display_name = lookup(var.subnets["snet-workers"], "display_name")
dns_label = lookup(var.subnets["snet-workers"], "dns_label")
prohibit_public_ip_on_vnic = true
security_list_ids = [oci_core_security_list.private_worker_nodes.id]
route_table_id = oci_core_route_table.rt-nat.id
}
variables looks like:
variable "subnets" {
description = "List of subnets to create for an environment"
type = map(object({
subnet_cidr = string
display_name = string
dns_label = string
}))
}
my tfvars looks like
nodepools = {
np1 = {
name = "np1"
size = 3
ocpus = 8
memory = 120
image_id = "test"
node_shape = "VM.Standard2.8"
subnet_name = "snet-worker1"
}
np2 = {
name = "np2"
size = 2
ocpus = 8
memory = 120
image_id = "test"
node_shape = "VM.Standard2.8"
subnet_name = "snet-worker2"
}
}
But in terraform plan I am getting error as
Error: Invalid index
│
│ on ../modules/oke/oke.tf line 39, in resource "oci_containerengine_node_pool" "node_pool":
│ 39: subnet_id = oci_core_subnet.snet-workers[each.value.subnet_name].id
│ ├────────────────
│ │ each.value.subnet_name is "snet-worker2"
│ │ oci_core_subnet.snet-workers is object with 22 attributes
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│ on ../modules/oke/oke.tf line 39, in resource "oci_containerengine_node_pool" "node_pool":
│ 39: subnet_id = oci_core_subnet.snet-workers[each.value.subnet_name].id
│ ├────────────────
│ │ each.value.subnet_name is "snet-worker1"
│ │ oci_core_subnet.snet-workers is object with 22 attributes
│
│ The given key does not identify an element in this collection value.
Can someone help

The following:
subnet_id = oci_core_subnet.snet-workers[each.value.subnet_name].id
would only work if you had used for_each while creating oci_core_subnet.snet-workers. Since you are not using for_each, it should be:
subnet_id = oci_core_subnet.snet-workers.id
UPDATE
To keep using original version:
resource "oci_core_subnet" "snet-workers" {
for_each = var.subnets
cidr_block = each.value["subnet_cidr"]
compartment_id = var.compartment_id
vcn_id = oci_core_virtual_network.base_vcn.id
display_name = leach.value[""display_name"]
dns_label = each.value["dns_label"]
prohibit_public_ip_on_vnic = true
security_list_ids = [oci_core_security_list.private_worker_nodes.id]
route_table_id = oci_core_route_table.rt-nat.id
}

You have to define a "oci_core_subnet" for each entry in "subnets" variable. Something like this:
resource "oci_core_subnet" "snet-workers" {
for_each = var.subnets
cidr_block = each.value.subnet_cidr
...
}

Related

How to create conditional vnet based on address space that I give in terraform

Objective: Trying to create azure vnet where address space differ based on environment
Code I am trying:
Variable.tf:
variable "vnet_address_space" {
type = map(any)
default = {
"Dev" = ["xx.xx.0.0/24","xx.xx.0.0/24","xx.xx.0.0/24","xx.xx.0.0/20"]
"Stage" = ["xx.xx.0.0/24","xx.xx.0.0/24","xx.xx.0.0/24","xx.xx.0.0/20"]
"Prod" = ["xx.xx.0.0/24","xx.xx.0.0/24","xx.xx.0.0/24","xx.xx.0.0/20"]
}
}
Main.tf: (updated)
resource "azurerm_virtual_network" "vnet" {
name = var.hub_vnet_name
location = azurerm_resource_group.rg[0].location
resource_group_name = azurerm_resource_group.rg[0].name
for_each = {for k,v in var.vnet_address_space: k=>v if k == "Dev"}
address_space = var.vnet_address_space.Dev
dns_servers = var.dns_servers
tags = {
environment = "${var.env}"
costcentre = "14500"
}
dynamic "ddos_protection_plan" {
for_each = local.if_ddos_enabled
content {
id = azurerm_network_ddos_protection_plan.ddos[0].id
enable = false
}
}
}
However It did not work as intended
Error I get:
on main.tf line 85, in resource "azurerm_virtual_network" "vnet":
│ 85: address_space = [var.vnet_address_space]
│ ├────────────────
│ │ var.vnet_address_space is a map of dynamic, known only after apply
│
│ Inappropriate value for attribute "address_space": element 0: string required.

when i was trying to cretae modules locally and refer the vpc name in creation of ec2 instances and security group i was not able to proceed further

below is the code in ec2, security group module.
data "aws_ami" "ubuntu" {
owners = ["373042721571"]
most_recent = true
filter {
name = "name"
values = ["image-test"]
}
}
# data "template_file" "user_data" {
# template = file("userdata.sh")
# }
resource "aws_instance" "web-1" {
count = 1
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t2.micro"
key_name = var.key_name
subnet_id = var.subnetid
vpc_security_group_ids = var.securitygroupid
associate_public_ip_address = true
# user_data = data.template_file.user_data.rendered
tags = {
Name = "Server-1"
Owner = "Terraform"
}
}
resource "aws_security_group" "allow_all" {
name = var.sg_name
description = "allowing all traffic to the servers in piblic "
vpc_id = var.vpcid
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
tags = {
Name = "allow_all_trafic"
}
}
module "vpc" {
source = "./module/vpc"
vpc_cidr = var.vpc_cidr
vpc_name = var.vpc_name
IGW_name = var.IGW_name
routing_table_public_name = var.routing_table_public_name
}
module "securitygroup" {
source = "./module/securitygroup"
sg_name = var.sg_name
vpcid = module.vpc.vpc_id
}
module "ec2" {
source = "./module/ec2"
key_name = var.key_name
securitygroupid = module.securitygroup.aws_security_group.allow_all.id
subnetid = module.vpcmodule.public[0]
}
this is the terrafrom modules i created locally when i refer to vpc-id and subnet ids
i was getting as
│ Error: Unsupported attribute
│
│ on output.tf line 3, in output "vpc_id":
│ 3: value = module.vpc.vpc_id
│ ├────────────────
│ │ module.vpc is a object, known only after apply
│
│ This object does not have an attribute named "vpc_id".

How to loop correctly in terraform for_each?

Objective: Loop through azure subnets via terraform.
Code That I use:
Main.tf:
resource "azurerm_network_security_group" "nsg" {
name = "nsg-vnet-hub-${var.env}-indoundDNS"
location = azurerm_resource_group.rg[0].location
resource_group_name = azurerm_resource_group.rg[0].name
tags = {
environment = "${var.env}"
costcentre = "12345"
}
}
resource "azurerm_monitor_diagnostic_setting" "nsg" {
for_each = var.subnets
name = lower("${each.key}-diag")
target_resource_id = azurerm_network_security_group.nsg[each.key].id
storage_account_id = azurerm_storage_account.storeacc.id
log_analytics_workspace_id = azurerm_log_analytics_workspace.logws.id
dynamic "log" {
for_each = var.nsg_diag_logs
content {
category = log.value
enabled = true
retention_policy {
enabled = false
}
}
}
}
My root module variable.tf :
variable "subnets" {
type = map(object({
name = string
}))
default = {
"s1" = { name = "dns_snet"},
"s2" = { name = "common_snet"},
"s3" = { name = "gw_snet"},
"s4" = { name = "data_snet"}
}
}
Problem I am facing:
Error:
network_security_group_id = azurerm_network_security_group.nsg[each.key].id
│ ├────────────────
│ │ azurerm_network_security_group.nsg is object with 7 attributes
│ │ each.key is "s3"
│
│ The given key does not identify an element in this collection value
Just updated this post, now I get error as above. I am referring to below documentation
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/network_security_group
You have only a single instance of azurerm_network_security_group.nsg. Thus there is nothing to iterate over. To fix your error, it should be:
target_resource_id = azurerm_network_security_group.nsg.id

Getting error while using Terraform for_each for App Registration

I am trying to do app registration and have few app roles that i would like to assign.
My code is given below
resource "random_uuid" "prod" {}
resource "azuread_application" "app_prod" {
display_name = format("app-%s-%s", var.project.name, var.project.environment.name)
owners = [data.azuread_client_config.default.object_id]
identifier_uris = [format("https://contoso.onmicrosoft.com/%s-%s", var.project.name, var.project.environment.name)]
api {
oauth2_permission_scope {
for_each = toset(local.oauth2_permissions)
admin_consent_description = each.value.admin_consent_description
admin_consent_display_name = each.value.admin_consent_display_name
enabled = true
id = random_uuid.prod.result
type = each.value.type
value = each.key
}
}
app_role {
for_each = toset(local.app_roles)
allowed_member_types = each.value.allowed_member_types
description = each.value.description
display_name = each.value.display_name
enabled = true
id = random_uuid.prod.result
value = each.key
}
web {
logout_url = format("https://app-%s-%s", var.project.name, var.project.environment.name)
redirect_uris = []
implicit_grant {
access_token_issuance_enabled = true
id_token_issuance_enabled = true
}
}
required_resource_access {
resource_app_id = data.azuread_application_published_app_ids.well_known.result.MicrosoftGraph
resource_access {
id = data.azuread_service_principal.msgraph.app_role_ids["User.Read.All"]
type = "Role"
}
}
}
locals {
app_roles = {
application-administrator = {
display_name = "Application administrator"
description = "Application administrators have the ability to administer the application."
allowed_member_types = ["User", "Application"]
}
BusinessAdmin = {
display_name = "BusinessAdmin"
description = "Business Administrator"
allowed_member_types = ["User"]
}
mulesoft-integration = {
display_name = "Mulesoft Integration"
description = "Allows MuleSoft Integration to talk to the APIs."
allowed_member_types = ["Application"]
}
}
oauth2_permissions = {
read-and-write = {
user_consent_description = "read-and-write"
admin_consent_display_name = "Read and write data"
admin_consent_description = "Allows the app to read and write data"
user_consent_display_name = "Allows the app to read and write data"
type = "User"
}
}
}
data "azuread_application_published_app_ids" "well_known" {}
data "azuread_service_principal" "msgraph" {
application_id = data.azuread_application_published_app_ids.well_known.result.MicrosoftGraph
}
The error that i get while doing terraform apply is :
Error: each.value cannot be used in this context
│
│ on resources.appreg.tf line 24, in resource "azuread_application" "app_prodstats":
│ 24: description = each.value.description
│
│ A reference to "each.value" has been used in a context in which it
│ unavailable, such as when the configuration no longer contains the value in
│ its "for_each" expression. Remove this reference to each.value in your
│ configuration to work around this error.
╵
╷
│ Error: each.value cannot be used in this context
│
│ on resources.appreg.tf line 25, in resource "azuread_application" "app_prodstats":
│ 25: display_name = each.value.display_name
│
│ A reference to "each.value" has been used in a context in which it
│ unavailable, such as when the configuration no longer contains the value in
│ its "for_each" expression. Remove this reference to each.value in your
│ configuration to work around this error.
╵
╷
│ Error: Reference to "each" in context without for_each
│
│ on resources.appreg.tf line 28, in resource "azuread_application" "app_prodstats":
│ 28: value = each.key
│
│ The "each" object can be used only in "module" or "resource" blocks, and
│ only when the "for_each" argument is set.
╵
You need content block if you are using dynamic blocks:
dynamic "app_role" {
for_each = toset(local.app_roles)
content {
allowed_member_types = app_role.value.allowed_member_types
description = app_role.value.description
display_name = app_role.value.display_name
enabled = true
id = random_uuid.prod.result
value = app_role.key
}
}
You have to make similar changes as above to other parts of your code where you get that error.

How to set the route_table_id

main.tf
private_nat_cidrs = {
test-prod-ec2-1 = {
subnet = "10.1.0.0/23"
name = "test-prod-ec2-1"
az = "ap-northeast-1a"
}
test-prod-ec2-2 = {
subnet = "10.1.2.0/23"
name = "test-prod-ec2-2"
az = "ap-northeast-1c"
}
test-prod-ec2-3 = {
subnet = "10.1.4.0/23"
name = "test-prod-ec2-3"
az = "ap-northeast-1d"
}
}
subnet.tf
/**
* private subnet(NAT)
*/
resource "aws_subnet" "nat" {
for_each = var.private_nat_cidrs
vpc_id = aws_vpc.test.id
availability_zone = lookup(each.value, "az")
cidr_block = lookup(each.value, "subnet")
map_public_ip_on_launch = true
tags = merge(
local.tags,
{
Name = format("%s_%s", var.env_prefix, lookup(each.value, "name"))
}
)
lifecycle {
prevent_destroy = false
}
}
nat.tf
resource "aws_nat_gateway" "private" {
for_each = var.public_subnet_cidrs
allocation_id = aws_eip.nat_gateway.id
subnet_id = aws_subnet.public[each.key].id
tags = merge(
local.tags,
{
Name = format("%s_%s_%s", var.env_prefix, var.env_name, "nat-gateway")
}
)
lifecycle {
prevent_destroy = false
}
}
route_table.tf
resource "aws_route_table" "private" {
for_each = aws_nat_gateway.private
vpc_id = aws_vpc.dandori.id
tags = merge(
local.tags,
{
Name = format("%s_%s", var.env_prefix, var.env_name)
}
)
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = each.value["id"]
}
lifecycle {
prevent_destroy = false
}
}
resource "aws_route_table_association" "private" {
for_each = aws_subnet.nat
subnet_id = each.value["id"]
route_table_id = aws_route_table.private[each.key].id
lifecycle {
prevent_destroy = false
}
}
【Error】
╷
│ Error: Invalid index
│
│ on ../modules/aws/vpc/route_table.tf line 69, in resource "aws_route_table_association" "private":
│ 69: route_table_id = aws_route_table.private[each.key].id
│ ├────────────────
│ │ aws_route_table.private is object with 1 attribute "test-prod-nat"
│ │ each.key is "test-prod-ec2-1"
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│ on ../modules/aws/vpc/route_table.tf line 69, in resource "aws_route_table_association" "private":
│ 69: route_table_id = aws_route_table.private[each.key].id
│ ├────────────────
│ │ aws_route_table.private is object with 1 attribute "test-prod-nat"
│ │ each.key is "test-prod-ec2-2"
│
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│ on ../modules/aws/vpc/route_table.tf line 69, in resource "aws_route_table_association" "private":
│ 69: route_table_id = aws_route_table.private[each.key].id
│ ├────────────────
│ │ aws_route_table.private is object with 1 attribute "test-prod-nat"
│ │ each.key is "test-prod-ec2-3"
│
│ The given key does not identify an element in this collection value.
I want to set the route_table_id to aws_route_table.private.id, but I don't know how to set it.
I've set the aws_route_table.private.id, but I can't set the aws_route_table.private.id directly because I'm looping through for_each.
I've tried everything, but I can't solve it.
Please give me some advice.

Resources