Search code examples
terraformterraform-provider-gcp

Terraform : Is it possible to interpolate or loop through ressources from a list within the output block?


I am trying to output gcp project information by doing something like this :

output "projects" {
  value = tomap({
    for project_name in ["project_1", "project_2", "project_3"] :
    project_name => tomap({
      id     = google_project."${project_name}".id
      number = google_project."${project_name}".number
    })
  })
  description = "Projects"
}

Or like this :

output "projects" {
  value = tomap({
    for_each = toset([google_project.project_1,google_project.project_2])
    id       = each.key.id
    number   = each.key.number

  })
  description = "Projects"
}

Is it at all possible to use resource names this way? Do I have to specify every resource by duplicating code?

E.g.

output "projects" {
  value = tomap({
    project_1 = tomap({
      id     = google_project.project_1.id
      number = google_project.project_1.number
    })
    project_2 = tomap({
      id     = google_project.project_2.id
      number = google_project.project_2.number
    })
    project_3 = tomap({
      id     = google_project.project_3 .id
      number = google_project.pproject_3 .number
    })
  })
  description = "Projects"
}

EDIT : declared resources.

In main.tf projects 1 to 3 are declared the same way.

resource "google_project" "project_3" {
  name                = var.projects.project_3.name
  project_id          = var.projects.project_3.id
  folder_id           = google_folder.parent.name
  billing_account     = data.google_billing_account.acct.id
  auto_create_network = false
}

in variables.tf

variable "projects" {
  type = map(object({
    name = string
    id   = string
  }))
}

in variables.tfvars

projects = {
  project_1= {
    name = "project_1"
    id   = "project_1-12345"
  }  
  project_2= {
    name = "project_2"
    id   = "project_2-12345"
  }
  project_3= {
    name = "project_2"
    id   = "project_2-12345"
  }
}

Solution

  • I misunderstood your question originally. I see now that you want to reference a resource by a variable name. No you cannot do that. But your setup here doesn't really make sense, and seems more complex than it needs to be.

    Consider if these options would improve your setup.

    locals {
      projects = { # This is equivalent to your input.
        project_1 = {
          name = "project_1"
          id   = "project_1-12345"
        }
        project_2 = {
          name = "project_2"
          id   = "project_2-12345"
        }
        project_3 = {
          name = "project_3"
          id   = "project_3-12345"
        }
      }
    }
    
    resource "google_project" "this" {
      for_each = local.projects
    
      name                = each.key # or each.value.name / don't really need name
      project_id          = each.value.id
      folder_id           = google_folder.parent.name
      billing_account     = data.google_billing_account.acct.id
      auto_create_network = false
    }
    
    output "projects_from_input" {
      description = "You can of course, just use the input."
      value       = local.projects
    }
    
    output "projects_explicit_values" {
      description = "Alternatively, if you need a subset of resource values."
      value = { for k, v in google_project.this : k => {
        name = v.name
        id   = v.project_id
      } }
    }
    
    output "complete_resources" {
      description = "But you can just output the complete resource."
      value       = google_project.this
    }