SSM 文档中的 Active Directory DNS 服务器 IP 地址列表

List of Active Directory DNS servers IP addresses in an SSM document

我正在将我的 0.11 代码转换为 0.12。大多数事情似乎都很好,但我真的迷失在 SSM 文档上。

在我的 0.11 代码中,我有这样的代码:

resource "aws_ssm_document" "ssm_document" {
    name = "ssm_document_${terraform.workspace}${var.addomainsuffix}"
    document_type = "Command"
    content = <<DOC
    {
        "schemaVersion": "1.0",
        "description": "Automatic Domain Join Configuration",
        "runtimeConfig": {
            "aws:domainJoin": {
                "properties": {
                    "directoryId": "${aws_directory_service_directory.microsoftad-lab.id}",
                    "directoryName": "${aws_directory_service_directory.microsoftad-lab.name}",
                    "dnsIpAddresses": [
                        "${aws_directory_service_directory.microsoftad-lab.dns_ip_addresses[0]}",
                        "${aws_directory_service_directory.microsoftad-lab.dns_ip_addresses[1]}"
                    ]
                }
            }
        }
    }
    DOC
    depends_on = ["aws_directory_service_directory.microsoftad-lab"]
}

这相当有效。但是,Terraform 0.12 不接受这个代码,说

This value does not have any indices.

我一直在尝试在网上查找不同的解决方案,但我遇到了无数与数据类型有关的问题。例如,我看到的解决方案之一是这样提出的:

"dnsIpAddresses": [
                    "${sort(aws_directory_service_directory.oit-microsoftad-lab.dns_ip_addresses)[0]}",
                    "${sort(aws_directory_service_directory.oit-microsoftad-lab.dns_ip_addresses)[1]}",
                ]
            }

我得到

InvalidDocumentContent: JSON not well-formed

这对我来说有点奇怪,因为如果我查看跟踪日志,我 似乎 得到相对正确的值:

{"Content":"{\n    \"schemaVersion\": \"1.0\",\n    \"description\": \"Automatic Domain Join Configuration\",\n    \"runtimeConfig\": {\n        \"aws:domainJoin\": {\n            \"properties\": {\n                \"directoryId\": \"d-9967245377\",\n                \"directoryName\": \"012mig.lab\",\n                \"dnsIpAddresses\": [\n                    \"10.0.0.227\",\n
      \"10.0.7.103\",\n                ]\n            }\n        }\n    }\n}\n    \n","DocumentFormat":"JSON","DocumentType":"Command","Name":"ssm_document_012mig.lab"}

我已经尝试使用 concat 和 list 将这些值放在一起,但是我收到了数据类型错误。眼下,我好像在兜圈子。

这里有没有大佬指点一下?

Terraform 0.12 具有比 0.11 更严格的类型,并且在幕后进行的自动类型强制转换更少,所以在这里您 运行 了解到 aws_directory_service_directory resource's dns_ip_addresses attribute isn't a list but a set:[=36 的输出=]

            "dns_ip_addresses": {
                Type:     schema.TypeSet,
                Elem:     &schema.Schema{Type: schema.TypeString},
                Set:      schema.HashString,
                Computed: true,
            },

Set's can't be indexed directly 而不是必须首先在 0.12 中明确转换为列表。

举个例子:

variable "example_list" {
  type = list(string)
  default = [
    "foo",
    "bar",
  ]
}


output "list_first_element" {
  value = var.example_list[0]
}

运行 terraform apply 将输出以下内容:

Outputs:

list_first_element = foo

但是,如果我们改用集合变量:

variable "example_set" {
  type = set(string)
  default = [
    "foo",
    "bar",
  ]
}

output "set_first_element" {
  value = var.example_set[0]
}

然后尝试 运行 terraform apply 将抛出以下错误:

Error: Invalid index

  on main.tf line 22, in output "set_foo":
  22:   value = var.example_set[0]

This value does not have any indices.

如果我们先将 set 变量转换为带有 tolist 的列表,那么它可以工作:

variable "example_set" {
  type = set(string)
  default = [
    "foo",
    "bar",
  ]
}

output "set_first_element" {
  value = tolist(var.example_set)[0]
}
Outputs:

set_first_element = bar

请注意,集合的顺序可能与您预期的不同(在这种情况下,它是按字母顺序排列的,而不是按照声明的顺序排列的)。在您的情况下,这不是问题,但在索引期望元素按您声明的顺序排列时值得考虑。

此处的另一个可能选项,而不是从输出集或输出列表构建 JSON 输出,您可以直接将 dns_ip_addresses 属性编码为 JSON 并使用 jsonencode function:

variable "example_set" {
  type = set(string)
  default = [
    "foo",
    "bar",
  ]
}

output "set_first_element" {
  value = jsonencode(var.example_set)
}

在 运行ning terraform apply 之后输出以下内容:

Outputs:

set_first_element = ["bar","foo"]

因此,对于您的具体示例,我们想要做这样的事情:

resource "aws_ssm_document" "ssm_document" {
    name = "ssm_document_${terraform.workspace}${var.addomainsuffix}"
    document_type = "Command"
    content = <<DOC
    {
        "schemaVersion": "1.0",
        "description": "Automatic Domain Join Configuration",
        "runtimeConfig": {
            "aws:domainJoin": {
                "properties": {
                    "directoryId": "${aws_directory_service_directory.microsoftad-lab.id}",
                    "directoryName": "${aws_directory_service_directory.microsoftad-lab.name}",
                    "dnsIpAddresses": ${jsonencode(aws_directory_service_directory.microsoftad-lab.dns_ip_addresses)}
                }
            }
        }
    }
    DOC
}

请注意,我还删除了不必要的 depends_on。如果一个资源从另一个资源中插入,Terraform 将自动理解需要在引用它之前创建插入的资源。

resource dependencies documentation 对此进行了更详细的介绍:

Most resource dependencies are handled automatically. Terraform analyses any expressions within a resource block to find references to other objects, and treats those references as implicit ordering requirements when creating, updating, or destroying resources. Since most resources with behavioral dependencies on other resources also refer to those resources' data, it's usually not necessary to manually specify dependencies between resources.

However, some dependencies cannot be recognized implicitly in configuration. For example, if Terraform must manage access control policies and take actions that require those policies to be present, there is a hidden dependency between the access policy and a resource whose creation depends on it. In these rare cases, the depends_on meta-argument can explicitly specify a dependency.