Terraform:如何在对象中定义的aws_实例上循环N次

Terraform:如何在对象中定义的aws_实例上循环N次,terraform,terraform-provider-aws,Terraform,Terraform Provider Aws,我有以下变量 variable "instance_types" { default = { instances : [ { count = 1 name = "control-plane" ami = "ami-xxxxx" instan

我有以下变量

variable "instance_types" {

  default = {

    instances : [
      {
        count                  = 1
        name                   = "control-plane"
        ami                    = "ami-xxxxx"
        instance_type          = "t2.large"
        iam_instance_profile   = "xxx-user"
        subnet_id              = "subnet-xxxxx"
      },
      {
        count                  = 3
        name                   = "worker"
        ami                    = "ami-xxxxx"
        instance_type          = "t2.large"
        iam_instance_profile   = "xxx-user"
        subnet_id              = "subnet-xxxxx"
      }
    ]
  }
}
resource "aws_instance" "k8s-node" {

  # Problem here : How to turn an array of 2 objects into 4 (1 control_plane, 3 workers)
  for_each = {for x in var.instance_types.instances:  x.count => x}

  ami                    = lookup(each.value, "ami")
  instance_type          = lookup(each.value, "instance_type")
  iam_instance_profile   = lookup(each.value, "iam_instance_profile")
  subnet_id              = lookup(each.value, "subnet_id")

  tags = {
    Name      = lookup(each.value, "name")
    Type      = each.key
  }
}
使用以下实例声明(我正在尝试迭代)

目标:
aws\u实例
迭代4次(1个控制平面+3个工作面),并填充
实例类型的索引值


问题:无法正确迭代对象数组并获得所需结果。在典型的编程语言中,这将通过双for循环实现。

对于输入变量,使用数据类型
map(object))
可以更容易地解决这一问题。转换后的数据结构如下所示:

variable "instance_types" {
  ...
  default = {
    "control-plane" = {
      count                  = 1
      ami                    = "ami-xxxxx"
      instance_type          = "t2.large"
      iam_instance_profile   = "xxx-user"
      subnet_id              = "subnet-xxxxx"
    },
    "worker" = {
      count                  = 3
      ami                    = "ami-xxxxx"
      instance_type          = "t2.large"
      iam_instance_profile   = "xxx-user"
      subnet_id              = "subnet-xxxxx"
    }
  }
}
注意
对象
中的
名称
键包含在
映射
键中,以提高效率和清洁度

如果资源在控制平面和工作节点之间分割,那么我们就完成了,可以立即在
中为每个
元参数利用此变量的值。但是,组合这些资源现在需要进行数据转换:

locals {
  instance_types = flatten([ # need this for final structure type
    for instance_key, instance in var.instance_types : [ # iterate over variable input objects
      for type_count in range(1, instance.count + 1) : { # sub-iterate over objects by "count" value specified; use range function and begin at 1 for human readability
        new_key              = "${instance_key} ${type_count}" # for resource uniqueness
        type                 = instance_key # for easier tag value later
        ami                  = instance.ami # this and below retained from variable inputs
        instance_type        = instance.instance_type
        iam_instance_profile = instance.iam_instance_profile
        subnet_id            = instance.subnet_id
      }
    ]
  ])
}
现在,我们可以在资源中使用
for_每个
元参数进行迭代,并利用
for
表达式重建输入,以便在资源中使用

resource "aws_instance" "k8s-node" {
  # local.instance_types is a list of objects, and we need a map of objects with unique resource keys
  for_each = { for instance_type in local.instance_types : instance_type.new_key => instance_type }

  ami                  = each.value.ami
  instance_type        = each.value.instance_type
  iam_instance_profile = each.value.iam_instance_profile
  subnet_id            = each.value.subnet_id

  tags = {
    Name = each.key
    Type = each.value.type
  }
}
这将为您提供所需的行为,您可以根据需要根据样式首选项或不同用途对其进行修改

请注意,
查找
函数被删除,因为它们仅在将默认值指定为第三个参数时才有用,并且这在变量声明中的对象类型中是不可能的,除非作为0.14中的实验功能

这些资源的导出资源属性的绝对命名空间为:

(module?.<declared_module_name>?.)<resource_type>.<resource_name>[<resource_key>].<attribute>
注意:您还可以通过在
处终止名称空间来访问所有资源的导出属性(保留所有资源的映射,而不是访问单个资源值)。然后,您还可以在
output
声明中使用
for
表达式,为所有类似资源及其相同的导出属性创建自定义聚合输出


使用
map(object))
键入并使用
count
作为键,而不是使用
映射(list(object))
进行表达式数据转换,这将非常容易。有什么东西妨碍你选择那种类型吗?没有,我可以随意改变对象结构。请在您的建议中说明如何实现这一点。请记住,对象不是一个详尽的列表。同样数量的countsOk可能会有更多,所以我现在更清楚地看到了你想要实现的目标。您希望将k8s工作节点和控制平面节点概括为单个TF AWS实例资源。我的评论现在稍微不那么有效,但不管怎么说,答案都是一样的。再次键入实例数是不够的,因为这两个之外的几种不同的实例类型将包含在这张地图中,不确定这与我解释前进道路的评论有何关系,但答案将很快完成。现在尝试一下-非常感谢response@stackoverflow我知道必须进行数据转换才能生成这样的嵌套迭代器看起来有多烦人,但在本机功能存在之前(希望很快)它实际上是有文档记录的算法:@stackoverflow Total brain fart on my part for映射变量上的for表达式中的临时lambda迭代器作用域变量。Answer已修复。@stackoverflow已添加到Answer中。@stackoverflow否,splat运算符
*
用于转换<0.12版本中的列表。
aws_instance.k8s-node["worker 1"].private_ip
{ for node_key, node in aws_instance.k8s-node : node_key => node.private_ip }