Terraform 失败并显示“无法访问对象列表上的属性”。 - 无法访问使用“for_each = toset(...)”创建的资源上的字段?

问题描述 投票:0回答:1

Terraform 失败并显示“无法访问对象列表上的属性”。 - 无法访问使用

for_each = toset(local.domains[*].domain_name)
创建的资源上的字段?

local.domains[*].domain_name
是一个域列表,例如 www.example.com,我需要将其转换为与
for_each
一起使用的集合。

如何单独迭代

aws_apigatewayv2_domain_name
资源来创建
aws_route53_record
资源?

我当前的尝试导致以下错误,我不明白(?):

╷
│ Error: Unsupported attribute
│
│   on ../modules/http-api-custom-domain-name/main.tf line 64, in resource "aws_route53_record" "api_gateway":
│   64:     name                   = aws_apigatewayv2_domain_name.api_gateway[each.value].domain_name_configuration.target_domain_name
│     ├────────────────
│     │ aws_apigatewayv2_domain_name.api_gateway is object with 1 attribute "bff-dev-partner.service-dev.dpt.lego.com"
│     │ each.value is "bff-dev-partner.service-dev.dpt.lego.com"
│
│ Can't access attributes on a list of objects. Did you mean to access attribute "target_domain_name" for a specific element of the list, or
│ across all elements of the list?

我宁愿直接迭代它们,而不是索引

aws_apigatewayv2_domain_name
资源。可以打吗?

如何修复代码,以便为每个

aws_route53_record
创建
aws_api_gateway_base_path_mapping
aws_apigatewayv2_domain_name
资源?

代码:

resource "aws_apigatewayv2_domain_name" "api_gateway" {
  for_each = toset(local.domains[*].domain_name)

  domain_name = each.value

  domain_name_configuration {
    certificate_arn = var.certificate_arn == null ? aws_acm_certificate.cert[0].arn : var.certificate_arn
    endpoint_type   = "REGIONAL"
    security_policy = "TLS_1_2"
  }
}

resource "aws_route53_record" "api_gateway" {
  for_each = toset(local.domains[*].domain_name)

  name    = aws_apigatewayv2_domain_name.api_gateway[each.value].domain_name_configuration.domain_name
  type    = "A"
  zone_id = local.domain_to_hosted_zone[each.value]

  alias {
    name                   = aws_apigatewayv2_domain_name.api_gateway[each.value].domain_name_configuration.target_domain_name
    zone_id                = aws_apigatewayv2_domain_name.api_gateway[each.value].domain_name_configuration.hosted_zone_id
    evaluate_target_health = false
  }
}

resource "aws_api_gateway_base_path_mapping" "api_gateway" {
  for_each = aws_apigatewayv2_domain_name.api_gateway[*].domain_name

  api_id      = var.api_gateway_id
  stage_name  = var.api_gateway_stage
  domain_name = each.value
}

错误:

│ Error: Unsupported attribute
│
│   on ../modules/http-api-custom-domain-name/main.tf line 59, in resource "aws_route53_record" "api_gateway":
│   59:   name    = aws_apigatewayv2_domain_name.api_gateway[each.value].domain_name_configuration.domain_name
│     ├────────────────
│     │ aws_apigatewayv2_domain_name.api_gateway is object with 1 attribute "bff-dev-partner.service-dev.dpt.lego.com"
│     │ each.value is "bff-dev-partner.service-dev.dpt.lego.com"
│
│ Can't access attributes on a list of objects. Did you mean to access an attribute for a specific element of the list, or across all
│ elements of the list?
╵
╷
│ Error: Unsupported attribute
│
│   on ../modules/http-api-custom-domain-name/main.tf line 64, in resource "aws_route53_record" "api_gateway":
│   64:     name                   = aws_apigatewayv2_domain_name.api_gateway[each.value].domain_name_configuration.target_domain_name
│     ├────────────────
│     │ aws_apigatewayv2_domain_name.api_gateway is object with 1 attribute "bff-dev-partner.service-dev.dpt.lego.com"
│     │ each.value is "bff-dev-partner.service-dev.dpt.lego.com"
│
│ Can't access attributes on a list of objects. Did you mean to access attribute "target_domain_name" for a specific element of the list, or
│ across all elements of the list?
╵
╷
│ Error: Unsupported attribute
│
│   on ../modules/http-api-custom-domain-name/main.tf line 65, in resource "aws_route53_record" "api_gateway":
│   65:     zone_id                = aws_apigatewayv2_domain_name.api_gateway[each.value].domain_name_configuration.hosted_zone_id
│     ├────────────────
│     │ aws_apigatewayv2_domain_name.api_gateway is object with 1 attribute "bff-dev-partner.service-dev.dpt.lego.com"
│     │ each.value is "bff-dev-partner.service-dev.dpt.lego.com"
│
│ Can't access attributes on a list of objects. Did you mean to access attribute "hosted_zone_id" for a specific element of the list, or
│ across all elements of the list?
╵
╷
│ Error: Unsupported attribute
│
│   on ../modules/http-api-custom-domain-name/main.tf line 71, in resource "aws_api_gateway_base_path_mapping" "api_gateway":
│   71:   for_each = aws_apigatewayv2_domain_name.api_gateway[*].domain_name
│
│ This object does not have an attribute named "domain_name".
amazon-web-services terraform continuous-integration cd
1个回答
0
投票

当您使用

for_each
创建多个资源时,Terraform 将它们视为对象的 map,而不是列表。

在您的

aws_route53_record
aws_api_gateway_base_path_mapping
资源中,您尝试使用列表语法访问属性,但您应该使用映射键(在您的情况下为
each.value
)。

这意味着需要调整访问单个资源属性的语法:

resource "aws_apigatewayv2_domain_name" "api_gateway" {
  for_each = toset(local.domains[*].domain_name)

  domain_name = each.value

  domain_name_configuration {
    certificate_arn = var.certificate_arn == null ? aws_acm_certificate.cert[0].arn : var.certificate_arn
    endpoint_type   = "REGIONAL"
    security_policy = "TLS_1_2"
  }
}

resource "aws_route53_record" "api_gateway" {
  for_each = aws_apigatewayv2_domain_name.api_gateway

  name    = each.value.domain_name_configuration.domain_name
  type    = "A"
  zone_id = local.domain_to_hosted_zone[each.key]

  alias {
    name                   = each.value.domain_name_configuration.target_domain_name
    zone_id                = each.value.domain_name_configuration.hosted_zone_id
    evaluate_target_health = false
  }
}

resource "aws_api_gateway_base_path_mapping" "api_gateway" {
  for_each = aws_apigatewayv2_domain_name.api_gateway

  api_id      = var.api_gateway_id
  stage_name  = var.api_gateway_stage
  domain_name = each.key
}

通过此修改,您应该不再遇到“

Unsupported attribute
”错误。每个
aws_route53_record
aws_api_gateway_base_path_mapping
资源应与每个
aws_apigatewayv2_domain_name
资源正确关联。


但是,正如jordanm评论中指出的那样,这取决于

local.domains
如何定义:

  • 如果

    local.domains
    是一个简单的域名字符串列表,如
    ["www.example.com", "api.example.com"]
    ,则上面的解决方案将按原样工作。这是因为
    toset(local.domains[*].domain_name)
    会正确地将这个列表转换为一组字符串,
    for_each
    可以对其进行迭代。

  • 如果

    local.domains
    是地图或对象的列表,例如
    [{"domain_name": "www.example.com"}, {"domain_name": "api.example.com"}]
    ,那么您提取
    for_each
    域名的方式将需要更改。您需要使用更复杂的表达式来从列表中的每个地图/对象中提取域名,而不是
    toset(local.domains[*].domain_name)

  • 如果

    local.domains
    具有更复杂或嵌套的结构,则需要定制解决方案以正确导航和提取所需信息。例如,如果
    local.domains
    包含额外的嵌套属性或不同级别的细节,则为
    for_each
    提取域名的方法将需要适应这种复杂性。


详细说明第二种情况,当

local.domains
是地图或对象列表时,其中每个元素都包含
domain_name
键,您的 Terraform 配置需要以不同方式提取这些域名以便与
for_each
一起使用。

假设

local.domains
的定义如下:

locals {
  domains = [
    { domain_name = "www.example.com" },
    { domain_name = "api.example.com" }
    // other domains
  ]
}

您的资源将定义如下:

  1. aws_apigatewayv2_domain_name:使用

    for_each
    迭代从
    local.domains
    中提取的一组域名。

    resource "aws_apigatewayv2_domain_name" "api_gateway" {
    for_each = { for d in local.domains : d.domain_name => d.domain_name }
    
    domain_name = each.value
    
    domain_name_configuration {
        certificate_arn = var.certificate_arn == null ? aws_acm_certificate.cert[0].arn : var.certificate_arn
        endpoint_type   = "REGIONAL"
        security_policy = "TLS_1_2"
    }
    }
    
  2. aws_route53_record:根据

    each.key
    资源中使用的
    each.value
    引用
    for_each
    aws_apigatewayv2_domain_name

    resource "aws_route53_record" "api_gateway" {
    for_each = aws_apigatewayv2_domain_name.api_gateway
    
    name    = each.value.domain_name_configuration.domain_name
    type    = "A"
    zone_id = local.domain_to_hosted_zone[each.key]
    
    alias {
        name                   = each.value.domain_name_configuration.target_domain_name
        zone_id                = each.value.domain_name_configuration.hosted_zone_id
        evaluate_target_health = false
    }
    }
    
  3. aws_api_gateway_base_path_mapping:使用

    each.key
    表示此设置中的域名。

    resource "aws_api_gateway_base_path_mapping" "api_gateway" {
    for_each = aws_apigatewayv2_domain_name.api_gateway
    
    api_id      = var.api_gateway_id
    stage_name  = var.api_gateway_stage
    domain_name = each.key
    }
    

for_each
中的
aws_apigatewayv2_domain_name
被更改为创建一个映射,其中键和值都是域名,从映射的
local.domains
列表中提取。然后可以在其他资源中一致地使用该结构。

© www.soinside.com 2019 - 2024. All rights reserved.