如何将逗号分隔数组传递给 terraform v0.12.0 中的资源?
How can I pass a comma separated array to a resource in terraform v0.12.0?
在下面的代码块中,我试图将一组服务器名称传递给 attributes_json 块:
resource "aws_instance" "consul-server" {
ami = var.consul-server
instance_type = "t2.nano"
key_name = var.aws_key_name
iam_instance_profile = "dna_inst_mgmt"
vpc_security_group_ids = [
"${aws_security_group.yutani_consul.id}",
"${aws_security_group.yutani_ssh.id}"
]
subnet_id = "${aws_subnet.public_1_subnet_us_east_1c.id}"
associate_public_ip_address = true
tags = {
Name = "consul-server${count.index}"
}
root_block_device {
volume_size = "30"
delete_on_termination = "true"
}
connection {
type = "ssh"
user = "chef"
private_key = "${file("${var.aws_key_path}")}"
timeout = "2m"
agent = false
host = self.public_ip
}
count = var.consul-server_count
provisioner "chef" {
attributes_json = <<-EOF
{
"consul": {
"servers": ["${split(",",aws_instance.consul-server[count.index].id)}"]
}
}
EOF
use_policyfile = true
policy_name = "consul_server"
policy_group = "aws_stage_enc"
node_name = "consul-server${count.index}"
server_url = var.chef_server_url
recreate_client = true
skip_install = true
user_name = var.chef_username
user_key = "${file("${var.chef_user_key}")}"
version = "14"
}
}
运行 这给了我一个错误:
Error: Cycle: aws_instance.consul-server[1], aws_instance.consul-server[0]
(这是在 var.consul-server_count 的变量中声明计数为 2 之后)
谁能告诉我正确的方法是什么?
这里有两个问题:(1) 如何在 JSON 字符串中插入 comma-separated 列表;和 (2) 是什么导致了循环依赖错误。
如何对列表进行插值以生成有效的 JSON 数组
使用 jsonencode
最干净的方法是根本不使用 heredoc 而只使用 jsonencode
函数。
你可以这样做:
locals {
arr = ["host1", "host2", "host3"]
}
output "test" {
value = jsonencode(
{
"consul" = {
"servers" = local.arr
}
})
}
这会产生输出:
Outputs:
test = {"consul":{"servers":["host1","host2","host3"]}}
使用 join 函数和 heredoc
Chef provisioner 的文档建议对 JSON 字符串使用 heredoc,因此您也可以这样做:
locals {
arr = ["host1", "host2", "host3"]
sep = "\", \""
}
output "test" {
value = <<-EOF
{
"consul": {
"servers": ["${join(local.sep, local.arr)}"]
}
}
EOF
}
如果我应用:
Outputs:
test = {
"consul": {
"servers": ["host1", "host2", "host3"]
}
}
这里需要注意的一些事情:
您正在尝试加入您的主机,以便它们在 JSON 数组的上下文中变得有效 JSON。您需要使用 ","
来连接它们,而不仅仅是逗号。这就是为什么我定义了一个局部变量 sep = "\", \""
.
当您显然需要 join
时,您似乎正在尝试 split
。
循环依赖问题
错误信息的原因:
Error: Cycle: aws_instance.consul-server[1], aws_instance.consul-server[0]
是不是你有循环依赖。考虑这个简化的例子:
resource "aws_instance" "example" {
count = 3
ami = "ami-08589eca6dcc9b39c"
instance_type = "t2.micro"
user_data = <<-EOF
hosts="${join(",", aws_instance.example[count.index].id)}"
EOF
}
或者您也可以在那里使用 splat 表示法以获得相同的结果,即 aws_instance.example.*.id
。
然后 Terraform 计划产生:
▶ terraform012 plan
...
Error: Cycle: aws_instance.example[2], aws_instance.example[1], aws_instance.example[0]
所以你在那里得到一个循环错误,因为 aws_instance.example.*.id
取决于正在创建的 aws_instance.example
,所以资源取决于它自己。换句话说,您不能在资源本身内部使用资源导出值。
做什么
我对 Consul 了解不多,但我还是有点困惑为什么要在 servers
字段中输入 EC2 实例 ID。 Consul 配置不会期望那里有 IP 地址或主机名吗?
在任何情况下,您可能需要自己计算此资源之外的主机名,作为静态输入参数或您可以以某种方式计算的东西。我想你最终会得到这样的结果:
variable "host_names" {
type = list
default = ["myhost1"]
}
resource "aws_instance" "consul_server" {
...
provisioner "chef" {
attributes_json = jsonencode(
{
"consul" = {
"servers" = var.host_names
}
})
}
}
在下面的代码块中,我试图将一组服务器名称传递给 attributes_json 块:
resource "aws_instance" "consul-server" {
ami = var.consul-server
instance_type = "t2.nano"
key_name = var.aws_key_name
iam_instance_profile = "dna_inst_mgmt"
vpc_security_group_ids = [
"${aws_security_group.yutani_consul.id}",
"${aws_security_group.yutani_ssh.id}"
]
subnet_id = "${aws_subnet.public_1_subnet_us_east_1c.id}"
associate_public_ip_address = true
tags = {
Name = "consul-server${count.index}"
}
root_block_device {
volume_size = "30"
delete_on_termination = "true"
}
connection {
type = "ssh"
user = "chef"
private_key = "${file("${var.aws_key_path}")}"
timeout = "2m"
agent = false
host = self.public_ip
}
count = var.consul-server_count
provisioner "chef" {
attributes_json = <<-EOF
{
"consul": {
"servers": ["${split(",",aws_instance.consul-server[count.index].id)}"]
}
}
EOF
use_policyfile = true
policy_name = "consul_server"
policy_group = "aws_stage_enc"
node_name = "consul-server${count.index}"
server_url = var.chef_server_url
recreate_client = true
skip_install = true
user_name = var.chef_username
user_key = "${file("${var.chef_user_key}")}"
version = "14"
}
}
运行 这给了我一个错误:
Error: Cycle: aws_instance.consul-server[1], aws_instance.consul-server[0]
(这是在 var.consul-server_count 的变量中声明计数为 2 之后)
谁能告诉我正确的方法是什么?
这里有两个问题:(1) 如何在 JSON 字符串中插入 comma-separated 列表;和 (2) 是什么导致了循环依赖错误。
如何对列表进行插值以生成有效的 JSON 数组
使用 jsonencode
最干净的方法是根本不使用 heredoc 而只使用 jsonencode
函数。
你可以这样做:
locals {
arr = ["host1", "host2", "host3"]
}
output "test" {
value = jsonencode(
{
"consul" = {
"servers" = local.arr
}
})
}
这会产生输出:
Outputs:
test = {"consul":{"servers":["host1","host2","host3"]}}
使用 join 函数和 heredoc
Chef provisioner 的文档建议对 JSON 字符串使用 heredoc,因此您也可以这样做:
locals {
arr = ["host1", "host2", "host3"]
sep = "\", \""
}
output "test" {
value = <<-EOF
{
"consul": {
"servers": ["${join(local.sep, local.arr)}"]
}
}
EOF
}
如果我应用:
Outputs:
test = {
"consul": {
"servers": ["host1", "host2", "host3"]
}
}
这里需要注意的一些事情:
您正在尝试加入您的主机,以便它们在 JSON 数组的上下文中变得有效 JSON。您需要使用
","
来连接它们,而不仅仅是逗号。这就是为什么我定义了一个局部变量sep = "\", \""
.当您显然需要
join
时,您似乎正在尝试split
。
循环依赖问题
错误信息的原因:
Error: Cycle: aws_instance.consul-server[1], aws_instance.consul-server[0]
是不是你有循环依赖。考虑这个简化的例子:
resource "aws_instance" "example" {
count = 3
ami = "ami-08589eca6dcc9b39c"
instance_type = "t2.micro"
user_data = <<-EOF
hosts="${join(",", aws_instance.example[count.index].id)}"
EOF
}
或者您也可以在那里使用 splat 表示法以获得相同的结果,即 aws_instance.example.*.id
。
然后 Terraform 计划产生:
▶ terraform012 plan
...
Error: Cycle: aws_instance.example[2], aws_instance.example[1], aws_instance.example[0]
所以你在那里得到一个循环错误,因为 aws_instance.example.*.id
取决于正在创建的 aws_instance.example
,所以资源取决于它自己。换句话说,您不能在资源本身内部使用资源导出值。
做什么
我对 Consul 了解不多,但我还是有点困惑为什么要在 servers
字段中输入 EC2 实例 ID。 Consul 配置不会期望那里有 IP 地址或主机名吗?
在任何情况下,您可能需要自己计算此资源之外的主机名,作为静态输入参数或您可以以某种方式计算的东西。我想你最终会得到这样的结果:
variable "host_names" {
type = list
default = ["myhost1"]
}
resource "aws_instance" "consul_server" {
...
provisioner "chef" {
attributes_json = jsonencode(
{
"consul" = {
"servers" = var.host_names
}
})
}
}