Terraform:如何在“ for_each”中使用多个局部变量和变量

时间:2020-01-24 08:15:36

标签: terraform terraform-provider-aws terraform-template-file

我有一个可创建多个EC2实例的Terraform模板。 然后,我在AWS控制台中创建了一些Elastic Network接口,并将它们作为本地添加到terraform模板中。 现在,我想将适当的ENI映射到实例,因此我如下添加了局部变量和变量。

locals {
  instance_ami = {
    A  = "ami-11111"
    B = "ami-22222"
    C  = "ami-33333"
    D   = "ami-4444"
  }
}

variable "instance_eni" {
  description = "Pre created Network Interfaces"
  default = [
    {
      name = "A"
      id   = "eni-0a15890a6f567f487"
    },
    {
      name = "B"
      id   = "eni-089a68a526af5775b"
    },
    {
      name = "C"
      id   = "eni-09ec8ad891c8e9d91"
    },
    {
      name = "D"
      id   = "eni-0fd5ca23d3af654a9"
    }
  ]
}


resource "aws_instance" "instance" {
  for_each = local.instance_ami

  ami           = each.value
  instance_type = var.instance_type
  key_name      = var.keypair

  root_block_device {
    delete_on_termination = true
    volume_size           = 80
    volume_type           = "gp2"
  }


  dynamic "network_interface" {
    for_each = [for eni in var.instance_eni : {
      eni_id = eni.id
    }]

    content {
      device_index          = 0
      network_interface_id  = network_interface.value.eni_id
      delete_on_termination = false
    }
  }
}

我遇到以下错误:

错误:启动源实例时出错:InvalidParameterValue:每个网络接口都需要一个 唯一设备索引。 状态码:400,请求ID:4a482753-bddc-4fc3-90f4-2f1c5e2472c7

我认为terraform试图将所有4个ENI仅附加到单个实例。 将ENI附加到单个实例应该怎么做?

1 个答案:

答案 0 :(得分:0)

您在问题中共享的配置要求Terraform管理四个实例,每个实例都有四个与之关联的网络接口。这有两种不同的问题:

  • 每个实例上的所有网络接口均配置有相同的device_index,这是无效的,也是这里的错误消息所报告的。
  • 即使您要解决此问题,它也会尝试将相同的四个网络接口连接到四个不同的EC2实例,这是无效的:每个网络接口一次只能连接一个实例。

要解决该问题并获得所需的行为,您只需要一个network_interface块,每个实例的内容都不同:

locals {
  instance_ami = {
    A = "ami-11111"
    B = "ami-22222"
    C = "ami-33333"
    D = "ami-4444"
  }
}

variable "instance_eni" {
  description = "Pre created Network Interfaces"
  default = [
    {
      name = "A"
      id   = "eni-0a15890a6f567f487"
    },
    {
      name = "B"
      id   = "eni-089a68a526af5775b"
    },
    {
      name = "C"
      id   = "eni-09ec8ad891c8e9d91"
    },
    {
      name = "D"
      id   = "eni-0fd5ca23d3af654a9"
    }
  ]
}

locals {
  # This expression is transforming the instance_eni
  # value into a more convenient shape: a map from
  # instance key to network interface id. You could
  # also choose to just change directly the
  # definition of variable "instance_eni" to already
  # be such a map, but I did it this way to preserve
  # your module interface as given.
  instance_network_interfaces = {
    for ni in var.instance_eni : ni.name => ni.id
  }
}

resource "aws_instance" "instance" {
  for_each = local.instance_ami

  ami           = each.value
  instance_type = var.instance_type
  key_name      = var.keypair

  root_block_device {
    delete_on_termination = true
    volume_size           = 80
    volume_type           = "gp2"
  }

  network_interface {
    device_index          = 0
    network_interface_id  = local.instance_network_interfaces[each.key]
    delete_on_termination = false
  }
}

现在每个实例只有一个一个网络接口,每个实例都附加到输入变量中提供的相应ENI ID上。引用each.keyeach.value是如何在使用资源for_each时在声明的每个实例之间创建差异;除非我们要创建嵌套的重复,例如每个实例具有动态数量的网络接口,否则我们不需要任何其他重复结构。