【问题标题】:Variable keys in terraform maps地形地图中的变量键
【发布时间】:2016-05-31 05:45:42
【问题描述】:

在 Terraform 中,我正在尝试创建一个模块,其中包含一个带有可变键的地图。我不确定这是否可行,但我尝试了以下方法但没有成功。

resource "aws_instance" "web" {
    ami = "${var.base_ami}"
    availability_zone = "${var.region_a}"
    instance_type = "${var.ec2_instance_size}"
    security_groups = ["sec1"]
    count = "${var.ec2_instance_count}"
    tags {
        Name = "${var.role} ${var_env}"
        role = "${var.app_role}"
        ${var.app_role} = "${var_env}"
    }
}

还有这个:

tags {
   Name = "${var.role} ${var_env}"
}
tags."${var.role}" = "${var.env}"

有什么想法吗?目前这在 Terraform 中是不可能的吗?

【问题讨论】:

  • 如果支持这个功能,我会感到非常惊讶。
  • 如果我理解正确,我不相信可以将变量设置为键。不过,Mapping 可以使用变量。另一个例子是here
  • @JoeyP 这个答案stackoverflow.com/a/57401750/2852528 应该被接受

标签: terraform


【解决方案1】:

terraform 插值语法中支持(现在)lookup function,它允许您在地图中查找动态键。

使用它,我现在可以执行以下操作:

output "image_bucket_name" {
  value = "${lookup(var.image_bucket_names, var.environment, "No way this should happen")}"
}

地点:

variable "image_bucket_names" {
  type = "map"

  default = {
    development = "bucket-dev"
    staging = "bucket-for-staging"
    preprod = "bucket-name-for-preprod"
    production = "bucket-for-production"
  }

}

environment 是一个简单的字符串变量。

【讨论】:

    【解决方案2】:

    更新

    接受的答案描述了如何在现有地图中进行动态查找。对于使用动态键构建地图,在 HCL2 (0.12) 中,您可以在键中使用带引号的插值表达式:

    resource "aws_instance" "web" {
      count = "${var.ec2_instance_count}"
      
      ami = "${var.base_ami}"
      availability_zone = "${var.region_a}"
      instance_type = "${var.ec2_instance_size}"
      security_groups = ["sec1"]
    
      tags = {
        Name              = "${var.role} ${var.env}"
        role              = "${var.app_role}"
        "${var.app_role}" = "${var.env}"               # <------ like this
      }
    }
    

    并且一旦issue #21566被修复,就可以将"${var.app_role}"替换为(var.app_role),也就是documentation中描述的方法。

    (以下同样的警告也适用于此处:如果 var.app_role 包含其中一个文字键作为其值,则它将替换它。)

    旧答案

    接受的答案描述了如何在现有地图中进行动态查找。对于使用动态键构建地图,在 HCL2 (0.12) 中,您有两种方法:

    For expressions + merge

    您可以使用 for expressions 为您的键从一个或多个变量动态构建映射,然后将其与 merge function 结合使用以构建包含静态和动态键组合的新映射:

    variable "app_role" {
      type = string
    }
    
    locals {
      tags = merge(
        {
          Name = "${var.role} ${var.env}"
          role = "${var.app_role}"
        },
        {
          for k in [var.app_role]: k => "${var.env}"
        }
      )
    }
    

    zipmap

    或者,您可以使用zipmap 一次性构建它:

    locals {
      tags = zipmap(
        [
           "Name",
           "role",
           var.app_role
        ],
        [
           "${var.role} ${var.env}",
           var.app_role,
           var.env
        ]
      )
    }
    

    然后您可以在资源中使用此地图:

    resource "aws_instance" "web" {
      count = "${var.ec2_instance_count}"
      
      ami = "${var.base_ami}"
      availability_zone = "${var.region_a}"
      instance_type = "${var.ec2_instance_size}"
      security_groups = ["sec1"]
    
      tags = local.tags // or inline the above here
    }
    

    需要注意的是,如果var.app_role 等于"Name""role",那么它将覆盖您的静态值。您可以通过交换 merge 中的参数或重新排序 zipmap 中的列表来避免这种情况,尽管这种冲突很可能是配置错误,应该在应用之前捕获并修复。

    【讨论】:

      【解决方案3】:

      以下适用于 terraform 版本 0.11.7。此解决方案使用map function

      resource "aws_instance" "web" {
        ...
        tags = "${map(
          "Name", "${var.role} ${var_env}",
          "role", "${var.app_role}",
          "${var.app_role}", "${var_env}"
        )}"
      }
      

      【讨论】:

        【解决方案4】:

        我最近也需要动态设置标签键,并设法使用zipmap

        locals {
          ec2_tag_keys = ["some/prefix/${var.some_var}", "another_tag"]
          ec2_tag_vals = ["some value", "another value"]
        }
        
        resource "aws_instance", "foo" {
          ...
          tags = "${zipmap(local.ec2_tag_keys, local.ec2_tag_vals)}"
        }
        

        这有点笨拙,但确实有效。

        【讨论】:

        • 这有助于在数据块中动态设置映射键。非常感谢。
        • 赞成将此作为 terraform 12 deprecated map()
        【解决方案5】:

        我不确定它是何时添加的,但至少从 0.11.7 版本开始,Terraform 支持使用变量作为映射键。这是我当前如何使用它来选择 AWS 实例类型的示例:

        .tf 文件中:

        variable "environment" {}
        
        ...
        
        variable "instance_types_webserver" {
          type = "map"
        
          default = {
            testing    = "t2.small"
            qa         = "t2.medium"
            staging    = "t2.xlarge"
            production = "t2.xlarge"
          }
        }
        
        ...
        
        resource "aws_opsworks_instance" "verification" {
          stack_id      = "${aws_opsworks_stack.verification.id}"
          layer_ids     = ["${aws_opsworks_custom_layer.verification.id}"]
          instance_type = "${var.instance_types_webserver["${var.environment}"]}"
          state         = "running"
          count         = 1
        }
        

        .tfvars 文件中:

        ...
        environment = "testing"
        ...
        

        【讨论】:

          猜你喜欢
          • 2019-11-08
          • 2020-05-09
          • 2023-02-04
          • 1970-01-01
          • 2020-05-10
          • 1970-01-01
          • 1970-01-01
          • 2021-06-22
          • 1970-01-01
          相关资源
          最近更新 更多