Переменные ключи на картах террафорт
В 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 в настоящее время?
Ответы
Ответ 1
Я знаю, что прошло много времени с тех пор, как вы отправили сообщение, но недавно мне понадобилось нечто подобное, поэтому я выкладываю решение здесь, на случай, если кто-нибудь еще наткнется на него.
В синтаксисе интерполяции терраформ теперь поддерживается функция lookup
, которая позволяет вам искать динамические ключи на карте.
Используя это, я теперь могу делать что-то вроде:
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
Следующее работает с terraform версии 0.11.7. В этом решении используется функция отображения.
resource "aws_instance" "web" {
...
tags = "${map(
"Name", "${var.role} ${var_env}",
"role", "${var.app_role}",
"${var.app_role}", "${var_env}"
)}"
}
Ответ 3
Недавно мне также нужно было установить динамический ключ, и ему удалось сделать это с помощью 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)}"
}
Это немного неуклюже, но он работает.
Ответ 4
Эта функция еще не поддерживается.
Ответ 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"
...
Ответ 6
Обновление
Принятый ответ описывает, как выполнять динамический поиск на существующей карте. Для построения карт с динамическими ключами в 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
}
}
И как только проблема # 21566 будет устранена, вы можете заменить "${var.app_role}"
на (var.app_role)
, что является методом, описанным в документации.
(Та же оговорка, что и ниже, применима и здесь: если var.app_role
содержит один из этих литеральных ключей в качестве значения, он заменит его.)
Старый ответ
Принятый ответ описывает, как выполнять динамический поиск на существующей карте. Для построения карт с динамическими ключами в HCL2 (0.12) у вас есть два способа:
Вы можете использовать для выражений для динамического построения карты из одной или нескольких переменных для ваших ключей, а затем использовать это в сочетании с функцией merge
для создания новой карты с сочетание статических и динамических ключей:
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
, чтобы создать его за один раз:
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
, хотя такое коллизия, скорее всего, будет ошибкой конфигурации, которая должна быть обнаружена & исправлено перед применением.