【问题标题】:Terrafrom dynamic block with dynamic content具有动态内容的 Terraform 动态块
【发布时间】:2021-06-15 03:10:23
【问题描述】:

我正在尝试为 aws_route_table 创建创建一个 terraform 模块,这是此资源定义的示例:

resource "aws_route_table" "example" {
  vpc_id = aws_vpc.example.id

  route {
    cidr_block = "10.0.1.0/24"
    gateway_id = aws_internet_gateway.example.id
  }

  route {
    ipv6_cidr_block        = "::/0"
    egress_only_gateway_id = aws_egress_only_internet_gateway.example.id
  }

  tags = {
    Name = "example"
  }
}

我正在尝试通过使用动态块使其更具动态性。问题是我总是必须在内容块中定义键

resource "aws_route_table" "example" {
...

   dynamic "route" {
        for_each = var.route
        content {
            cidr_block  = route.value.cidr_block  
            gateway_id  = route.value.gateway_id  
        }
    }

...
}

所以在这种情况下,我需要编写两个动态块,一个用于cidr_blockgateway_id 的内容,另一个用于ipv6_cidr_blockegress_only_gateway_id 的内容。

有没有办法在不明确定义键的情况下做到这一点。像这样的:

   dynamic "route" {
        for_each = var.route
        content {
          var.route.map
        }
    }

【问题讨论】:

    标签: amazon-web-services dynamic terraform terraform-provider-aws


    【解决方案1】:

    是的,您可以动态创建route,因为块route 充当Attributes as Blocks。所以你可以做(​​例子)

    # define all your routes in a variable (example content)
    
    variable "routes" {
    
      default = [
        {
          cidr_block = "0.0.0.0/0"
          gateway_id = "igw-0377483faa64bf010"
        },
        {
          cidr_block = "172.31.0.0/20"
          instance_id = "i-043fc97db72ad1b59"     
        }
      ]
    }
    
    
    # need to provide default values (null) for all possibilities
    # in route
    
    locals {
    
      routes_helper = [
          for route in var.routes: merge({
              carrier_gateway_id = null
              destination_prefix_list_id = null
              egress_only_gateway_id = null 
              ipv6_cidr_block = null 
              local_gateway_id = null
              nat_gateway_id = null
              network_interface_id = null
              transit_gateway_id = null 
              vpc_endpoint_id = null 
              instance_id = null
              gateway_id = null
              vpc_peering_connection_id = null
          }, route)
        ]
    
    }
    
    
    resource "aws_route_table" "example" {
      vpc_id = aws_vpc.example.id
    
      # route can be attribute, instead of blocks
      route = local.routes_helper
    
      tags = {
        Name = "example"
      }
    }
    

    文档一般不建议使用它,但我认为 route 是可以接受的一个很好的例子。

    【讨论】:

      【解决方案2】:

      对于 使用“属性作为块”的块类型的一般答案是 Marcin 提到的向后兼容 shim 是依赖于 Terraform 提供者参数没有区别的事实省略参数或将其显式设置为 null 之间的含义。

      这意味着您可以编写一个表达式来决定是否填充特定参数,方法是在适当的情况下使其返回显式null。例如:

        dynamic "route" {
          for_each = var.route
          content {
            cidr_block      = try(route.value.cidr_block, null)
            gateway_id      = try(route.value.gateway_id, null)
            ipv6_cidr_block = try(route.value.ipv6_cidr_block, null)
            # ...
          }
        }
      

      这样的嵌套块更像是一个固定的数据结构而不是一个集合,因此没有任何语法可以动态地构造它。

      话虽如此,在这种特殊情况下,route 正如 Marcin 所指出的那样,实际上实际上只是对象类型的一个属性,Terraform Core 允许将它与块语法一起使用,作为与旧版 Terraform 向后兼容的让步版本。出于这个原因,这两种方法在实践中实际上并没有任何显着差异,但是“属性作为块”机制仅适用于某些情况,其中提供者被设计为承担 Terraform v0.11 验证错误,因此有条件的null 方法我上面描述的是更一般的答案,它也适用于普通的嵌套块。

      【讨论】:

        猜你喜欢
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 2020-08-18
        • 2020-05-30
        • 2020-11-06
        • 2014-05-18
        • 1970-01-01
        相关资源
        最近更新 更多