如何读取从 terraform 传递到 powershell userdata 脚本的 Map 类型变量的值?

How do I read values of a variable of type Map passed from terraform to powershell userdata script?

我需要将 map 类型的变量从 terraform 传递到 powershell userdata 脚本,并能够在 powershell 脚本中访问地图的键值对。谢谢

userdata.tf

data "template_file" "user_data" {
  template = "${file("${path.module}/init.ps1")}"
  vars = {
    environment = var.env
    # I want to pass the values as shown below
    hostnames   = {"dev":"devhost","test":"testhost","prod":"prodhost"}
  }
}

init.ps1

$hostnames = "${hostnames}"
$environment = "${environment}"

if ($environment -eq "dev"){
   # print the value of the dev key in the hostname map here
}

不鼓励 template_file 数据源。

Note In Terraform 0.12 and later, the templatefile function offers a built-in mechanism for rendering a template from a file. Use that function instead, unless you are using Terraform 0.11 or earlier.

templatefile function 是首选,这就是我的解决方案使用它的原因。

无论哪种情况,模板变量仅支持 map(string)。值 必须 是字符串。 JSON 可以对任意树结构进行编码,包括将主机名映射为字符串。

在您的 terraform 代码中,使用 jsonencode.

将您的 主机名 编码为 JSON

userdata.tf:

locals {
  user_data = templatefile("${path.module}/init.ps1" ,{
    environment = var.env
    # I want to pass the values as shown below
    hostnames   = jsonencode({"dev":"devhost","test":"testhost","prod":"prodhost"})
  })
}

在您的 PowerShell 中,使用 the ConvertFrom-Json cmdlet.

从 JSON 解码您的 主机名

init.ps1:

$hostnames = '${hostnames}' | ConvertFrom-Json
$environment = "${environment}"

if ($environment -eq "dev"){
   # print the value of the dev key in the hostname map here
}

更新:如评论中所述,-AsHashtable 不一定有效,因为它是在 PowerShell 6.0 中添加的。 Windows 10 和 Windows Server 2016 包括 PowerShell 5.1。如果您的映射在键 ({"name" = "foo" ; "Name" = "bar"}) 中仅区分大小写,那么您将需要安装 PowerShell 6.0 或更高版本并使用 ConvertFrom-Json -AsHashtable.

为了在模板结果中包含集合值,您必须决定如何将其表示为字符串,因为模板结果始终是字符串。

PowerShell 通过 the ConvertFrom-Json cmdlet 支持 JSON 编码,因此 JSON 字符串可能是一个不错的选择,尽管它带来了一些挑战,因为您必须确保 JSON字符串作为有效的 PowerShell 表达式写入结果,这意味着我们还必须应用 PowerShell 转义。

综上所述,您可以像这样调整模板:

$hostnames = '${replace(jsonencode(hostnames), "'", "''")}' | ConvertFrom-Json
$environment = '${replace(environment, "'", "''")}'

if ($environment -eq "dev"){
   Write-Output $hostnames["dev"]
}

jsonencode 函数生成给定值的 JSON 编码版本。上面然后将该结果传递给 replace 以便结果中的任何 ' 字符将被转义为 '',然后允许将整个结果放在单引号 ' 中以确保有效的 PowerShell 语法。

渲染模板的结果是这样的:

$hostnames = '{"dev":"devhost","test":"testhost","prod":"prodhost"}' | ConvertFrom-Json -AsHashtable
$environment = 'dev'

if ($environment -eq "dev"){
   Write-Output $hostnames["dev"]
}

您似乎正在使用 Terraform 0.12,因此您应该使用 the templatefile function 而不是 template_file 数据源。该函数更好,因为它可以接受任何类型的值,而数据源只能接受字符串值(因为它是为 Terraform 0.11 设计的)。

要使用 templatefile,请找到您之前引用 data.template_file.user_data 的地方,然后改用 templatefile 函数:

templatefile("${path.module}/init.ps1", {
  environment = var.env
  hostnames   = {"dev":"devhost","test":"testhost","prod":"prodhost"}
})

然后您可以删除 data "template_file" "user_data" 块,因为此 templatefile 函数调用将替换它。