How to extract from Terraform complex variable value??

Variable file:

# Selection
variable "selections" {
  description = "A map of selction maps"
  type = map(object({
    name         = string
    plan_id      = optional(string)
    iam_role_arn = optional(string)
    selection_tags = optional(map(object({
      type  = string
      key   = string
      value = string
    })))
    condition = optional(map(object({
      string_equals = optional(map(object({
        key   = string
        value = string
      })))

      string_like = optional(map(object({
        key   = string
        value = string
      })))

      string_not_equals = optional(map(object({
        key   = string
        value = string
      })))

      string_not_like = optional(map(object({
        key   = string
        value = string
      })))
    })))

  }))
  default = {}
}

tfvars:

selections = {
  selection1 = {
    name          = "selection-1"
    resources     = ["arn:aws:dynamodb:ap-southeast-1:123456789101:table/mydynamodb-table1"]
    not_resources = []
    selection_tags = {
      1 = {
        type  = "STRINGEQUALS"
        key   = "Environment"
        value = "production"
      },
      2 = {
        type  = "STRINGEQUALS"
        key   = "Owner"
        value = "production"
      }
    }
  },
  selection2 = {
    name      = "selection-2"
    resources = ["arn:aws:dynamodb:ap-southeast-1:123456789101:table/mydynamodb-table2"]
  },
  selection3 = {
    name          = "selection-3"
    resources     = ["arn:aws:dynamodb:ap-southeast-1:123456789101:table/mydynamodb-table3"]
    not_resources = []
    condition = {
      string_equals = {
        1 = {
          key   = "aws:ResourceTag/Component"
          value = "rds"
        },
        2 = {
          key   = "aws:ResourceTag/Project"
          value = "Project1"
        },
      }
    }
  },
}

Xử lý:

resource "aws_backup_selection" "backup_selection" {
  # count = var.enable_backup ? length(local.selections) : 0
  for_each = local.selections

  iam_role_arn = var.backup_iam_role_arn != null ? var.backup_iam_role_arn : aws_iam_role.backup_role[0].arn
  name         = try(local.selections[each.key]["name"], null)
  plan_id      = aws_backup_plan.backup_plan[0].id

  resources     = try(local.selections[each.key]["resources"], null)
  not_resources = try(local.selections[each.key]["not_resources"], null)

  dynamic "selection_tag" {
    for_each = each.value.selection_tags != null ? each.value.selection_tags : {}
    content {
      type  = try(selection_tag.value["type"], null)
      key   = try(selection_tag.value["key"], null)
      value = try(selection_tag.value["value"], null)
    }
  }

  condition {
    dynamic "string_equals" {
      for_each = lookup(try(each.value.condition[each.key].value["string_equals"], {}), "string_equals", {})
      content {
        key   = try(string_equals.value["key"], null)
        value = lookup(string_equals.value["value"], null)
      }
    }
  }
}

Lỗi:

Hiện tại đang bị lỗi chưa biết cách lấy giá trị khai báo để tạo ra condition string_equals (Khi apply code như trên đang bị condition = {})

\=> Solution + chỉnh sửa: Hiện tại code đã chạy khi làm như bên dưới.

Cách troubleshooting + testing: Em tạo ra 1 variable condition {} tách biệt riêng ra khỏi hẳn selections và test việc lấy các giá trị trên variable riêng đó, việc này sẽ giúp em tận dụng được terraform console dễ dàng hơn, vì không bị lẫn các giá trị, loop nhiều lần.

Sau khi lấy được thành công giá trị từ biến condition tách biệt, thì em đưa vào trong xử lý chung với selections. Nhận thấy rằng condition cùng level select với selection_tags => có thể get block condition ra tương tự như selection_tags block, việc xử lý thì chỉ cần copy từ cách xử lý variable condtion tách biệt là done!

Bài học rút ra là Terraform console là một feature rất nên sử dụng của Terraform, giúp thuận tiện cho việc troubleshooting.

variable "selections" {
  description = "A map of selction maps"
  type = map(object({
    name         = string
    plan_id      = optional(string)
    iam_role_arn = optional(string)
    selection_tags = optional(map(object({
      type  = string
      key   = string
      value = string
    })))
    condition = optional(object({
      string_equals = optional(map(object({
        key   = string
        value = string
      }))),
      string_like = optional(map(object({
        key   = string
        value = string
      }))),
      string_not_equals = optional(map(object({
        key   = string
        value = string
      }))),
      string_not_like = optional(map(object({
        key   = string
        value = string
      }))),
    }))
  }))
  default = {}
}

Khai báo tfvars:

selections = {
  selection1 = {
    name          = "selection-1"
    resources     = ["arn:aws:dynamodb:ap-southeast-1:123456789101:table/mydynamodb-table1"]
    not_resources = []
    selection_tags = {
      1 = {
        type  = "STRINGEQUALS"
        key   = "Environment"
        value = "production"
      },
      2 = {
        type  = "STRINGEQUALS"
        key   = "Owner"
        value = "production"
      }
    }
  },
  selection2 = {
    name      = "selection-2"
    resources = ["arn:aws:dynamodb:ap-southeast-1:123456789101:table/mydynamodb-table2"]
  },
  selection3 = {
    name          = "selection-3"
    resources     = ["arn:aws:dynamodb:ap-southeast-1:123456789101:table/mydynamodb-table3"]
    not_resources = []
    selection_tags = {
      1 = {
        type  = "STRINGEQUALS"
        key   = "Environment"
        value = "production"
      }
    }
    condition = {
      string_equals = {
        1 = {
          key   = "aws:ResourceTag/Component"
          value = "rds"
        },
        2 = {
          key   = "aws:ResourceTag/Project"
          value = "Project1"
        },
      }
      string_like = {
        1 = {
          key   = "aws:ResourceTag/Application"
          value = "app*"
        }
      }
      string_not_equals = {
        1 = {
          key   = "aws:ResourceTag/Backup"
          value = "false"
        },
      }
      string_not_like = {
        1 = {
          key   = "aws:ResourceTag/Environment"
          value = "test*"
        },
      }
    }
  },
}

tags = {
  Owner       = "devops"
  Environment = "production"
  Terraform   = true
}

Xử lý:

resource "aws_backup_selection" "backup_selection" {
  for_each = local.selections

  iam_role_arn = var.backup_iam_role_arn != null ? var.backup_iam_role_arn : aws_iam_role.backup_role[0].arn
  name         = try(local.selections[each.key]["name"], null)
  plan_id      = aws_backup_plan.backup_plan[0].id

  resources     = try(local.selections[each.key]["resources"], null)
  not_resources = try(local.selections[each.key]["not_resources"], null)

  dynamic "selection_tag" {
    for_each = each.value.selection_tags != null ? each.value.selection_tags : {}
    content {
      type  = try(selection_tag.value["type"], null)
      key   = try(selection_tag.value["key"], null)
      value = try(selection_tag.value["value"], null)
    }
  }

  dynamic "condition" {
    for_each = each.value.condition != null ? each.value.condition : {}
    content {
      dynamic "string_equals" {
        #for_each = var.selection_conditions["string_equals"] != null ? var.selection_conditions["string_equals"] : {}
        for_each = each.value.condition["string_equals"] != null ? each.value.condition["string_equals"] : {}
        content {
          key   = try(string_equals.value["key"], null)
          value = try(string_equals.value["value"], null)
        }
      }
      dynamic "string_like" {
        for_each = each.value.condition["string_like"] != null ? each.value.condition["string_like"] : {}
        content {
          key   = try(string_like.value["key"], null)
          value = try(string_like.value["value"], null)
        }
      }
      dynamic "string_not_equals" {
        for_each = each.value.condition["string_not_equals"] != null ? each.value.condition["string_not_equals"] : {}
        content {
          key   = try(string_not_equals.value["key"], null)
          value = try(string_not_equals.value["value"], null)
        }
      }
      dynamic "string_not_like" {
        for_each = each.value.condition["string_not_like"] != null ? each.value.condition["string_not_like"] : {}
        content {
          key   = try(string_not_like.value["key"], null)
          value = try(string_not_like.value["value"], null)
        }
      }
    }
  }
}

local:

locals {

  # Selection
  selection = var.selection_name == null ? {} : {
    selection = {
      name           = var.selection_name
      resources      = var.selection_resources
      not_resources  = var.selection_not_resources
      conditions     = var.selection_conditions
      selection_tags = var.selection_tags
    }
  }

  # Selections
  selections = merge(local.selection, var.selections)
}