Scott
Scott

Reputation: 97

How to create a Terraform nested loop for Azure with inner and outer loop

I'm trying to figure out how to use what I think might require a nested loop in Terraform.

I have a module that creates Azure storage accounts from a list of storage accounts.

I would like to extend this module to be able to include a list of storage containers inside the definition.

The variable is a map object for the storage_account that contains a sub map object for containers as shown below:

variables.tf

variable "location" {
  type        = string
  description = "Location for storage account resource"
}

variable "resource_group_name" {
  type        = string
  description = "Resource group the resource will fall under"
}

variable "storage_account" {
  type = map(object({
    name                          = string
    access_tier                   = string
    account_kind                  = string
    account_replication_type      = string
    account_tier                  = string
    containers = optional(map(object({
      name = string
      container_access_type = optional(string, "private")
    })))
    network_rules = list(object({
      default_action             = string
      bypass                     = optional(set(string))
      ip_rules                   = optional(set(string))
      virtual_network_subnet_ids = optional(set(string))
    }))
  }))
}

The module code looks like this:

main.tf

resource "azurerm_storage_account" "storage" {
  for_each = var.storage_account

  name                          = each.value.name
  resource_group_name           = var.resource_group_name
  location                      = var.location
  account_tier                  = each.value.account_tier
  account_replication_type      = each.value.account_replication_type
  account_kind                  = each.value.account_kind
  access_tier                   = each.value.access_tier
  public_network_access_enabled = true
  tags                          = var.tags

}

resource "azurerm_storage_container" "storage"{
  for_each = {
    for key, value in var.storage_account : key => value
  }

      name                 = each.value.name
      storage_account_name = azurerm_storage_account.storage[each.key].name
}

I call/use the module using something like this:

main.tf

module "storage_account" {
  source = "./modules/azurerm_storage_account"

  resource_group_name = "rg-temp"
  location            = "uksouth"

  storage_account = {
    "bigrandomthingy01" = {
      name                          = "bigrandomthingy01"
      account_kind                  = "StorageV2"
      account_tier                  = "Standard"
      account_replication_type      = "LRS"
      access_tier                   = "Hot"
      network_rules                 = []
      containers = {
        "container-01" = {
          name = "randomaa"
          container_access_type = "private"
        },
        "container-02" = {
          name = "randomab"
          container_access_type = "private"
        }
      }
    },
    "bigrandomthingy02" = {
      name                          = "bigrandomthingy02"
      account_kind                  = "StorageV2"
      account_tier                  = "Standard"
      account_replication_type      = "LRS"
      access_tier                   = "Hot"
      network_rules                 = []
      containers = {
        "container-01" = {
          name = "random01"
          container_access_type = "private"
        },
        "container-02" = {
          name = "random02"
          container_access_type = "private"
        }
      }
    }
  }
}

The code loops over each storage account and creates it no problem.

But it then also creates a single storage_container in the account that has the same name as the storage account.

I know my loop code is way off, but I'm not sure what I need to do to loop over the list of containers to create in each storage account?

Is this something that would need me to use flatten? Would this be an 'inner and outer' loop?

I've never really nested a loop before in TF, it's very confusing.

Upvotes: 0

Views: 106

Answers (1)

Venkat V
Venkat V

Reputation: 7725

You can use the code below to create two storage accounts, each containing two containers with specified names.

Here is my directory structure

├── main.tf
├── modules
│   └── azurerm_storage_account
│       ├── main.tf
│       └── variables.tf

main.tf

provider "azurerm" {
  features {}
  subscription_id = "8332bf56-aa7c-xxxxxxx-d7e60e5f09a9"
}

resource "azurerm_resource_group" "example" {
  name     = "storage-rg"
  location = "East US"
}

module "storage_accounts" {
  source                = "./modules/azurerm_storage_account"
  resource_group_name   = azurerm_resource_group.example.name
  location              = azurerm_resource_group.example.location
  storage_accounts = {
    "venaktstoragedemo" = ["venkatcontainer1", "venkatcontainer2"],
    "thejastoragedemo"  = ["thejacontainer1", "thejacontainer2"]
  }
}

modules/azurerm_storage_account/main.tf

resource "azurerm_storage_account" "this" {
  for_each                = var.storage_accounts
  name                    = each.key
  resource_group_name     = var.resource_group_name
  location                = var.location
  account_tier           = "Standard"
  account_replication_type = "LRS"
}

locals {
  storage_containers = flatten([
    for storage_account, containers in var.storage_accounts : [
      for container in containers : {
        name                 = container
        storage_account_name = storage_account
      }
    ]
  ])
}

resource "azurerm_storage_container" "this" {
  for_each               = { for container in local.storage_containers : container.name => container }

  name                   = each.value.name
  storage_account_name   = each.value.storage_account_name
  container_access_type  = "private"
}

modules/storage_with_containers/variables.tf

variable "resource_group_name" {
  description = "The name of the resource group."
  type        = string
}

variable "location" {
  description = "The Azure location where the storage accounts will be created."
  type        = string
}

variable "storage_accounts" {
  description = "A map of storage accounts with their associated container names."
  type        = map(list(string))
}

terrafrom apply

enter image description here

After running the Terraform code, two storage accounts and two containers in each account were created successfully.

enter image description here

Upvotes: 1

Related Questions