无法创建嵌套的动态块

时间:2019-08-20 06:23:52

标签: terraform

我有一组9个安全组规则,需要将它们应用于4个不同的来源。我想将其构建为模块,因此无需将端口和源作为变量传递,而不必多次复制/粘贴同一块。

我尝试创建一个模块,以在动态块中将端口获取为for_each,并通过count传递源,因为我无法通过for_each提供附加的动态块也用于来源。

modules / sg / main.tf

resource "aws_security_group" "test" {
  name = "test2"
  count = length(var.groups)
  vpc_id = var.vpc_id


  dynamic "ingress_tcp" {
    for_each = var.tcp_ports
    content {
      from_port = ingress_tcp.value
      to_port = ingress_tcp.value
      protocol = "tcp"
      security_groups = [var.groups[*].id]
    }
  }
  dynamic "ingress_udp" {
    for_each = var.udp_ports
    content {
      from_port = ingress_udp.value
      to_port = ingress_udp.value
      protocol = "udp"
      security_groups = [var.groups[*].id]
    }
  }
}

main.tf

module "rules" {
  source = "./module/sg"
  vpc_id = var.vpc_id
  name = "tomer-test"
  tcp_ports = var.tcp_ports
  udp_ports = var.udp_ports
  groups = [var.groups[*].id]
}

variables.tf

variable "groups" {
  description = "source groups"
  type = "list"
  default  = [{
    name = "Enforcement-STG",
    id = "sg-c9db2183abcd"
  },
    {
      name = "Managment-STG",
      id = "sg-b0e71dfa123"
  }]
}

variable "name" {
  type = string
}
variable "vpc_id" {
  type = string
  default = ""
}
variable "tcp_ports" {
  description = "tcp ports to open"
  default = [514,1514, 11514, 12514, 6514]
}
variable "udp_ports" {
  description = "tcp ports to open"
  default = [514,1514, 11514, 12514]
}

我接受为每个源组构建一组规则的输出,但是根模块无法调用该模块。 我当前遇到的错误是

terraform plan

Error: Unsupported block type

  on module/sg/main.tf line 7, in resource "aws_security_group" "test":
   7:   dynamic "ingress_tcp" {

Blocks of type "ingress_tcp" are not expected here.


Error: Unsupported block type

  on module/sg/main.tf line 16, in resource "aws_security_group" "test":
  16:   dynamic "ingress_udp" {

Blocks of type "ingress_udp" are not expected here.

1 个答案:

答案 0 :(得分:0)

如错误消息所暗示,您在此处尝试的操作无效,因为ingress_tcp不是aws_security_group资源内部预期的块类型。此嵌套块类型的正确名称为ingress

resource "aws_security_group" "test" {
  count = length(var.groups)

  name = "test2"
  vpc_id = var.vpc_id

  dynamic "ingress" {
    for_each = var.tcp_ports
    content {
      from_port       = ingress.value
      to_port         = ingress.value
      protocol        = "tcp"
      security_groups = var.groups[*].id
    }
  }

  dynamic "ingress" {
    for_each = var.udp_ports
    content {
      from_port       = ingress.value
      to_port         = ingress.value
      protocol        = "udp"
      security_groups = var.groups[*].id
    }
  }
}

如果您使用的是Terraform 0.12.6或更高版本,则可能更喜欢使用资源for_each而不是count来编写,就像这样:

resource "aws_security_group" "test" {
  for_each = { for g in var.groups : g.name => g }

  name = "test2-${each.key}"
  vpc_id = var.vpc_id

  dynamic "ingress" {
    for_each = var.tcp_ports
    content {
      from_port       = ingress.value
      to_port         = ingress.value
      protocol        = "tcp"
      security_groups = var.groups[*].id
    }
  }

  dynamic "ingress" {
    for_each = var.udp_ports
    content {
      from_port       = ingress.value
      to_port         = ingress.value
      protocol        = "udp"
      security_groups = var.groups[*].id
    }
  }
}

这将与您的count示例产生相似的结果,但是将生成地址为aws_security_group.test["Enforcement-STG"]而不是aws_security_group.test[0]的实例,这意味着您在{{ 1}},将来Terraform将能够确定与每个元素对应的实例,而仅添加/删除所需的单个实例。

基于此地图的资源也可能更易于在配置中的其他位置使用,因为您将能够轻松找到每个符号组名称的特定安全组。