Цикл Terraform с for_each - PullRequest
       81

Цикл Terraform с for_each

2 голосов
/ 12 июля 2020

Как получить su bnet id, если вы используете for_each вместо count? В моем случае я делаю что-то вроде этого

resource "aws_instance" "k8s" {
    for_each = var.profiles

    ami = data.aws_ami.latest-ubuntu.id
    instance_type = "t2.medium"
    iam_instance_profile = "${each.value}"
    subnet_id = ??????????????
    vpc_security_group_ids = [var.security_group]
    key_name = var.keyname
    
    connection {
    type        = "ssh"
    host        = self.public_ip
    user        = "ubuntu"
    private_key = file(var.private_key_path)

  }
    tags = {
     Name = "${each.key}"
  }
}

И это потому, что я создаю похожие экземпляры, но мне нужно назначить им разные профили экземпляров.

В идеале я бы сделали что-то вроде

subnet_id = element(var.subnets, count.index )

, чтобы разместить экземпляры в разных подсетях, но я не думаю, что count и for_each можно использовать в одном определении блока.

У меня есть подсети и 4 экземпляра, и я хотел бы oop пройти через подсети, поместив каждый экземпляр в одну.

Есть идеи, пожалуйста? Спасибо.

Ответы [ 3 ]

1 голос
/ 12 июля 2020

Если var.profiles - это список, вы можете использовать each.key для получения индекса каждого элемента.

0 голосов
/ 13 июля 2020

Хорошая общая стратегия с ресурсом for_each состоит в том, чтобы разработать структуру данных, которую вы ему передаете, так, чтобы each.value содержал все данные для каждого экземпляра, которые вам нужны внутри блока ресурсов.

В этом случае , это означает, что выражение for_each для вашего ресурса aws_instance будет картой объектов, где каждый объект имеет как профиль экземпляра, так и su bnet id.

Один из способов добиться этого - записать for выражение , которое преобразует var.profiles (которое предположительно является значением set(string)) в карту объектов, которая даст желаемый результат. Например:

resource "aws_instance" "k8s" {
  for_each = {
    # This assigns a subnet to each of the profiles
    # by first sorting them by name to produce a list
    # and then selecting subnets based on the order
    # of the sort result.
    for i, profile_name in sort(var.profiles) : profile_name => {
      iam_instance_profile = profile_name
      subnet_id            = element(var.subnets, i)
    }
  }

  ami                    = data.aws_ami.latest-ubuntu.id
  instance_type          = "t2.medium"
  iam_instance_profile   = each.value.iam_instance_profile
  subnet_id              = each.value.subnet_id
  vpc_security_group_ids = [var.security_group]
  key_name               = var.keyname
}

Использование count.index с элементом element зависит от каждого элемента, имеющего собственный индекс, но это не относится к набору строк, поэтому в приведенном выше примере я использовал sort для преобразования в список при условии, что в этой ситуации на самом деле не имеет значения , который su bnet назначен каждому экземпляру, пока экземпляры в конечном итоге примерно равномерно распределены между подсетями.

Однако следует помнить о важных последствиях: если вы добавите новый элемент в var.profiles позже, это может привести к переназначению subnet_id для существующих экземпляров и, следовательно, потребует те экземпляры, которые необходимо воссоздать. Если вы не хотите, чтобы это было правдой, вам нужно как-то сделать более явным выбор su bnet для каждого профиля, что можно сделать, сделав var.profiles list(string) вместо set(string) а затем документирование того, что новые профили должны быть добавлены только в конец этого списка, или, в качестве альтернативы, вы можете переместить решение в вызывающую сторону вашего модуля, сделав саму var.profiles карту объектов, где вызывающий затем укажет один su bnet на профиль:

variable "profiles" {
  type = map(object({
    subnet_id = string
  }))
}

В этом случае ваш ресурсный блок станет проще, потому что значение переменной уже будет иметь подходящую форму:

resource "aws_instance" "k8s" {
  for_each = var.profiles

  ami                    = data.aws_ami.latest-ubuntu.id
  instance_type          = "t2.medium"
  iam_instance_profile   = each.key
  subnet_id              = each.value.subnet_id
  vpc_security_group_ids = [var.security_group]
  key_name               = var.keyname
}
0 голосов
/ 13 июля 2020

вы можете предоставить вам профили в виде списка объектов:

например:

 variable "profiles" {
  type = list(object({
    name = string
    key =  string
  }))
  default = 
    [
      {name = "exemple" , key = "exemplekey" },
      {name = "exemple2" , key = "exemplekey2" }
    ]
}

вот так each.key будет содержать индекс элемента в списке и each.value будет содержать объект {имя, ключ}

, поэтому ваш код будет таким:

resource "aws_instance" "k8s" {
    for_each = var.profiles
    ami = data.aws_ami.latest-ubuntu.id
    instance_type = "t2.medium"
    iam_instance_profile = each.value
    subnet_id = element(var.subnets , each.key)
    vpc_security_group_ids = [var.security_group]
    key_name = var.keyname
    connection {
    type        = "ssh"
    host        = self.public_ip
    user        = "ubuntu"
    private_key = file(var.private_key_path)

  }
    tags = {
     Name = each.value.key
  }

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...