簡體   English   中英

Terraform 0.12 AWS 資源,包含從變量構建的 JSON

[英]Terraform 0.12 AWS resource containing JSON built from variable

要在 AWS 組織中預置標簽策略,我需要從變量構建 JSON content 對標簽策略、scp等進行集中管理,可以隨處應用更改:重命名、添加、刪除標簽等。

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}
provider "aws" {
  profile = "default"
  region  = "us-west-1"
}

我面臨的問題是:我將如何構建 JSON 對象?

示例變量/標簽映射:

# tag_policies.tf
variable "resource_tags" {
  description = "Central resource tags"
  type = list( object( {
    name = string
    tags = map(string)
  } ) )
  default = [
    {
      name = "Environment"
      tags = {
        prod = "crn::env:prod"
        lab = "crn::env:lab"
        dev = "crn::env:dev"
      }
    }
  ]
}

到目前為止,我嘗試過的是使用 HCL 模板標簽,但在遍歷標簽名稱映射時,我最終得到了一個,逗號太多。 這對於帶有標記名稱子圖的join()工作正常,但如果我嘗試包裝模板標記,則不起作用。 我為什么要嘗試這個? 因為我的想法用完了。

# vars.tf
resource "aws_organizations_policy" "root-tag-policy" {
  name = "RootTagPolicy"
  type = "TAG_POLICY"

  content = <<CONTENT
{
  "tags": {
    %{ for tag in var.resource_tags_env ~}
      "${tag.name}": {
        "tag_key": {
          "@@assign": "${tag.name}",
          "@@operators_allowed_for_child_policies": [ "@@none" ]
        },
        "tag_value": { "@@assign": [ "${join( ", ", values( tag.tags ) )}" ] }
      },
    %{ endfor ~}
  }
}
CONTENT
}

解決方案實際上非常簡單:使用for表達式迭代標記並用大括號{ … }將其括起來以返回一個對象( =>返回元組)。

最后jsonencode()關心將 HCL key = value語法轉換為正確的 JSON。

resource "aws_organizations_policy" "root-tag-policy" {
  name = "RootTagPolicy"
  type = "TAG_POLICY"

  content = jsonencode( [ for key, tag in var.resource_tags: {
    "${tag.name}" = {
      "tag_key" = {
        "@@assign" = tag.name,
        "@@operators_allowed_for_child_policies" = [ "@@none" ]
      },
      "tag_value" = { "@@assign" = [ join( ", ", values( tag.tags ) ) ] }
    }
  } ] )
}

編輯這仍然不起作用,因為我忘記了整個 JSON 對象需要包裝在tags: {}

kaiser 的回答顯示了一個很好的通用方法:構建一個合適的數據結構,然后將其傳遞給jsonencode以從中獲取有效的 JSON 字符串。

這是一個我認為與原始問題中的字符串模板匹配的示例:

  content = jsonencode({
    tags = {
      for tag in var.resource_tags_env : tag.name => {
        tag_key = {
          "@@assign" = tag.name
          "@@operators_allowed_for_child_policies" = ["@@none"]
        }
        tag_value = {
          "@@assign" = values(tag.tags)
        }
      }
    }
  })

我不熟悉aws_organizations_policy資源類型,所以如果我在這里弄錯了一些細節,我很抱歉,但希望您可以調整上面的示例以生成您需要的 JSON 數據結構。

閱讀@martin-atkins 的回答后,我終於明白了for是如何作用於objectsmaps =>箭頭之前的 var 實際上是結果對象的一部分。 (這讓我非常困惑,因為我將它與其他語言的箭頭函數和參數進行了比較。)

該過程的第一部分是構建地圖地圖。 主要原因是我不想在變量映射中約定name鍵。 這可能會導致稍后處理約定,應該不惜一切代價避免這種情況,因為如果不密切注意或意識到它可能是一個陷阱。 所以key實際上是現在的name

數據結構

variable "resource_tags" {
  description = "Central resource tags"
  type = map(
    map(string)
  )
  default = {
    Environment = {
      common = "grn::env:common"
      prod = "grn::env:prod"
      stage = "grn::env:stage"
      dev = "grn::env:dev"
      demo = "grn::env:demo"
      lab = "grn::env:lab"
    },
    Foo = {
      bar = "baz"
    }
  }
}

content為 JSON

在了解{ "tags": { … } }中的鍵只是=>之前的部分后,我可以將最終資源減少到以下塊。

resource "aws_organizations_policy" "root-tag-policy" {
  name = "RootTagPolicy"
  description = "Tag policies, assigned to the root org."
  type = "TAG_POLICY"

  content = jsonencode({
    tags = {
      for key, tags in var.resource_tags : key => {
        tag_key = {
          "@@assign" = key
          "@@operators_allowed_for_child_policies" = ["@@none"]
        }
        tag_value = {
          "@@assign" = values( tags )
        }
      }
    }
  })
}

快速測試:

resource塊后添加以下output語句:

output "debug" {
  value = aws_organizations_policy.tp_root-tag-policy.content
}

現在apply (或planrefresh )此資源。 這種方式更快。 然后從applyrefresh運行輸出構建的debug

$ terraform apply -target=aws_organizations_policy.root-tag-policy
…things happening…
$ terraform output debug | json_pp

小貼士:

  1. 將輸出的output直接通過管道傳輸到json_ppjq以便您可以讀取它。
  2. 使用jq . 如果你想在上面進行驗證。 如果您看到輸出,則表示它是有效的。 否則你應該收到0作為響應。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM