>我需要将 map 类型的变量从 terraform 传递到 powershell 用户数据脚本,并能够在 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"}
}
}
初始化.ps1
$hostnames = "${hostnames}"
$environment = "${environment}"
if ($environment -eq "dev"){
# print the value of the dev key in the hostname map here
}
不建议使用template_file数据源。
注意 在 Terraform 0.12 及更高版本中,
templatefile
函数提供了从文件呈现模板的内置机制。请改用该函数,除非您使用的是 Terraform 0.11 或更早版本。
模板文件函数是首选,这就是我的解决方案使用它的原因。
无论哪种情况,模板变量都只支持map(string(。这些值必须是字符串。JSON 可以将任意树结构编码,包括主机名映射为字符串。
在您的地形代码中,使用 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中,使用ConvertFrom-Json cmdlet从JSON解码主机名。
初始化.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 支持通过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,因此您应该使用templatefile
函数而不是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
函数调用会替换它。