Как я могу передать массив через запятую ресурсу в terraform v0.12.0? - PullRequest
1 голос
/ 26 мая 2019

В следующем блоке кода я пытаюсь передать массив имен серверов в блок attribute_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]

(Это после объявления счетчика 2 в переменной для var.consul-server_count)

Может кто-нибудь сказать мне, как правильно это сделать?

1 Ответ

0 голосов
/ 26 мая 2019

Здесь есть две проблемы: (1) Как интерполировать список через запятую в строке JSON;и (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 предлагают использовать heredoc для строки JSON, поэтому вы также можете сделать это:

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 = "\", \"".

  • Вы, кажется, пытаетесь split там, когда вам, очевидно, нужно join.

Проблема циклической зависимости

Причина сообщения об ошибке:

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
}

Или вы можете использовать там тоже знак сплат для того же результата, то есть 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, поэтому ресурс зависит от самого себя.Другими словами, вы не можете использовать экспортируемые в ресурсы значения внутри самого ресурса.

Что делать

Я не знаю много о Консуле, но все же янемного запутался, почему вы хотите идентификаторы экземпляра EC2 в поле servers.Разве конфиг Консула не будет ожидать там IP-адреса или имена хостов?

В любом случае, вам, вероятно, придется рассчитывать имена хостов самостоятельно вне этого ресурса, либо как статический входной параметр, либо как что-то, что вы можете вычислитькак-то.И я полагаю, у вас получится что-то вроде:

variable "host_names" {
  type    = list
  default = ["myhost1"]
}

resource "aws_instance" "consul_server" {
  ...
  provisioner "chef" {
    attributes_json = jsonencode(
      {
        "consul" = {
          "servers" = var.host_names
        }
      })
  }
}
...