我有一个用于部署服务器的模块代码,带有网络的动态块,如下所示
resource "hcloud_server" "this" {
count = var.instance_count
name = "${local.instance_prefix}.${var.instance_name}${format("%02d", count.index + 1)}"
image = data.hcloud_image.image.id
server_type = var.flavour
datacenter = var.datacenter
ssh_keys = var.sshkeys
placement_group_id = hcloud_placement_group.this.id
labels = local.labels_default
firewall_ids = var.firewall_ids
lifecycle {
ignore_changes = [
ssh_keys,
image,
]
}
public_net {
ipv4_enabled = var.public_ipv4
ipv6_enabled = var.public_ipv6
}
dynamic "network" {
for_each = var.network
content {
network_id = lookup(network.value, "network_id")
ip = lookup(network.value, "private_ip", null)
# https://github.com/hetznercloud/terraform-provider-hcloud/issues/650#issuecomment-1497160625
alias_ips = []
}
}
}
根据文档,
network
块有一个名为 ip 的属性,它保存分配的IP,请参阅https://registry.terraform.io/providers/hetznercloud/hcloud/latest/docs/resources/server#network
我想在模块输出中访问这个私有IP,但我无法到达那里。我的输出现在看起来像这样
output "private_ip" {
description = "List with public IPv4 IPs of the instances"
value = hcloud_server.this.*.network[*].ip
}
并产生以下错误
╷
│ Error: Unsupported attribute
│
│ on .terraform/modules/testserver/outputs.tf line 18, in output "private_ip":
│ 18: value = hcloud_server.this.*.network[*].ip
│
│ Can't access attributes on a set of objects. Did you mean to access an attribute across all elements of the set?
如何访问输出中的 ip 属性(最好与实例名称结合使用)?
我尝试使用
*
和 [count.index]
但我没有成功。
感谢您的帮助!
表达式
hcloud_server.this.*.network[*].ip
包含嵌套的splat表达式,这意味着一个“splat”的结果正在被另一个“splat”消耗。因此,了解 Terraform 如何评估这些非常重要。
hcloud_server.this.*.network
生成一个列表,其长度与 hcloud_server.this
的实例数量匹配(在您的情况下为 var.instance_count
),其中每个元素都是相应实例的 network
属性的值。从错误消息中我推断 network
是一组对象,因此 hcloud_server.this.*.network
的结果是对象集的列表。
然后,[*].ip
部分尝试访问该列表中每个元素的
ip
属性。但该列表的元素是对象集而不是单个对象,因此
.ip
访问失败。正如错误消息所述,集合没有任何属性。
ip
块中的所有
network
属性——而不保留有关每个 IP 地址属于哪个实例的任何信息——那么一种合理的方法是使用
flatten
函数将对象集列表转换为对象列表,然后将
[*]
运算符应用于该结果:flatten(hcloud_server.this.*.network)[*].ip
flatten(hcloud_server.this.*.network)
的结果是一个对象列表,丢弃嵌套集合并将所有元素收集到一个列表中。因此,
[*].ip
部分现在可以工作,因为现在可以针对该列表中的每个对象评估.ip
。
请注意,.*
是一个
旧版(仅属性)splat表达式,支持向后兼容旧版本的Terraform,但在本例中不需要,因为现代的
[*]
运算符与我上面写的表达:flatten(hcloud_server.this[*].network)[*].ip
这个修改是不需要的——这个表达式与上面的结果完全相同——但是现代的 splat 运算符对于最近学习 Terraform 的人来说更熟悉,所以我个人更喜欢使用它,除了极少数情况下,我实际上需要
传统运营商的行为略有不同。 (这种情况并不经常发生;这就是为什么它有一个更普遍适用的替代品!)