简体   繁体   中英

Terraform Outputs: How do I create a (map?) and how do I use the map? Is a map even the right tool?

I am struggling with a few terraform concepts.

I am successfully using the aztfmod/azurecaf provider to name my resourcegroup, but this means I need to get that name as an output for the compan.net.resource_group module, so that I can use that name again when calling the compan.net.key_vault module.

# terraform.tfvars

resource_groups = {
  rg1 = { 
    name     = "resourcegroup1"
    location = "eastus"
  }
  rg2 = { 
    name     = "resourcegroup2"
    location = "eastus"
  }
}
# root main.tf

provider "azurerm" {
  features {}
}

module "companynet" {
  source = "./modules/companynet"

  tenant_id         = var.tenant_id
  environment       = var.environment
  resource_groups   = var.resource_groups
  key_vaults        = var.key_vaults
  storage_accounts  = var.storage_accounts
  app_service_plans = var.app_service_plans
}
# modules/companynet/main.tf

module "resource_group" {
  source          = "../companynet.resource_group"
  environment     = var.environment
  resource_groups = var.resource_groups
}

module "key_vault" {
 source          = "../companynet.key_vault"
 tenant_id       = var.tenant_id
 environment     = var.environment
 resource_groups = "${module.resource_group.resource_groups.companynet}"
 key_vaults      = var.key_vaults
 
}

The module resource_group has the following main.tf :

# modules/companynet.resource_group/main.tf

resource "azurecaf_name" "resource_group" {
  for_each      = var.resource_groups
  name          = each.value.name
  resource_type = "azurerm_resource_group"
  suffixes      = ["${var.environment}", "001"]
}

resource "azurerm_resource_group" "resource_group" {
  for_each = var.resource_groups
  name     = azurecaf_name.resource_group[each.key].result
  location = each.value.location

}

but I don't know how to get the output of that resource_group name.

I have tried a few different things that do not work

# modules/companynet.resource_group/outputs.tf

output "resource_groups" {
 value = azurerm_resource_group.resource_group[*].name
}

value = azurerm_resource_group.resource_group.name

value = azurerm_resource_group.resource_group.compan.net.name

value = azurerm_resource_group.resource_group[compan.net].name

Each of these results in one error or another, all indicating a problem with modules/compan.net.resource_group/outputs.tf

Ideally I would get an object that I can then iterate through in another module. I expect to be able to call something like to get access to those resource group names in other modules such as:

# modules/companynet.key_vault/main.tf

resource "azurerm_key_vault" "key_vault" {
  for_each            = var.key_vaults
  name                = azurecaf_name.key_vault[each.key].result
  location            = var.resource_groups.location

  resource_groups     = "${module.resource_group.resource_groups.[companynet]}"

  sku_name            = "standard"
  tenant_id           = var.tenant_id
}

azurerm_resource_group.resource_group is declared with for_each , and so that expression refers to a map of objects where the keys match the keys of the for_each expression and the values are the corresponding declared resource instances.

In References to Resource Attributes there are various examples of referring to resource attributes in different situations, including the following about resources using for_each :

When a resource has the for_each argument set, the resource itself becomes a map of instance objects rather than a single object, and attributes of instances must be specified by key, or can be accessed using a for expression .

  • aws_instance.example["a"].id returns the id of the "a"-keyed resource.
  • [for value in aws_instance.example: value.id] returns a list of all of the ids of each of the instances.

That second item shows how to use a for expression to produce a list of the ids of aws_instance.example , but it doesn't show exactly how to produce a map and instead expects you to refer to the linked documentation about for expressions to learn about that:

The type of brackets around the for expression decide what type of result it produces.

The above example uses [ and ], which produces a tuple. If you use { and } instead, the result is an object and you must provide two result expressions that are separated by the => symbol:

 {for s in var.list: s => upper(s)}

This expression produces an object whose attributes are the original elements from var.list and their corresponding values are the uppercase versions. For example, the resulting value might be as follows:

 { foo = "FOO" bar = "BAR" baz = "BAZ" }

A for expression alone can only produce either an object value or a tuple value, but Terraform's automatic type conversion rules mean that you can typically use the results in locations where lists, maps, and sets are expected.

This section describes how to produce an object and then notes that you can use the result in a location where a map is expected. In practice it's often possible to use object-typed values and mapped-type values interchangeably in Terraform, because they both have in common that they have elements identified by string keys. The difference is that an object type can have a separate type for each of its attributes, whereas a map must have the same type for all attributes.

Given all of this information, we can produce an object value describing the names for each resource group like this:

output "resource_groups" {
  value = { for k, g in azurerm_resource_group.resource_group : k => g.name }
}

For most purposes it doesn't really matter that this is an object-typed result rather than specifically a map, but since we know that .name is always a string we can infer that all of the attributes of this object have string-typed values, and so it would also be valid to explicitly convert to a map of strings using the tomap function (which is a "location where [...] maps [...] are expected", per the above documentation):

output "resource_groups" {
  value = tomap({
    for k, g in azurerm_resource_group.resource_group : k => g.name
  })
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM