Integrating Remote and Local State - GlennChia/terraform-azurerm-caf GitHub Wiki

The file that is responsible for merging the local and remote state is locals.combined_objects.tf. This guide comprises the Application section which shows how to use the combined object in a module and the Background section which shows

  1. Application
  2. Background

Application

This seciton covers the pattern on how to use the combined_object in the module.

First, understand the attributes provided by the resource_groups object. These attributes are:

  1. name
  2. location
  3. tags
  4. rbac_id
  5. id

Now, several possible patterns emerge depending on the number of attributes that the module needs to reference

Reference one attribute

For example, if a module requires only the attribute name and maps it to resource_group_name, then we opt to destructure the combined objects at the module level. Example:

module "example" {
  source   = "./modules/some_module/example"
  for_each = local.some_module.example
  name     = each.value.name

  resource_group_name = local.combined_objects_resource_groups[try(each.value.lz_key, local.client_config.landingzone_key)][each.value.resource_group_key].name
}

Then in the modules directory, for that specific resource, create a variables.tf that expects this resource_group_name

variable "resource_group_name" {
  description = "Name of the existing resource group to deploy the virtual machine"
}

Then this variable is easily referenced in the resource's .tf file

resource_group_name   = var.resource_group_name

Reference multiple attributes

For example, a module may require the tags, location, and name attribute. In this case, we opt to destructure the combined ibjects at the resource level. Example:

module "example" {
  source   = "./modules/some_module/example"
  for_each = local.some_module.example
  name     = each.value.name

  resource_group = local.combined_objects_resource_groups[try(each.value.lz_key, local.client_config.landingzone_key)][each.value.resource_group_key]
}

Then in the modules directory, for that specific resource, create a variables.tf that expects this resource_group object

variable "resource_group" {
}

Then destructure this variable in the resource's .tf file

resource_group_name   = var.resource_group.name

Note: There could be cases where we want to resolve the landing zone key within the resource itself (for example if certain resources use a specified lz_key rather than the common one). For this use case, the module level will look like:

module "example" {
  source   = "./modules/some_module/example"
  for_each = local.some_module.example
  name     = each.value.name

  resource_groups = local.combined_objects_resource_groups
  # inject the lz_key here
}

Then within the resource, destructure similar to how it was done at the module level but now do it at the resource level.

Background

We use the combined_objects_resource_groups to illustrate this.

locals.combined_objects.tf

The relevant snippet shows that combined_objects_resource_groups merges the local state that comes from local.resource_groups with the remote state that comes from var.remote_objects.resource_groups.

locals {
  combined_objects_resource_groups = merge(
    tomap({
      (local.client_config.landingzone_key) = local.resource_groups
    }),
    try(var.remote_objects.resource_groups, {})
  )
}

resource_groups.tf

This module initialize the resource groups and stores the outputs in the locals. This is how locals.combined_objects.tf can reference the local resource groups by using local.resource_groups.

locals {
  resource_groups = merge(module.resource_groups, module.resource_group_reused)
}

variables.tf

The remote objects is initialized here. This is how locals.combined_objects.tf can reference the local resource groups by using var.remote_objects.resource_groups. This variable has its values injected behind the scenes by the caf_launchpad or landing zone.

variable "remote_objects" {
  description = "Remote objects is used to allow the landing zone to retrieve remote tfstate objects and pass them to the caf module"
  default     = {}
}