将一个地形模块的输出引用到另一个模块时出错



我是terraform的新手,正在尝试在terraform v0.14.0中创建一个项目,该项目将执行以下步骤:

  1. 创建n个ec2机器(一个将是主机器,其余将是子机器(
  2. 创建NLB和terget组
  3. 通过引用步骤1的输出变量(ec2模块(,将ec2子实例私有ip附加到目标组

但当我运行地形计划时,我收到以下消息。这能修好吗?或者采取任何其他方法一次性提供这些资源?

Error: Invalid for_each argument
on ../../../../modules/nlb_new2/main.tf line 493, in resource "aws_lb_target_group_attachment" "tgr_attachment":
493:   for_each = {
494:           for pair in setproduct(keys(tomap({arn = lookup(aws_lb_target_group.main[0],"arn")})),  **var.target_id**) :
495:           "${pair[0]},${pair[1]}" => {
496:             target_group = aws_lb_target_group.main[0].arn
497:             target       = length(split(":",pair[1])) > 0 ? split(":",pair[1])[0]: null
498:             port         = length(split(":",pair[1])) == 2 ? split(":",pair[1])[1] : null
499:           }
500:     }

#项目级main.tf

region = lookup(var.lb_common_prop, "region", "us-east-1")
}
module "ec2_detail" {
source = "../../../../modules/ec2_new2"
for_each = var.ec2_detail
instance_count = each.value.instance_count
name =  format("%s-${var.ec2_name.suffix}",each.key)
ami_name      = var.ec2_common_prop.ami_name
instance_type = var.ec2_common_prop.instance_type
subnet_id     = ""
vpc_name      = var.ec2_common_prop.vpc_name

subnet_names  = var.security.subnet_names
vpc_security_group_names    = var.security.vpc_security_group_names

associate_public_ip_address = var.ec2_common_prop.associate_public_ip_address
tags                        = var.ec2_tags
volume_tags                 = var.ec2_volume_tags
key_name                    = var.ec2_common_prop.key_name
user_data                   = ""
iam_instance_profile        = var.ec2_common_prop.iam_instance_profile
monitoring                  = var.ec2_common_prop.monitoring
source_dest_check           = var.ec2_common_prop.source_dest_check
placement_group             = var.ec2_common_prop.placement_group
ebs_optimized               = var.ec2_common_prop.ebs_optimized
disable_api_termination     = var.ec2_common_prop.disable_api_termination
root_block_device = var.hardware.root_block_device
ebs_block_device  = var.hardware.ebs_block_device
}

module "network_load_balancer" {
depends_on=[module.ec2_detail]
source = "../../../../modules/nlb_new2"

for_each = var.all_load_balancer
name = format("%s-${var.ec2_name.suffix}",each.key)
load_balancer_type = each.value.load_balancer_type
vpc_name      = var.ec2_common_prop.vpc_name
subnet_names  = var.security.subnet_names
internal      = lookup(merge(var.lb_tags, each.value.lb_tags), "internal", true)

target_id = lookup(each.value.target_groups[0],"target_id",[])==[] ? [for pair in setproduct(module.ec2_detail["memsql-child"].private_ip, [lookup(var.lb_common_prop,"target_port")]) :  "${pair[0]}:${pair[1]}" ] : lookup(each.value.target_groups[0],"target_id",[])

target_groups = each.value.target_groups
http_tcp_listeners = each.value.http_tcp_listeners
tags  = merge(var.lb_tags, each.value.lb_tags)
}

#NLB模块主.tf

data aws_vpc "selected" {
filter {
name   = "tag:Name"
values = [var.vpc_name] 
}
}
data "aws_subnet_ids" "selected" {
vpc_id=data.aws_vpc.selected.id
filter {
name   = "tag:Name"
values = var.subnet_names
}
}
#data "aws_subnet" "selected" {
#  for_each = data.aws_subnet_ids.selected.ids
#  id       = each.value
#}
resource "aws_lb" "this" {
count = var.create_lb ? 1 : 0
name        = var.name
name_prefix = var.name_prefix
load_balancer_type = var.load_balancer_type
internal           = var.internal
#security_groups    = var.security_groups

#security_groups    = [for i in range(length(var.vpc_security_group_names)) : data.aws_security_group.selected.*.id[i]]

#subnets            = var.subnets
#subnets = [for s in data.aws_subnet_ids.selected : s.ids]
subnets = data.aws_subnet_ids.selected.ids
idle_timeout                     = var.idle_timeout
enable_cross_zone_load_balancing = var.enable_cross_zone_load_balancing
enable_deletion_protection       = var.enable_deletion_protection
enable_http2                     = var.enable_http2
ip_address_type                  = var.ip_address_type
drop_invalid_header_fields       = var.drop_invalid_header_fields
# See notes in README (ref: https://github.com/terraform-providers/terraform-provider-aws/issues/7987)
dynamic "access_logs" {
for_each = length(keys(var.access_logs)) == 0 ? [] : [var.access_logs]
content {
enabled = lookup(access_logs.value, "enabled", lookup(access_logs.value, "bucket", null) != null)
bucket  = lookup(access_logs.value, "bucket", null)
prefix  = lookup(access_logs.value, "prefix", null)
}
}
dynamic "subnet_mapping" {
for_each = var.subnet_mapping
content {
subnet_id     = subnet_mapping.value.subnet_id
allocation_id = lookup(subnet_mapping.value, "allocation_id", null)
}
}
tags = merge(
var.tags,
var.lb_tags,
{
Name = var.name != null ? var.name : var.name_prefix
"name" =  var.name != null ? var.name : var.name_prefix
},
)
timeouts {
create = var.load_balancer_create_timeout
update = var.load_balancer_update_timeout
delete = var.load_balancer_delete_timeout
}
}
resource "aws_lb_target_group" "main" {
count = var.create_lb ? length(var.target_groups) : 0
name        = lookup(var.target_groups[count.index], "name", null)
name_prefix = lookup(var.target_groups[count.index], "name_prefix", null)

#vpc_id      = var.vpc_id
vpc_id      = data.aws_vpc.selected.id
port        = lookup(var.target_groups[count.index], "backend_port", null)
protocol    = lookup(var.target_groups[count.index], "backend_protocol", null) != null ? upper(lookup(var.target_groups[count.index], "backend_protocol")) : null
target_type = lookup(var.target_groups[count.index], "target_type", null)
deregistration_delay               = lookup(var.target_groups[count.index], "deregistration_delay", null)
slow_start                         = lookup(var.target_groups[count.index], "slow_start", null)
proxy_protocol_v2                  = lookup(var.target_groups[count.index], "proxy_protocol_v2", false)
lambda_multi_value_headers_enabled = lookup(var.target_groups[count.index], "lambda_multi_value_headers_enabled", false)
load_balancing_algorithm_type      = lookup(var.target_groups[count.index], "load_balancing_algorithm_type", null)
dynamic "health_check" {
for_each = length(keys(lookup(var.target_groups[count.index], "health_check", {}))) == 0 ? [] : [lookup(var.target_groups[count.index], "health_check", {})]
content {
enabled             = lookup(health_check.value, "enabled", null)
interval            = lookup(health_check.value, "interval", null)
path                = lookup(health_check.value, "path", null)
port                = lookup(health_check.value, "port", null)
healthy_threshold   = lookup(health_check.value, "healthy_threshold", null)
unhealthy_threshold = lookup(health_check.value, "unhealthy_threshold", null)
timeout             = lookup(health_check.value, "timeout", null)
protocol            = lookup(health_check.value, "protocol", null)
matcher             = lookup(health_check.value, "matcher", null)
}
}
dynamic "stickiness" {
for_each = length(keys(lookup(var.target_groups[count.index], "stickiness", {}))) == 0 ? [] : [lookup(var.target_groups[count.index], "stickiness", {})]
content {
enabled         = lookup(stickiness.value, "enabled", null)
cookie_duration = lookup(stickiness.value, "cookie_duration", null)
type            = lookup(stickiness.value, "type", null)
}
}
tags = merge(
var.tags,
{"stack-technology"       = "target-group"},
var.target_group_tags,
#lookup(var.target_groups[count.index], "tags", {}),
{
"Name" = format("%s${var.name}", lookup(var.target_groups[count.index], "name_prefix", ""))
"name" =  format("%s${var.name}", lookup(var.target_groups[count.index], "name_prefix", "")) 
},
)
depends_on = [aws_lb.this]
lifecycle {
create_before_destroy = true
}
}
resource "aws_lb_listener_rule" "https_listener_rule" {
count = var.create_lb ? length(var.https_listener_rules) : 0
listener_arn = aws_lb_listener.frontend_https[lookup(var.https_listener_rules[count.index], "https_listener_index", count.index)].arn
priority     = lookup(var.https_listener_rules[count.index], "priority", null)
# authenticate-cognito actions
dynamic "action" {
for_each = [
for action_rule in var.https_listener_rules[count.index].actions :
action_rule
if action_rule.type == "authenticate-cognito"
]
content {
type = action.value["type"]
authenticate_cognito {
authentication_request_extra_params = lookup(action.value, "authentication_request_extra_params", null)
on_unauthenticated_request          = lookup(action.value, "on_authenticated_request", null)
scope                               = lookup(action.value, "scope", null)
session_cookie_name                 = lookup(action.value, "session_cookie_name", null)
session_timeout                     = lookup(action.value, "session_timeout", null)
user_pool_arn                       = action.value["user_pool_arn"]
user_pool_client_id                 = action.value["user_pool_client_id"]
user_pool_domain                    = action.value["user_pool_domain"]
}
}
}
# authenticate-oidc actions
dynamic "action" {
for_each = [
for action_rule in var.https_listener_rules[count.index].actions :
action_rule
if action_rule.type == "authenticate-oidc"
]
content {
type = action.value["type"]
authenticate_oidc {
# Max 10 extra params
authentication_request_extra_params = lookup(action.value, "authentication_request_extra_params", null)
authorization_endpoint              = action.value["authorization_endpoint"]
client_id                           = action.value["client_id"]
client_secret                       = action.value["client_secret"]
issuer                              = action.value["issuer"]
on_unauthenticated_request          = lookup(action.value, "on_unauthenticated_request", null)
scope                               = lookup(action.value, "scope", null)
session_cookie_name                 = lookup(action.value, "session_cookie_name", null)
session_timeout                     = lookup(action.value, "session_timeout", null)
token_endpoint                      = action.value["token_endpoint"]
user_info_endpoint                  = action.value["user_info_endpoint"]
}
}
}
# redirect actions
dynamic "action" {
for_each = [
for action_rule in var.https_listener_rules[count.index].actions :
action_rule
if action_rule.type == "redirect"
]
content {
type = action.value["type"]
redirect {
host        = lookup(action.value, "host", null)
path        = lookup(action.value, "path", null)
port        = lookup(action.value, "port", null)
protocol    = lookup(action.value, "protocol", null)
query       = lookup(action.value, "query", null)
status_code = action.value["status_code"]
}
}
}
# fixed-response actions
dynamic "action" {
for_each = [
for action_rule in var.https_listener_rules[count.index].actions :
action_rule
if action_rule.type == "fixed-response"
]
content {
type = action.value["type"]
fixed_response {
message_body = lookup(action.value, "message_body", null)
status_code  = lookup(action.value, "status_code", null)
content_type = action.value["content_type"]
}
}
}
# forward actions
dynamic "action" {
for_each = [
for action_rule in var.https_listener_rules[count.index].actions :
action_rule
if action_rule.type == "forward"
]
content {
type             = action.value["type"]
target_group_arn = aws_lb_target_group.main[lookup(action.value, "target_group_index", count.index)].id
}
}
# Path Pattern condition
dynamic "condition" {
for_each = [
for condition_rule in var.https_listener_rules[count.index].conditions :
condition_rule
if length(lookup(condition_rule, "path_patterns", [])) > 0
]
content {
path_pattern {
values = condition.value["path_patterns"]
}
}
}
# Host header condition
dynamic "condition" {
for_each = [
for condition_rule in var.https_listener_rules[count.index].conditions :
condition_rule
if length(lookup(condition_rule, "host_headers", [])) > 0
]
content {
host_header {
values = condition.value["host_headers"]
}
}
}
# Http header condition
dynamic "condition" {
for_each = [
for condition_rule in var.https_listener_rules[count.index].conditions :
condition_rule
if length(lookup(condition_rule, "http_headers", [])) > 0
]
content {
dynamic "http_header" {
for_each = condition.value["http_headers"]
content {
http_header_name = http_header.value["http_header_name"]
values           = http_header.value["values"]
}
}
}
}
# Http request method condition
dynamic "condition" {
for_each = [
for condition_rule in var.https_listener_rules[count.index].conditions :
condition_rule
if length(lookup(condition_rule, "http_request_methods", [])) > 0
]
content {
http_request_method {
values = condition.value["http_request_methods"]
}
}
}
# Query string condition
dynamic "condition" {
for_each = [
for condition_rule in var.https_listener_rules[count.index].conditions :
condition_rule
if length(lookup(condition_rule, "query_strings", [])) > 0
]
content {
dynamic "query_string" {
for_each = condition.value["query_strings"]
content {
key   = lookup(query_string.value, "key", null)
value = query_string.value["value"]
}
}
}
}
# Source IP address condition
dynamic "condition" {
for_each = [
for condition_rule in var.https_listener_rules[count.index].conditions :
condition_rule
if length(lookup(condition_rule, "source_ips", [])) > 0
]
content {
source_ip {
values = condition.value["source_ips"]
}
}
}
}

resource "aws_lb_listener" "frontend_http_tcp" {
count = var.create_lb ? length(var.http_tcp_listeners) : 0
load_balancer_arn = aws_lb.this[0].arn
port     = var.http_tcp_listeners[count.index]["port"]
protocol = var.http_tcp_listeners[count.index]["protocol"]
dynamic "default_action" {
for_each = length(keys(var.http_tcp_listeners[count.index])) == 0 ? [] : [var.http_tcp_listeners[count.index]]
# Defaults to forward action if action_type not specified
content {
type             = lookup(default_action.value, "action_type", "forward")
target_group_arn = contains([null, "", "forward"], lookup(default_action.value, "action_type", "")) ? aws_lb_target_group.main[lookup(default_action.value, "target_group_index", count.index)].id : null
dynamic "redirect" {
for_each = length(keys(lookup(default_action.value, "redirect", {}))) == 0 ? [] : [lookup(default_action.value, "redirect", {})]
content {
path        = lookup(redirect.value, "path", null)
host        = lookup(redirect.value, "host", null)
port        = lookup(redirect.value, "port", null)
protocol    = lookup(redirect.value, "protocol", null)
query       = lookup(redirect.value, "query", null)
status_code = redirect.value["status_code"]
}
}
dynamic "fixed_response" {
for_each = length(keys(lookup(default_action.value, "fixed_response", {}))) == 0 ? [] : [lookup(default_action.value, "fixed_response", {})]
content {
content_type = fixed_response.value["content_type"]
message_body = lookup(fixed_response.value, "message_body", null)
status_code  = lookup(fixed_response.value, "status_code", null)
}
}
}
}
}
resource "aws_lb_listener" "frontend_https" {
count = var.create_lb ? length(var.https_listeners) : 0
load_balancer_arn = aws_lb.this[0].arn
port            = var.https_listeners[count.index]["port"]
protocol        = lookup(var.https_listeners[count.index], "protocol", "HTTPS")
certificate_arn = var.https_listeners[count.index]["certificate_arn"]
ssl_policy      = lookup(var.https_listeners[count.index], "ssl_policy", var.listener_ssl_policy_default)
dynamic "default_action" {
for_each = length(keys(var.https_listeners[count.index])) == 0 ? [] : [var.https_listeners[count.index]]
# Defaults to forward action if action_type not specified
content {
type             = lookup(default_action.value, "action_type", "forward")
target_group_arn = contains([null, "", "forward"], lookup(default_action.value, "action_type", "")) ? aws_lb_target_group.main[lookup(default_action.value, "target_group_index", count.index)].id : null
dynamic "redirect" {
for_each = length(keys(lookup(default_action.value, "redirect", {}))) == 0 ? [] : [lookup(default_action.value, "redirect", {})]
content {
path        = lookup(redirect.value, "path", null)
host        = lookup(redirect.value, "host", null)
port        = lookup(redirect.value, "port", null)
protocol    = lookup(redirect.value, "protocol", null)
query       = lookup(redirect.value, "query", null)
status_code = redirect.value["status_code"]
}
}
dynamic "fixed_response" {
for_each = length(keys(lookup(default_action.value, "fixed_response", {}))) == 0 ? [] : [lookup(default_action.value, "fixed_response", {})]
content {
content_type = fixed_response.value["content_type"]
message_body = lookup(fixed_response.value, "message_body", null)
status_code  = lookup(fixed_response.value, "status_code", null)
}
}
# Authentication actions only available with HTTPS listeners
dynamic "authenticate_cognito" {
for_each = length(keys(lookup(default_action.value, "authenticate_cognito", {}))) == 0 ? [] : [lookup(default_action.value, "authenticate_cognito", {})]
content {
# Max 10 extra params
authentication_request_extra_params = lookup(authenticate_cognito.value, "authentication_request_extra_params", null)
on_unauthenticated_request          = lookup(authenticate_cognito.value, "on_authenticated_request", null)
scope                               = lookup(authenticate_cognito.value, "scope", null)
session_cookie_name                 = lookup(authenticate_cognito.value, "session_cookie_name", null)
session_timeout                     = lookup(authenticate_cognito.value, "session_timeout", null)
user_pool_arn                       = authenticate_cognito.value["user_pool_arn"]
user_pool_client_id                 = authenticate_cognito.value["user_pool_client_id"]
user_pool_domain                    = authenticate_cognito.value["user_pool_domain"]
}
}
dynamic "authenticate_oidc" {
for_each = length(keys(lookup(default_action.value, "authenticate_oidc", {}))) == 0 ? [] : [lookup(default_action.value, "authenticate_oidc", {})]
content {
# Max 10 extra params
authentication_request_extra_params = lookup(authenticate_oidc.value, "authentication_request_extra_params", null)
authorization_endpoint              = authenticate_oidc.value["authorization_endpoint"]
client_id                           = authenticate_oidc.value["client_id"]
client_secret                       = authenticate_oidc.value["client_secret"]
issuer                              = authenticate_oidc.value["issuer"]
on_unauthenticated_request          = lookup(authenticate_oidc.value, "on_unauthenticated_request", null)
scope                               = lookup(authenticate_oidc.value, "scope", null)
session_cookie_name                 = lookup(authenticate_oidc.value, "session_cookie_name", null)
session_timeout                     = lookup(authenticate_oidc.value, "session_timeout", null)
token_endpoint                      = authenticate_oidc.value["token_endpoint"]
user_info_endpoint                  = authenticate_oidc.value["user_info_endpoint"]
}
}
}
}
dynamic "default_action" {
for_each = contains(["authenticate-oidc", "authenticate-cognito"], lookup(var.https_listeners[count.index], "action_type", {})) ? [var.https_listeners[count.index]] : []
content {
type             = "forward"
target_group_arn = aws_lb_target_group.main[lookup(default_action.value, "target_group_index", count.index)].id
}
}
}
resource "aws_lb_listener_certificate" "https_listener" {
count = var.create_lb ? length(var.extra_ssl_certs) : 0
listener_arn    = aws_lb_listener.frontend_https[var.extra_ssl_certs[count.index]["https_listener_index"]].arn
certificate_arn = var.extra_ssl_certs[count.index]["certificate_arn"]
}

resource "aws_lb_target_group_attachment" "tgr_attachment" {
depends_on = [aws_lb.this]
for_each = {
for pair in setproduct(keys(tomap({arn = lookup(aws_lb_target_group.main[0],"arn")})),  var.target_id) :
"${pair[0]},${pair[1]}" => {
target_group = aws_lb_target_group.main[0].arn
target       = length(split(":",pair[1])) > 0 ? split(":",pair[1])[0]: null
port         = length(split(":",pair[1])) == 2 ? split(":",pair[1])[1] : null
}
}

target_group_arn = var.create_lb ? each.value.target_group : null
target_id        = var.create_lb ? each.value.target : null
port             = var.create_lb ? each.value.port : null

}

您的错误消息和代码示例似乎并不完整,但尽管如此,我想我还是能看出问题的原因:您试图使用目标组ARN作为aws_lb_target_group_attachment.tgr_attachment的实例密钥的一部分,但ARN不适合用作实例密钥,因为提供程序直到创建每个对象后才知道ARN值,因此它无法在规划过程中预测价值。

相反,我建议将var.target_groups更改为对象映射,而不是对象列表,然后在aws_lb_target_group.main中使用for_each = var.target_groups。因此,模块的调用者可以为每个目标组指定一个有意义的名称,您可以将其用作aws_lb_target_group_attachment.tgr_attachment:的实例密钥的一部分

resource "aws_lb_target_group_attachment" "tgr_attachment" {
for_each = {
for pair in setproduct(keys(aws_lb_target_group.main), var.target_id) :
"${pair[0]},${pair[1]}" => {
target_group_arn = aws_lb_target_group.main[pair[0]].arn
target           = length(split(":",pair[1])) > 0 ? split(":",pair[1])[0]: null
port             = length(split(":",pair[1])) == 2 ? split(":",pair[1])[1] : null
}
}
# ...
}

通过让模块的调用方为每个目标组指定一个键,可以让调用方控制对目标组集合的更改是否应理解为更新现有目标组、创建新目标组或删除现有目标组。

作为一个很好的副作用,您还可以为每个实例获得一个静态和稳定的标识符,这对查看terraform plan输出的人来说是有意义的,并且即使将来的更改导致目标组之一被替换,也会保持一致。

最新更新