pm_at_bim
pm_at_bim

Reputation: 1

terraform stacks component reference to module output error: "unsupported attribute"

I am working with a test Terraform Stacks build, creating a resource group and then placing some resources in it. Each resource is created with a separate module, so one for the resource group, another for vnet, subnet, etc. When I reference another component during build, eg the name of the resource group to place a vnet, I'm receiving the error "unsupported attribute - this object does not have an attribute named "resource_group_name"".

# input vars:
location = {
    dev = ["eastus2",]
    stage = ["eastus2",]
    prod = ["centralus","westus"]
}
environment = "dev"
app_name = "app1"

# components.tfstack.hcl:
component "rg" {
  for_each = var.location

  source = "./modules/rg"
  inputs = {
    name      = "${each.value}-${var.environment}-${var.app_name}-rg"
    location  = each.value
    tags      = var.tags
  }

  providers = {
    azurerm = provider.azurerm.this
  }
}

component "vnet" {
  for_each = var.location

  source = "./modules/vnet"
  inputs = {
    name                = "${each.value}-${var.environment}-${var.app_name}-vnet"
    location            = each.value
    resource_group_name = component.rg.resource_group_name
    address_space       = var.vnet_address_space
    tags                = var.tags
  }

  providers = {
    azurerm = provider.azurerm.this
  }
}

# resource group module:
resource "azurerm_resource_group" "rg" {
    name = var.name
    location = var.location

    tags = var.tags
}

output "resource_group_name" {
  value = azurerm_resource_group.rg.name
}

The plan shows the correct resource group name being created and Hashicorp code examples seem to support my syntax. Outputting the "name" property string from the resource group creation module should be referenced with "component.other component name.output string name", am I missing something or doing it wrong?

Upvotes: 0

Views: 352

Answers (2)

Martin Atkins
Martin Atkins

Reputation: 74219

Your component "rg" block includes the for_each argument, which means that component.rg appears in expressions elsewhere as a map of objects whose keys match the keys in var.location. To refer to a specific instance of that component you need to select a specific object from that map using the index syntax, with [ ] brackets.

Since you are using the same for_each in component "vnet" I assume your intention is to have the vnet instances matched to the rg instances where the keys match, in which case you can use each.key to refer to the key of the current instance of component "vnet", and thus find the matching instance of component "rg":

  resource_group_name = component.rg[each.key].resource_group_name

Because Stacks is relatively new the documentation on these features is not yet as comprehensive as for the traditional Terraform modules language, but for for_each with components in particular the language design is very similar to how for_each behaves for module block in the traditional Terraform language, and so the documentation on referring to instances is also largely relevant to components except that you'd use the prefix component. instead of the prefix module..

Upvotes: 0

Vinay B
Vinay B

Reputation: 2261

Terraform stacks component reference to module output error: "unsupported attribute"

Issue seems to be with the way you declaring the name property in resource group module.

You should used in such a way that the output is refered properly as mentioned module.rg[each.key].resource_group_name in your vnet module configuration.

Demo configuration:

variable "location" {
  type = map(list(string))
  default = {
    dev   = ["eastus2"]
    stage = ["eastus2"]
    prod  = ["centralus", "westus"]
  }
}

variable "environment" {
  type    = string
  default = "dev"
}

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

  for_each = { for k, v in var.location : k => v }

  name      = "${each.value[0]}-${var.environment}-${var.app_name}-rg"
  location  = each.value[0]
  tags      = var.tags
}


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

  for_each = { for k, v in var.location : k => v }

  name                = "${each.value[0]}-${var.environment}-${var.app_name}-vnet"
  location            = each.value[0]
  resource_group_name = module.rg[each.key].resource_group_name
  address_space       = ["10.0.0.0/16"]
  tags                = var.tags
}

module/rg:

resource "azurerm_resource_group" "rg" {
  name     = var.name
  location = var.location
  tags     = var.tags
}

output "resource_group_name" {
  value = azurerm_resource_group.rg.name
}

module/vnet:

resource "azurerm_virtual_network" "vnet" {
  name                = var.name
  location            = var.location
  resource_group_name = var.resource_group_name
  address_space       = var.address_space
  tags                = var.tags
}

Deployment:

enter image description here

enter image description here

Refer:

https://developer.hashicorp.com/terraform/language/modules/develop

The for_each Meta-Argument - Configuration Language | Terraform | HashiCorp Developer

Output Values - Configuration Language | Terraform | HashiCorp Developer

Terraform referencing output from another module with for_each - Stack Overflow answered by charles-xu

Upvotes: 0

Related Questions