Terraform – 引用由 ‘count’ 创建的特定资源的值

huangapple go评论57阅读模式
英文:

Terraform - reference specific resource that was created by 'count' by a value

问题

在我的Terraform代码中,我正在使用count创建多个vnet中的子网。这很有效,但现在我想在另一个资源中引用子网ID。我可以通过使用:

azurerm_subnet.subnets[1].id

来实现这一点,但这不是很方便,我想要做的是,不是给出索引号,而是给出应该匹配的名称值,类似于这样:

azurerm_subnet.subnets['where name = applicationsubnet'].id

有这样的选项吗?

谢谢!

英文:

In my Terraform code, I'm using a count to create multiple subnets in a vnet. This works great, but now, I want to reference the subnet ID in another resource. I can do this by using:

azurerm_subnet.subnets[1].id

but that's not very handy, something I would like to do is, instead of giving the index number, giving a name value it should match, something like this:

azurerm_subnet.subnets['where name = applicationsubnet'].id

Is there an option to do this?

Thanks!

答案1

得分: 3

> 有这样的选项吗?

不,没有这样的选项。您能做的最接近的是通过迭代。一个伪代码示例:

subnet_id = [for subnet in azurerm_subnet.subnets: subnet.id if subnet.name == "applicationsubnet"][0]

否则,不要使用 count,而是使用基于 name 的键来使用 for_each

英文:

> Is there an option to do this?

No, there is no such option. The closes you can get is by iteration. En example of a pseudo-code:

subnet_id = [for subnet in azurerm_subnet.subnets: subnet.id if subnet.name == "applicationsubnet"][0]

Otherwise, instead of count use for_each with keys based on name.

答案2

得分: 2

当您使用 count 时,这意味着您声明的所有实例是可以互换的,因此想要通过其属性之一选择一个项目就显得不寻常,因为这表明该实例有一些特殊之处。这可能会带来问题,因为 Terraform 不理解该实例有什么特殊之处,因此如果将来更改 count,可能会建议删除“错误的实例”。

对于那些实例之间存在某些有意义的差异的情况,通常最好使用 for_each,并将映射键设置为您想要查找实例的内容。例如:

variable "subnets" {
  type = map(object({
    cidr_block = string
  }))
}

resource "azurerm_subnet" "example" {
  for_each = var.subnets

  address_space = [each.value.cidr_block]
}

如果您将 var.subnets 设置为如下内容...

{
  "applicationsubnet" = {
    cidr_block = "10.0.0.0/16"
  }
}

...那么您将会有一个资源的实例称为 azurerm_subnet.example["applicationsubnet"],因此您可以使用该实例键进行查找。

此外,如果例如更改此映射中某个对象的 cidr_block,Terraform 将使用映射键来了解您计划更改的资源实例,并因此计划仅更新该资源。如果从此映射中删除一个元素,将删除具有相同键的实例。


如果您的情况是不寻常的,以至于在这里使用 count 是适当的,但仍然需要根据名称进行查找,您可以使用 for 表达式count 生成的列表中导出一个映射:

locals {
  subnets_by_name = tomap({
    for sn in azurerm_subnet.example : sn.name => sn
  })
}

然后,您可以引用 local.subnets_by_name["applicationsubnet"] 来查找具有该名称的子网对象。

但是,Terraform 仍然会跟踪具有类似 azurerm_subnet.example[0] 的资源实例,因此您可能需要在随着时间修改原始资源时注意确保实例键(如 0)与名称(如 "applicationsubnet")之间的关系保持恒定。

英文:

When you use count this suggests that all of the instances you are declaring are interchangable and thus it's unusual to then want to select an item by one of its attributes, because that suggests there's something special about that instance. That can be problematic because Terraform doesn't understand that there's something special about that instance and so if you change the count in future "the wrong instance" might get proposed for deletion.

For situations where there's some meaningful difference between your instances it's often better to use for_each and set the map keys to something that you'd want to look up the instances by. For example:

variable "subnets" {
  type = map(object({
    cidr_block = string
  }))
}

resource "azurerm_subnet" "example" {
  for_each = var.subnets

  address_space = [each.value.cidr_block]
}

If you were to set var.subnets like this...

{
  "applicationsubnet" = {
    cidr_block = "10.0.0.0/16"
  }
}

...then you would have an instance of the resource called aws_subnet.example["applicationsubnet"], and so you can look it up using that instance key.

Furthermore, if you for example change the cidr_block of one of the objects in this map later Terraform will use the map keys to understand which resource instance you were planning to change and thus plan to update that one only. If you remove an element from this map, the instance with the same key will be removed.


If your situation is unusual such that count is an appropriate thing to use here but yet you still need to look up by name anyway, you can use a for expression to derive a map from the list produced by count:

locals {
  subnets_by_name = tomap({
    for sn in azurerm_subnet.example : sn.name => sn
  })
}

You can then refer to local.subnets_by_name["applicationsubnet"] to look up the subnet object with that name.

However, Terraform will still track the instances of that resource with addresses like azurerm_subnet.example[0] and so you may need to take care with how you modify the original resource over time to make sure that the relationships between the instance keys like 0 and the names like "applicationsubnet" stay constant.

huangapple
  • 本文由 发表于 2023年6月22日 17:43:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76530568.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定