【问题标题】:List of Active Directory DNS servers IP addresses in an SSM documentSSM 文档中的 Active Directory DNS 服务器 IP 地址列表
【发布时间】:2020-10-21 15:35:20
【问题描述】:

我正在将我的 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 不接受这个代码,说

这个值没有任何索引。

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

"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 格式不正确

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

{"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 将值放在一起,但随后出现数据类型错误。现在,看来我在这里循环。

这里有人给我指路吗?

【问题讨论】:

    标签: amazon-web-services terraform terraform-provider-aws terraform0.12+


    【解决方案1】:

    Terraform 0.12 具有比 0.11 更严格的类型,并且在幕后进行的自动类型强制更少,所以在这里您遇到了这样一个事实:aws_directory_service_directory 资源的输出 dns_ip_addresses attribute isn't a list but a set

                "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
    

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

    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
    

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

    这里还有一个可能的选项,您可以直接将dns_ip_addresses 属性编码为带有jsonencode function 的JSON,而不是从输出集或列表构建JSON 输出:

    variable "example_set" {
      type = set(string)
      default = [
        "foo",
        "bar",
      ]
    }
    
    output "set_first_element" {
      value = jsonencode(var.example_set)
    }
    

    运行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 对此进行了更详细的介绍:

    大多数资源依赖项都是自动处理的。地形 分析资源块中的任何表达式以查找对 其他对象,并将这些引用视为隐式排序 创建、更新或销毁资源时的要求。自从 大多数在行为上依赖于其他资源的资源也 参考这些资源的数据,通常不需要手动 指定资源之间的依赖关系。

    但是,某些依赖项无法隐式识别 配置。例如,如果 Terraform 必须管理访问控制 政策并采取需要这些政策存在的行动, 访问策略和资源之间存在隐藏的依赖关系 谁的创造取决于它。在这些罕见的情况下,depends_on 元参数可以显式指定依赖项。

    【讨论】:

    • 谢谢,这已经解决了。我认为我应该花更多时间阅读 Terraform 文档,因为如果我花更多时间阅读不同的数据类型,我可能会自己找到答案。我确实尝试将变量包装在 list() 中,但不是 tolist(),看起来这是我的错误之一。谢谢。
    猜你喜欢
    • 2016-09-11
    • 1970-01-01
    • 1970-01-01
    • 2013-05-18
    • 2020-12-09
    • 1970-01-01
    • 1970-01-01
    • 2019-07-01
    • 1970-01-01
    相关资源
    最近更新 更多