Search code examples
terraformterraform-provider-gcp

Terraform dynamic block for GCP firestore


I'm trying to create a module for GCP firestore that creates a single database which can create multiple indexes with multiple fields but am having some trouble.

I've tried with for_each but I don't know how to do it exactly. I need the collection (from the index) name and the fields to be dynamic together.

This is my code so far:

main.tf (module)

resource "google_firestore_database" "database" {
 project                           = var.project_id
 name                              = var.firestore_name
 location_id                       = var.firestore_location_id
 type                              = var.firestore_type
 concurrency_mode                  = var.firestore_concurrency_mode
 app_engine_integration_mode       = var.firestore_app_engine_integration_mode
 point_in_time_recovery_enablement = var.firestore_point_in_time_recovery_enablement
 delete_protection_state           = var.firestore_delete_protection_state
 # deletion_policy                   = var.firestore_deletion_policy
}

resource "google_firestore_index" "my-index" {
 project    = var.project_id
 database   = var.firestore_name
 collection = var.firestore_collection

 fields {
   field_path = var.firestore_field_path
   order      = var.firestore_order
 }
 fields {
   field_path = var.firestore_field_path
   order      = var.firestore_order
 }
}

I have tried this:

resource "google_firestore_index" "catalog-dev" {
 project    = google_firestore_database.database.project
 database   = google_firestore_database.database.name
 collection = var.firestore_collection

 dynamic "fields" {
   for_each = var.indexfieldvars
   content {
     field_path = fields.value.field_path
     order      = fields.value.order
   }
 }
}
variable "indexfieldvars" {
   type = list(object({
       field_path = string
       order = string
   }))
}

variable "firestore_collection" {
   type = string
}

But I need the collection to be related to the specific fields.

I've read on nested dynamic blocks, but I'm not sure if that works for my case.


Solution

  • Solution 1

    If collections are known beforehand you can add a condition in the for_each statement and make as many dynamic blocks as collections that you know of:

    resource "google_firestore_index" "catalog-dev" {
      project    = google_firestore_database.database.project
      database   = google_firestore_database.database.name
      collection = var.firestore_collection
    
    
      dynamic "fields" {
        for_each = var.firestore_collection == "collection1" ? var.indexfieldvars : []
        content {
          field_path = fields.value.field_path
          order      = fields.value.order
        }
      }
    
      dynamic "fields" {
        for_each = var.firestore_collection == "collection2" ? var.indexfieldvars : []
        content {
          field_path = fields.value.field_path
          order      = fields.value.order
        }
      }
      
      # More dynamic blocks if needed
    
    }
    

    Solution 2

    If collections are not known beforehand, as @Marko E suggests, create a variable that will map collections with fields. Then use for_each at a resource level and inside a dynamic block.

    Variable:

    variable "firestore_collections_with_fields" {
      type = map(object({
        fields = list(object({
          field_path = string
          order      = string
        }))
      }))
      default = {
        collection1 = {
          fields = [
            {
              field_path = "field_path0",
              order      = "order"
            },
            {
              field_path = "field_path1",
              order      = "order"
            }
          ]
        },
        collection2 = {
          fields = [
            {
              field_path = "field_path2",
              order      = "order"
            },
            {
              field_path = "field_path3",
              order      = "order"
            }
          ]
        }
      }
    }
    

    Resource:

    resource "google_firestore_index" "catalog-dev" {
      for_each = var.firestore_collections_with_fields
    
      project  = google_firestore_database.database.project
      database = google_firestore_database.database.name
    
      collection = each.key
    
      dynamic "fields" {
        for_each = each.value.fields
        content {
          field_path = fields.value.field_path
          order      = fields.value.order
        }
      }
    }