英文:
Combining locals and variables
问题
尝试在变量定义中使用本地变量似乎不起作用,是否知道原因或如何解决?
locals {
project_id = {
dev = "dev01-a7"
prod = "prd01-b2"
}
}
variable "project_id" {
default = local.project_id[terraform.workspace]
}
provider "google" {
project = var.project_id
region = var.region
credentials = "xx.json"
}
错误:
│ 错误: 不允许使用变量
│
│ 在 main.tf 的第 13 行,位于 variable "project_id":
│ 13: default = local.project_id[terraform.workspace]
│
│ 此处不允许使用变量。
╵
╷
│ 错误: 不允许使用变量
│
│ 在 main.tf 的第 13 行,位于 variable "project_id":
│ 13: default = local.project_id[terraform.workspace]
│
│ 此处不允许使用变量。
英文:
I try to use a local inside the definition of a variable but it does not seems to work, do you know why or how to do it ?
The goal behind that is it keep the possibilty for user to override default value with it's own without editing the tf file
locals {
project_id = {
dev = "dev01-a7"
prod = "prd01-b2"
}
}
variable "project_id" {
default = local.project_id[terraform.workspace]
}
provider "google" {
project = var.project_id
region = var.region
credentials = "xx.json"
}
Error :
│ Error: Variables not allowed
│
│ on main.tf line 13, in variable "project_id":
│ 13: default = local.project_id[terraform.workspace]
│
│ Variables may not be used here.
╵
╷
│ Error: Variables not allowed
│
│ on main.tf line 13, in variable "project_id":
│ 13: default = local.project_id[terraform.workspace]
│
│ Variables may not be used here.
答案1
得分: 1
这不能按照你尝试的方式完成,但你可以使用类似的引用正确配置文件的方法:
locals {
project_id = {
dev = "dev01-a7"
prod = "prd01-b2"
}
}
provider "google" {
project = local.project_id[terraform.workspace]
region = var.region
credentials = "xx.json"
}
英文:
That cannot be done the way you are trying, but you can use a similar way of referencing the correct profile:
locals {
project_id = {
dev = "dev01-a7"
prod = "prd01-b2"
}
}
provider "google" {
project = local.project_id[terraform.workspace]
region = var.region
credentials = "xx.json"
}
答案2
得分: 1
以下是您要的翻译内容:
输入变量的默认值必须始终是调用模块的人可以在其自己的module
块中编写的内容;不能从调用模块的子模块内部的信息构建,调用模块的人无法引用该信息。
然而,默认值并不是提供后备选项的唯一方法,您可以在模块内使用表达式来描述当变量被设置与未被设置时,Terraform应该采取的行为。例如:
variable "project_id" {
type = string
# 这使变量是可选的,而不需要明确的默认值。
default = null
}
locals {
default_project_ids = tomap({
dev = "dev01-a7"
prod = "prd01-b2"
})
project_id = coalesce(
var.project_id,
local.default_project_ids[terraform.workspace],
)
}
provider "google" {
project = local.project_id
region = var.region
credentials = "xx.json"
}
上述内容的重点是:
- 变量的默认值是
null
,这意味着它是可选的,但对于模块的用户来说,没有明确的默认值可见,当变量未设置时,var.project_id
将为null。 - 本地值
project_id
使用coalesce
来选择其参数中的第一个非null参数。这意味着如果var.project_id
被设置,那么local.project_id
将正好是该值,如果未设置,则Terraform将使用local.default_project_ids
中的适当条目作为后备。 provider "google"
块的project
参数现在引用local.project_id
,而不是var.project_id
,因此可以从默认值中受益。
请注意,在子模块中使用terraform.workspace
而不是根模块稍微存在一定的可维护性风险,因为工作区概念上属于每个根模块,因此在共享模块中直接依赖于工作区名称将使其无法从具有不同工作区命名方案的不同根模块中重用该模块。
如果这对您的情况不是问题,那么您使用terraform.workspace
的方法是有效的,并且将起作用,但如果您想要更强的关注分离,我建议调用者传递一个环境名称,由调用者决定如何确定该名称:
variable "environment" {
type = string
validation {
condition = contains(["dev", "prod"], var.environment)
error_message = "必须是“dev”或“prod”."
}
}
# ...
locals {
default_project_ids = tomap({
dev = "dev01-a7"
prod = "prd01-b2"
})
project_id = coalesce(
var.project_id,
local.default_project_ids[var.environment],
)
}
# ...
然后,模块的调用者可以决定将其工作区用作环境名称的决定者:
module "example" {
# ...
environment = terraform.workspace
}
英文:
The default value for an input variable must always be something that the caller of the module could have written in their own module
block; it cannot be built from information inside the child module that the caller of the module would not be able to refer to.
However, default values aren't the only way to provide a fallback when something isn't set. You can use expressions within your module to describe to Terraform what behavior you intend when the variable is set vs. not set. For example:
variable "project_id" {
type = string
# This makes the variable optional without
# specifying an explicit default.
default = null
}
locals {
default_project_ids = tomap({
dev = "dev01-a7"
prod = "prd01-b2"
})
project_id = coalesce(
var.project_id,
local.default_project_ids[terraform.workspace],
)
}
provider "google" {
project = local.project_id
region = var.region
credentials = "xx.json"
}
The important parts of the above:
- The variable's default value is
null
, which means that it's optional but it doesn't have an explicit default that's visible to the user of the module, andvar.project_id
will be null when the variable isn't set. - The local value
project_id
usescoalesce
to choose the first of its arguments that isn't null. This means that ifvar.project_id
is set thenlocal.project_id
will be exactly that value, while if it isn't set then Terraform will use the appropriate entry fromlocal.default_project_ids
as a fallback. - The
provider "google"
block'sproject
argument now refers tolocal.project_id
instead ofvar.project_id
, so it can benefit from the fallback to the default.
Note that using terraform.workspace
in a child module rather than a root module is a bit of a maintainability hazard, because workspaces conceptually belong to each root module separately and so relying directly on workspace names in a shared module will make it impossible to reuse that module from a different root module that has a different naming scheme for its workspaces.
If that isn't a concern for your situation then what you did with terraform.workspace
is valid and will work, but if you want to employ a stronger separation of concerns then I'd suggest a variant where the caller passes in an environment name and it's up to the caller to decide how it will determine that:
variable "environment" {
type = string
validation {
condition = contains(["dev", "prod"], var.environment)
error_message = "Must be \"dev\" or \"prod\"."
}
}
# ...
locals {
default_project_ids = tomap({
dev = "dev01-a7"
prod = "prd01-b2"
})
project_id = coalesce(
var.project_id,
local.default_project_ids[var.environment],
)
}
# ...
Then the caller of the module can be the one to decide that it will use its workspaces as the determinant for the environment name:
module "example" {
# ...
environment = terraform.workspace
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论