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".
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
资源正确关联。
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
]
}
您的资源将定义如下:
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"
}
}
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
}
}
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
列表中提取。然后可以在其他资源中一致地使用该结构。