使用terraform yamldecode访问多级元素

使用terraform yamldecode访问多级元素,yaml,terraform,Yaml,Terraform,我有一个yaml文件(也在azure devops管道中使用,因此需要采用这种格式),其中包含一些我想直接从terraform模块访问的设置 该文件看起来像: variables: - name: tenantsList value: tenanta,tenantb - name: unitName value: canary 我希望有一个这样的模块来访问设置,但我看不到如何进入底层: locals { settings = yamldecode(file("../

我有一个yaml文件(也在azure devops管道中使用,因此需要采用这种格式),其中包含一些我想直接从terraform模块访问的设置

该文件看起来像:

variables:
  - name: tenantsList
    value: tenanta,tenantb
  - name: unitName
    value: canary
我希望有一个这样的模块来访问设置,但我看不到如何进入底层:

locals {
  settings = yamldecode(file("../settings.yml"))
}

module "infra" {
  source = "../../../infra/terraform/"
  unitname = local.settings.variables.unitName
}
但是
地形平面图
错误如下:

Error: Unsupported attribute

  on canary.tf line 16, in module "infra":
  16:   unitname  = local.settings.variables.unitName
    |----------------
    | local.settings.variables is tuple with 2 elements

This value does not have any attributes.

看起来这很困难的主要原因是因为这个YAML文件在逻辑上表示一个映射,但在物理上表示为一个映射的YAML列表

当从这样一个单独的文件中读取数据时,我喜欢编写一个显式表达式来规范化它,并有选择地转换它,以便在Terraform模块的其余部分中更方便地使用。在这种情况下,将
变量
作为地图似乎是地形值最有用的表示形式,因此我们可以编写如下转换表达式:

locals {
  raw_settings = yamldecode(file("${path.module}/../settings.yml"))
  settings = {
    variables = tomap({
      for v in local.raw_settings.variables : v.name => v.value
    })
  }
}
上面使用a将贴图列表投影到单个贴图中,使用
名称
值作为键

将地图列表转换为单个地图后,您可以按照最初尝试的方式访问它:

module "infra" {
  source = "../../../infra/terraform/"
  unitname = local.settings.variables.unitName
}
如果要将变换后的
local.settings
值输出为YAML,它看起来会像这样,这就是现在可以直接访问地图元素的原因:

variables:
  tenantsList: tenanta,tenantb
  unitName: canary
只有当输入中的所有
name
字符串都是唯一的时,这才有效,因为否则每个元素都不会有唯一的映射键



(像这样编写一个规范化表达式也可以作为YAML文件形状的隐式验证:如果
变量
不是一个列表,或者如果值不是所有的类型,那么Terraform将在计算该表达式时引发一个类型错误。即使不需要任何转换,我也喜欢写出这种类型的表达式。)表达式,因为它可以作为YAML文件的预期形状的文档,而不必在其余配置中研究对它的所有引用。)

您的YAML变量
variables
是一个列表,而不是一个映射,因此您需要更改数据结构或以列表的形式访问它。您的意思是
unitname=element(local.settings.variables,1)
吗?因为我尝试过,得到了:
给定的值不适合子模块变量“unitname”在..\\..\infra\terraform\variables.tf:7,1-27:需要字符串。
因此,它似乎没有成功获取值,但很难看到它获取了什么,这将为您提供一个
{name=unitName,value=canary}的映射如果你想要值<代码>加那利< /代码>,那么你会想使用<代码>本地设置。变量1。值。但是这似乎是一种脆弱的访问数据的方式。我会考虑将YAML输入更改为<代码>变量=“TunANSISLIST”=“TANTANA,TANANTB”,“UnITNED”=“金丝雀”}。
这样您就可以通过
local.settings.variables.unitName
访问它,这更清晰。