使用 for-each 将模块中的值映射到输出
Map value in module with for-each to output
我有一个模块可以为姓名列表创建多个资源。因此,对于名为 instances
的变量中提供的每个名称,都会创建一组资源(虚拟机、端口、卷)。
在该模块的输出中,我想要一个映射,它将实例(instances
中的每个值)映射到关联端口的 IP。
这是端口的定义
resource "openstack_networking_port_v2" "this" {
for_each = var.instances
name = "port-${each.key}"
network_id = var.network_id
admin_state_up = true
security_group_ids = var.security_group_ids
fixed_ip {
subnet_id = var.subnet_id
}
}
到目前为止,我在模块的输出中有这个
output "int-port" {
value = openstack_networking_port_v2.this
}
这是我用过的地方
int-ip : module.my-instance.int-port["${var.deployment}-my-01"].all_fixed_ips[0]
升级terraform后,我需要在输出中添加sensitive = true
,因为openstack提供者已经将一些东西标记为敏感,这将导致输出不被打印。 (我知道我可以用 terraform output -json
得到它)
所以我只想在输出中 return 我需要的 IP,而不是整个对象,但我不知道怎么做。
我尝试了以下操作:
output "int-ip" {
value = openstack_networking_port_v2.this.*.all_fixed_ips[0]
}
和
output "int-ip" {
value = openstack_networking_port_v2.this[*].all_fixed_ips[0]
}
这给了我
│ Error: Unsupported attribute
│
│ on ../../modules/ext-instance-v2/outputs.tf line 24, in output "int-port":
│ 24: value = openstack_networking_port_v2.this.*.all_fixed_ips[0]
│
│ This object does not have an attribute named "all_fixed_ips".
我也试过了
output "int-ip" {
value = {
for instance in var.instances:
instance => openstack_networking_port_v2.this["${instance}"].all_fixed_ips[0]
}
}
和
output "int-ip" {
value = {
for instance in var.instances:
instance => openstack_networking_port_v2.this[instance].all_fixed_ips[0]
}
}
导致该错误
│ Error: Invalid index
│
│ on ../../modules/ext-instance-v2/outputs.tf line 19, in output "int-ip":
│ 19: instance => openstack_networking_port_v2.this["${instance}"].all_fixed_ips[0]
│ ├────────────────
│ │ openstack_networking_port_v2.this is object with 9 attributes
│
│ The given key does not identify an element in this collection value.
感觉很亲近,但又遥不可及
我不仅对解决方案感兴趣,而且对为什么我尝试过的事情没有成功的解释感兴趣。
由于 for_each
,您的 openstack_networking_port_v2.this
是 map,它应该是:
output "int-ip" {
value = values(openstack_networking_port_v2.this)[*].all_fixed_ips[0]
}
更新
根据评论。最后一次尝试的正确方法是:
output "int-ip" {
value = {
for instance in keys(var.instances):
instance => openstack_networking_port_v2.this[instance].all_fixed_ips[0]
}
}
这是必需的,因为 instances
是地图,但您需要一个列表。在这种情况下,您想使用 for-each 中的键列表。
[*]
运算符 (Splat operator) is designed for producing lists only. The documentation says the following about splat expressions on maps:
The splat expression patterns shown above apply only to lists, sets, and tuples. To get a similar result with a map or object value you must use for
expressions.
Resources that use the for_each
argument will appear in expressions as a map of objects, so you can't use splat expressions with those resources. For more information, see Referring to Resource Instances.
使用 for
表达式的最简单版本如下:
output "int-ip" {
value = {
for k, port in openstack_networking_port_v2.this : k => port.all_fixed_ips[0]
}
}
这意味着构建一个新的映射,其中 openstack_networking_port_v2.this
(对象映射)的每个元素都被转换为具有相同键但 只是 的元素第一个 IP 地址作为值。
我上面的示例与您问题中的示例的一个重要区别是 for
子句有两个符号:k, port
。意思是把每个元素的key放在k
中,把每个元素的value放在port
中。如果你只写一个符号,比如 for port
,那么 Terraform 会将它绑定到每个元素的 value 而不是键,并且没有直接的方法来找到key对应一个特定的值,只能找到一个key对应的值。
原则上也可以使用the keys
function特别重复键,然后使用键查找元素:
output "int-ip" {
value = {
for k in keys(openstack_networking_port_v2.this) : k => openstack_networking_port_v2.this[k].all_fixed_ips[0]
}
}
这等同于我上面显示的另一个 for
表达式,但由于需要引用 openstack_networking_port_v2.this
两次,因此更加冗长。因此,我更喜欢双符号 for
,尤其是在这种情况下,映射的表达式中包含大量字符。
我有一个模块可以为姓名列表创建多个资源。因此,对于名为 instances
的变量中提供的每个名称,都会创建一组资源(虚拟机、端口、卷)。
在该模块的输出中,我想要一个映射,它将实例(instances
中的每个值)映射到关联端口的 IP。
这是端口的定义
resource "openstack_networking_port_v2" "this" {
for_each = var.instances
name = "port-${each.key}"
network_id = var.network_id
admin_state_up = true
security_group_ids = var.security_group_ids
fixed_ip {
subnet_id = var.subnet_id
}
}
到目前为止,我在模块的输出中有这个
output "int-port" {
value = openstack_networking_port_v2.this
}
这是我用过的地方
int-ip : module.my-instance.int-port["${var.deployment}-my-01"].all_fixed_ips[0]
升级terraform后,我需要在输出中添加sensitive = true
,因为openstack提供者已经将一些东西标记为敏感,这将导致输出不被打印。 (我知道我可以用 terraform output -json
得到它)
所以我只想在输出中 return 我需要的 IP,而不是整个对象,但我不知道怎么做。
我尝试了以下操作:
output "int-ip" {
value = openstack_networking_port_v2.this.*.all_fixed_ips[0]
}
和
output "int-ip" {
value = openstack_networking_port_v2.this[*].all_fixed_ips[0]
}
这给了我
│ Error: Unsupported attribute
│
│ on ../../modules/ext-instance-v2/outputs.tf line 24, in output "int-port":
│ 24: value = openstack_networking_port_v2.this.*.all_fixed_ips[0]
│
│ This object does not have an attribute named "all_fixed_ips".
我也试过了
output "int-ip" {
value = {
for instance in var.instances:
instance => openstack_networking_port_v2.this["${instance}"].all_fixed_ips[0]
}
}
和
output "int-ip" {
value = {
for instance in var.instances:
instance => openstack_networking_port_v2.this[instance].all_fixed_ips[0]
}
}
导致该错误
│ Error: Invalid index
│
│ on ../../modules/ext-instance-v2/outputs.tf line 19, in output "int-ip":
│ 19: instance => openstack_networking_port_v2.this["${instance}"].all_fixed_ips[0]
│ ├────────────────
│ │ openstack_networking_port_v2.this is object with 9 attributes
│
│ The given key does not identify an element in this collection value.
感觉很亲近,但又遥不可及
我不仅对解决方案感兴趣,而且对为什么我尝试过的事情没有成功的解释感兴趣。
由于 for_each
,您的 openstack_networking_port_v2.this
是 map,它应该是:
output "int-ip" {
value = values(openstack_networking_port_v2.this)[*].all_fixed_ips[0]
}
更新
根据评论。最后一次尝试的正确方法是:
output "int-ip" {
value = {
for instance in keys(var.instances):
instance => openstack_networking_port_v2.this[instance].all_fixed_ips[0]
}
}
这是必需的,因为 instances
是地图,但您需要一个列表。在这种情况下,您想使用 for-each 中的键列表。
[*]
运算符 (Splat operator) is designed for producing lists only. The documentation says the following about splat expressions on maps:
The splat expression patterns shown above apply only to lists, sets, and tuples. To get a similar result with a map or object value you must use
for
expressions.Resources that use the
for_each
argument will appear in expressions as a map of objects, so you can't use splat expressions with those resources. For more information, see Referring to Resource Instances.
使用 for
表达式的最简单版本如下:
output "int-ip" {
value = {
for k, port in openstack_networking_port_v2.this : k => port.all_fixed_ips[0]
}
}
这意味着构建一个新的映射,其中 openstack_networking_port_v2.this
(对象映射)的每个元素都被转换为具有相同键但 只是 的元素第一个 IP 地址作为值。
我上面的示例与您问题中的示例的一个重要区别是 for
子句有两个符号:k, port
。意思是把每个元素的key放在k
中,把每个元素的value放在port
中。如果你只写一个符号,比如 for port
,那么 Terraform 会将它绑定到每个元素的 value 而不是键,并且没有直接的方法来找到key对应一个特定的值,只能找到一个key对应的值。
原则上也可以使用the keys
function特别重复键,然后使用键查找元素:
output "int-ip" {
value = {
for k in keys(openstack_networking_port_v2.this) : k => openstack_networking_port_v2.this[k].all_fixed_ips[0]
}
}
这等同于我上面显示的另一个 for
表达式,但由于需要引用 openstack_networking_port_v2.this
两次,因此更加冗长。因此,我更喜欢双符号 for
,尤其是在这种情况下,映射的表达式中包含大量字符。