14
Terraform v0.12.12
+ provider.aws v3.0.0
+ provider.template v2.1.2

在我这样做之前:

resource "aws_route53_record" "derps" {
  name    = aws_acm_certificate.mycert[0].resource_record_name
  type    = aws_acm_certificate.mycert[0].resource_record_type
  zone_id = var.my_zone_id
  records = aws_acm_certificate.mycert[0].resource_record_value
  ttl     = 60
}

大约一周前,这对我来说效果很好。

我刚刚做了一个计划并得到了一个错误:

records = [aws_acm_certificate.mycert.domain_validation_options[0].resource_record_value]

This value does not have any indices.

现在我不固定提供程序版本,所以我假设我拉了一个更新的版本并且资源发生了变化。

在与这个斗争并意识到它不是一个列表之后(即使show state它看起来确实像一个)我现在这样做是为了让它成为一个列表:

resource "aws_route53_record" "derps" {
  name    = sort(aws_acm_certificate.mycert.domain_validation_options[*].resource_record_name)[0]
  type    = sort(aws_acm_certificate.mycert.domain_validation_options[*].resource_record_type)[0]
  zone_id = var.my_zone_id
  records = [sort(aws_acm_certificate.mycert.domain_validation_options[*].resource_record_value)[0]]
  ttl     = 60
} 

这导致没有变化,这是好的。但是,如果我使用他们现在使用 for_each 的文档中的示例来执行此操作:https ://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation

resource "aws_route53_record" "example" {
  for_each = {
    for dvo in aws_acm_certificate.example.domain_validation_options : dvo.domain_name => {
      name    = dvo.resource_record_name
      record  = dvo.resource_record_value
      type    = dvo.resource_record_type
      zone_id = dvo.domain_name == "example.org" ? data.aws_route53_zone.example_org.zone_id : data.aws_route53_zone.example_com.zone_id
    }
  }

  allow_overwrite = true
  name            = each.value.name
  records         = [each.value.record]
  ttl             = 60
  type            = each.value.type
  zone_id         = each.value.zone_id
}

resource "aws_acm_certificate_validation" "example" {
  certificate_arn         = aws_acm_certificate.example.arn
  validation_record_fqdns = [for record in aws_route53_record.example : record.fqdn]
}

以上是现在执行此操作的正确方法吗?我会以目前的方式遇到问题吗?像上面那样做会导致销毁/重新创建(我想我可以自己导入它,但这很痛苦)。

以我的方式这样做不会导致意外的差异吗?

编辑

所以,对于我的问题更具体。这是我在查看状态时看到的:

terraform state show aws_acm_certificate.mycert

    ...
    domain_name               = "*.mydom.com"
    domain_validation_options = [
        {
            domain_name           = "*.mydom.com"
            resource_record_name  = "_11111111111.mydom.com."
            resource_record_type  = "CNAME"
            resource_record_value = "_1111111111.11111111.acm-validations.aws."
        },
        {
            domain_name           = "mydom.com"
            resource_record_name  = "_11111111111.mydom.com."
            resource_record_type  = "CNAME"
            resource_record_value = "_1111111111.111111111.acm-validations.aws."
        },
    ]
    ... 

通过使用排序,我有效地使用了计数,如果订单发生变化,这当然会导致销毁/重新创建。但就我而言,我认为这不太可能?我也不完全理解仅使用通配符验证配置中的值和同时使用它们之间的区别。

4

4 回答 4

10

AWS Terraform 提供程序最近升级到版本 3.0。这个版本附带了一个重大更改列表。我建议查阅AWS 提供商 3.0 升级指南

您遇到的问题是因为该domain_validation_options属性现在是一个集合而不是一个列表。从该指南:

由于domain_validation_options属性从列表更改为集合,并且集合无法在 Terraform 中建立索引,因此建议更新配置以使用更稳定的资源for_each支持,而不是count

我建议按照升级指南的建议使用新foreach语法,以避免意外差异。该指南指出,您将需要使用terraform state mv将旧配置状态移动到新配置,以防止重新创建资源。

于 2020-08-03T19:05:12.543 回答
8

这与我们刚才面临的相同问题.. 我们使用 for_each 根据提供的局部变量来定义多个站点的托管,现在,由于我们已经使用 for_each 我们不能使用它来解决它们的更改.. 不幸。

我不想进行排序,所以我检查了 Jimmy 写的内容,但由于输出是索引,它不适用于这种情况,我通过使用 [0] 而不是 [*] 来修复它:

resource "aws_route53_record" "cert_validation" {
  for_each = local.web_pages
  allow_overwrite = true
  name            = tolist(aws_acm_certificate.cert[each.key].domain_validation_options)[0].resource_record_name
  type            = tolist(aws_acm_certificate.cert[each.key].domain_validation_options)[0].resource_record_type
  records         = [tolist(aws_acm_certificate.cert[each.key].domain_validation_options)[0].resource_record_value]
  zone_id         = var.aws_hosted_zone
  ttl             = 60
}

现在为我们工作;)

于 2020-08-26T12:23:25.313 回答
2

你也可以用tolist.

例如重写aws_acm_certificate.mycert.domain_validation_options[*].resource_record_nametolist(aws_acm_certificate.mycert.domain_validation_options)[*].resource_record_name

我必须在一个模块中执行此操作,因为这个特定的模块资源中已经有一个count,而且我知道我只会有一个条目。

于 2020-08-13T22:02:19.877 回答
2

下面这 3 组代码有效。(我用过Terraform v0.15.0

1st*和的区别2nd[0].0

第一个:

resource "aws_route53_record" "myRecord" {
  zone_id = aws_route53_zone.myZone.zone_id
  name    = tolist(aws_acm_certificate.myCert.domain_validation_options)[0].resource_record_name
  type    = tolist(aws_acm_certificate.myCert.domain_validation_options)[0].resource_record_type
  records = [tolist(aws_acm_certificate.myCert.domain_validation_options)[0].resource_record_value]
  ttl = "60"
  allow_overwrite = true
}

第二:

resource "aws_route53_record" "myRecord" {
  zone_id = aws_route53_zone.myZone.zone_id
  name    = tolist(aws_acm_certificate.myCert.domain_validation_options).0.resource_record_name
  type    = tolist(aws_acm_certificate.myCert.domain_validation_options).0.resource_record_type
  records = [tolist(aws_acm_certificate.myCert.domain_validation_options).0.resource_record_value]
  ttl = "60"
  allow_overwrite = true
}

第三:

resource "aws_route53_record" "myRecord" {
  for_each = {
    for dvo in aws_acm_certificate.myCert.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
      record = dvo.resource_record_value
      type   = dvo.resource_record_type
    }
  }

  name            = each.value.name
  records         = [each.value.record]
  ttl             = 60
  type            = each.value.type
  zone_id         = aws_route53_zone.myZone.zone_id
  allow_overwrite = true
}
于 2021-04-24T16:09:31.267 回答