Как условно заполнить значение аргумента в terraform?

#terraform #terraform-provider-aws #terraform-provider-gcp

#terraform #terraform-provider-aws #terraform-provider-gcp

Вопрос:

Я пишу скрипт Terraform для расширения ресурсов в облачной платформе Google.
Некоторым ресурсам требуется один аргумент, только если задан другой, как заполнить один аргумент, только если заполнен другой (или любое другое подобное условие)?

Например:

 resource "google_compute_router" "compute_router" {
  name    = "my-router"
  network = "${google_compute_network.foobar.name}"
  bgp {
    asn               = 64514
    advertise_mode    = "CUSTOM"
    advertised_groups = ["ALL_SUBNETS"]
    advertised_ip_ranges {
      range = "1.2.3.4"
    }
    advertised_ip_ranges {
      range = "6.7.0.0/16"
    }
  }
}
  

В приведенном выше ресурсе (google_compute_router) в описании для обоих advertised_groups и advertised_ip_ranges говорится , что это поле может быть заполнено, только если advertise_mode является пользовательским и рекламируется всем одноранговым узлам маршрутизатора.

Теперь, если я сохраню значение advertise_mode по УМОЛЧАНИЮ, мой код будет выглядеть примерно так, как показано ниже:

 resource "google_compute_router" "compute_router" {
  name    = "my-router"
  network = "${google_compute_network.foobar.name}"
  bgp {
    asn               = 64514

    #Changin only the value below
    advertise_mode    = "DEFAULT"

    advertised_groups = ["ALL_SUBNETS"]
    advertised_ip_ranges {
      range = "1.2.3.4"
    }
    advertised_ip_ranges {
      range = "6.7.0.0/16"
    }
  }
}
  

Однако приведенный выше скрипт при запуске выдает следующую ошибку:

 * google_compute_router.compute_router_default: Error creating Router: googleapi: Error 400: Invalid value for field 'resource.bgp.advertiseMode': 'DEFAULT'. Router cannot have a custom advertisement configurati
on in default mode., invalid
  

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

 resource "google_compute_router" "compute_router_default" {
  count               = "${var.advertise_mode == "DEFAULT" ? 1 : 0}"
  name                = "${var.router_name}"
  region              = "${var.region}"
  network             = "${var.network_name}"

  bgp {
    asn               = "${var.asn}"
    advertise_mode    = "${var.advertise_mode}"
    #Removed some codes from here
  }
}

resource "google_compute_router" "compute_router_custom" {
  count               = "${var.advertise_mode == "CUSTOM" ? 1 : 0}"
  name                = "${var.router_name}"
  region              = "${var.region}"
  network             = "${var.network_name}"

  bgp {
    asn               = "${var.asn}"
    advertise_mode    = "${var.advertise_mode}"
    advertised_groups = ["${var.advertised_groups}"]

    advertised_ip_ranges {
      range = "${var.advertised_ip_range}"
      description = "${var.advertised_ip_description}"
    }
  }
}
  

Приведенный выше скрипт работает нормально, однако мне кажется, что это много повторений кода и взлом. Кроме того, для двух параметров (зависимых атрибутов) это нормально, однако, если есть больше параметров, скажем, 5, повторение кода для такой маленькой вещи было бы слишком большим.
Есть ли лучший способ сделать то, чего я пытаюсь достичь?

Ответ №1:

Это в значительной степени то, чем вы ограничены в Terraform < 0.12. Некоторые ресурсы позволяют использовать пустую строку для пропуска базовых значений, и поставщик интерпретирует это как нулевое значение, не передавая его конечной точке API, чтобы она не жаловалась на то, что оно не установлено должным образом. Но, исходя из моего краткого опыта работы с поставщиком GCP, это не относится к большинству вещей там.

Terraform 0.12 вводит null доступные аргументы, которые позволили бы вам установить их условно с помощью чего-то вроде следующего:

 variable "advertise_mode" {}

resource "google_compute_router" "compute_router" {
  name    = "my-router"
  network = "${google_compute_network.foobar.name}"
  bgp {
    asn               = 64514
    advertise_mode    = "${var.advertise_mode}"
    advertised_groups = ["${var.advertise_mode == "DYNAMIC" ? ALL_SUBNETS : null}"]
    advertised_ip_ranges {
      range = "${var.advertise_mode == "DYNAMIC" ? 1.2.3.4 : null}"
    }
    advertised_ip_ranges {
      range = "${var.advertise_mode == "DYNAMIC" ? 6.7.0.0/16 : null}"
    }
  }
}
  

Это также введет динамические блоки, которые вы сможете перебирать, чтобы у вас также могло быть динамическое количество advertised_ip_ranges блоков.

Комментарии:

1. Я читал об этом на веб-сайте terraform. Хорошая ли идея использовать бета-версию 0.12 для временного написания скрипта и внесения изменений после выхода версии 0.12? Кроме того, есть ли у вас представление о том, когда будет выпущена следующая версия?

2. Первоначально Terraform 0.12 была запланирована на конец лета 2018 года, но столкнулась с кучей трудностей, поэтому я не думаю, что будет справедливо пытаться угадать дату, когда она может быть выпущена на данный момент. Я бы не стал использовать его для производственных целей в основном потому, что на данный момент они предостерегают от этого, и у меня есть несколько ужасных историй из менее стабильных версий Terraform давным-давно. На данный момент (и если это только та конкретная вещь, которую вы хотите) Я бы придерживался вашего дублированного кода и перешел на 0.12, когда он будет выпущен.

Ответ №2:

Приведенный выше ответ неверен, поскольку ‘advertised_ip_ranges’ не принимает нулевое значение; решение этой проблемы заключается в использовании динамического блока, который может обрабатывать нулевое значение для этого ресурса и дополнительно позволяет ресурсу принимать переменное количество диапазонов ip.

 variable custom_ranges {
  default = ["172.16.31.0/24","172.16.32.0/24"]
}

resource "google_compute_router" "router_01" {
  name    = "cr-bgp-${var.gcp_bgp_asn}"
  region  = var.gcp_region
  project = var.gcp_project
  network = var.gcp_network

  bgp {
    asn = var.gcp_bgp_asn
    advertise_mode = var.advertise_mode
    advertised_groups = var.advertise_mode == "CUSTOM" ? ["ALL_SUBNETS"] : null
    dynamic "advertised_ip_ranges" {
      for_each = var.advertise_mode == "CUSTOM" ? var.custom_ranges : []
      content { 
        range = advertised_ip_ranges.value
      }
    }
  }
}
  

дополнительные ключи поиска: google_compute_router «bgp.0.advertised_ip_ranges.0.range» не принимает нулевое значение.

Комментарии:

1. Stack Overflow и Stack Exchange в целом не используют подписи в сообщениях. Ваша карточка пользователя, которая отображается в правом нижнем углу каждой вашей записи, служит для этой цели. Если вы хотите, чтобы ваша контактная информация была общедоступной, то она может быть на странице вашего профиля, на которую ссылается ваша карточка пользователя. Добавление подписи, как вы сделали здесь, часто считается спамом. Это также способствует тому, что вы получаете голоса против этого ответа.

2. Это должен быть принятый ответ