Spec-Zone.ru › OpenTofu 1.12

Настройка провайдеров

Провайдеры позволяют OpenTofu взаимодействовать с облачными провайдерами, SaaS-провайдерами и другими API.

Для работы с OpenTofu некоторым провайдерам требуется предварительная настройка URL-адресов конечных точек, облачных регионов или других параметров. На этой странице описана настройка параметров провайдеров.

Кроме того, во всех конфигурациях OpenTofu необходимо объявлять требуемые провайдеры, чтобы OpenTofu мог установить и использовать их. На странице Требования к провайдерам описано, как объявлять провайдеры, чтобы OpenTofu мог их установить.

Настройка провайдеров​

Конфигурации провайдеров должны находиться в корневом модуле конфигурации OpenTofu. (Дочерние модули получают конфигурации провайдеров от корневого модуля; дополнительную информацию см. в разделах Метааргумент providers и Разработка модулей: провайдеры в модулях.)

Конфигурация провайдера задаётся блоком provider:

Блок кода
provider "google" {
  project = "acme-app"
  region  = "us-central1"
}

Имя, указанное в заголовке блока (в этом примере — "google"), является локальным именем настраиваемого провайдера. У каждого модуля есть собственное пространство имён локальных имён провайдеров, определённых в его блоке required_providers.

Тело блока (между { и }) содержит аргументы конфигурации провайдера. Большинство аргументов в этом разделе определяются самим провайдером; в данном примере и project, и region относятся к провайдеру google.

В значениях этих аргументов конфигурации можно использовать выражения, но ссылаться можно только на значения, известные до применения конфигурации. Это означает, что можно безопасно ссылаться на входные переменные, но не на атрибуты, экспортируемые ресурсами, если только они не определены непосредственно в конфигурации или в документации не указано, что они доступны на этапе планирования.

Для настройки провайдера можно использовать эфемерные значения. Они могут поступать из разных источников, например из переменных, выходных значений или эфемерных ресурсов. Пример настройки провайдера приведён в документации по эфемерным значениям.

В документации провайдера должны быть перечислены ожидаемые аргументы конфигурации. Для провайдеров, распространяемых через публичный реестр OpenTofu, документация с указанием версии доступна на странице каждого провайдера по ссылке «Документация» в заголовке.

Некоторые провайдеры могут использовать переменные среды оболочки (или другие альтернативные источники, например профили экземпляров виртуальных машин) в качестве значений некоторых аргументов. Если такая возможность доступна, рекомендуется использовать её, чтобы не хранить учётные данные в коде OpenTofu, который находится под контролем версий.

Также существуют два «метааргумента», определяемых самим OpenTofu и доступных для всех блоков provider:

  • alias — для определения дополнительных конфигураций того же провайдера
  • for_each — для определения нескольких динамических экземпляров конфигурации провайдера
  • version, который мы больше не рекомендуем использовать (вместо него используйте требования к провайдерам)

В отличие от многих других объектов языка OpenTofu, блок provider можно опустить, если в противном случае он был бы пустым. OpenTofu предполагает пустую конфигурацию по умолчанию для любого провайдера, который не настроен явно.

alias: несколько конфигураций провайдера​

При необходимости можно определить несколько конфигураций одного и того же провайдера и выбирать, какую из них использовать для каждого ресурса или модуля. Чаще всего это нужно для поддержки нескольких регионов облачной платформы; также это может быть полезно при работе с несколькими узлами Docker, узлами Consul и т. д.

Чтобы создать несколько конфигураций заданного провайдера, добавьте несколько блоков provider с одним и тем же именем провайдера. Для каждой дополнительной конфигурации, отличной от конфигурации по умолчанию, используйте метааргумент alias, чтобы задать дополнительный сегмент имени. Конфигурация провайдера с псевдонимом называется альтернативной конфигурацией провайдера. Например:

Блок кода
# The default provider configuration; resources that begin with `aws_` will use
# it as the default, and it can be referenced as `aws`.
provider "aws" {
  region = "us-east-1"
}

# Alternate provider configuration for west coast region; resources can
# reference this as `aws.west`.
provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

Чтобы объявить в модуле псевдоним конфигурации и получить альтернативную конфигурацию провайдера из родительского модуля, добавьте аргумент configuration_aliases в запись required_providers этого провайдера. В следующем примере в содержащем модуле объявлены имена конфигураций провайдера mycloud и mycloud.alternate:

Блок кода
terraform {
  required_providers {
    mycloud = {
      source  = "mycorp/mycloud"
      version = "~> 1.0"
      configuration_aliases = [ mycloud.alternate ]
    }
  }
}

Конфигурации провайдера по умолчанию​

Блок provider без аргумента alias является конфигурацией по умолчанию для этого провайдера. Ресурсы, в которых не задан метааргумент provider, будут использовать конфигурацию провайдера по умолчанию, соответствующую первому слову в имени типа ресурса. (Например, ресурс aws_instance использует конфигурацию провайдера aws по умолчанию, если не указано иное.)

Если блок provider с конфигурацией провайдера по умолчанию отсутствует, OpenTofu автоматически предполагает для этого провайдера пустую конфигурацию по умолчанию. Если схема конфигурации провайдера содержит обязательные аргументы, пустая конфигурация будет недопустимой, поэтому потребуется явный блок provider.

Конфигурация провайдера по умолчанию не требуется и не предполагается, если все ресурсы в модуле явно выбирают другую конфигурацию провайдера с помощью метааргумента provider в своих блоках resource или data.

for_each: несколько экземпляров конфигурации провайдера​

Иногда требуется динамически объявлять несколько экземпляров провайдера на основе других данных, доступных в конфигурации, например входной переменной.

Например, конфигурация, объявляющая базовый набор инфраструктуры для каждого используемого организацией региона AWS, может предоставлять входную переменную для указания этих регионов. Однако провайдер hashicorp/aws поддерживает только один регион для каждого экземпляра провайдера, поэтому объявить инфраструктуру в динамическом наборе регионов, используя только статические конфигурации провайдера, невозможно.

Любая альтернативная конфигурация провайдера (объявленная с помощью аргумента alias) может также содержать аргумент for_each, указывающий, что конфигурацию нужно создать в нескольких экземплярах на основе значения коллекции:

Блок кода
variable "aws_regions" {
  type = map(object({
    vpc_cidr_block = string
  }))
}

provider "aws" {
  alias    = "by_region"
  for_each = var.aws_regions

  region = each.key
}

Без аргумента for_each блок provider всегда объявляет только один экземпляр соответствующего провайдера. Конфигурация провайдера, содержащая аргумент for_each, вместо этого объявляет ноль или больше экземпляров провайдера. Каждый из них соответствует одному элементу коллекции for_each и систематически настраивается на основе одного и того же блока конфигурации.

У каждого экземпляра есть ключ экземпляра, однозначно идентифицирующий его среди всех экземпляров одной конфигурации провайдера. Значение, присвоенное for_each, должно иметь тип map или object либо быть набором строк. Для типа map или object ключ элемента или имя атрибута становится ключом экземпляра. Для набора строк ключом экземпляра становится значение самого элемента.

Оператор этой конфигурации должен передать входной переменной aws_regions значение типа map, в котором ключ каждого элемента является допустимым именем региона AWS, а значение — объектом с уникальными настройками для этого региона. Например, в файле terraform.tfvars:

Блок кода
aws_regions = {
  eu-central-2 = {
    vpc_cidr_block = "10.1.0.0/16"
  }
  ap-northeast-1 = {
    vpc_cidr_block = "10.2.0.0/16"
  }
}

Аргумент for_each можно использовать только вместе с alias, поскольку у конфигурации по умолчанию каждого провайдера всегда должен быть ровно один экземпляр, чтобы OpenTofu мог автоматически выбирать его при необходимости.

Выбор альтернативных конфигураций провайдера​

Каждый ресурс в конфигурации OpenTofu должен быть привязан к одной конфигурации провайдера.

По умолчанию каждый ресурс привязывается к конфигурации провайдера по умолчанию, автоматически выбранной на основе первого сегмента имени типа ресурса. Например, блок resource "azurerm_subnet" "example" будет привязан к конфигурации по умолчанию провайдера с локальным именем «azurerm» в модуле, где объявлен ресурс.

Чтобы использовать альтернативную конфигурацию провайдера, в блоке resource или data нужно указать метааргумент provider и ссылку на экземпляр провайдера, содержащую псевдоним выбранной конфигурации:

Блок кода
resource "aws_instance" "foo" {
  provider = aws.west

  # ...
}

Если в выбранной конфигурации для объявления нескольких экземпляров используется аргумент for_each, то аргумент provider должен также содержать выражение с ключом экземпляра, чтобы выбрать один экземпляр конфигурации провайдера для каждого экземпляра ресурса, как описано в следующем разделе.

Если аргумент provider не указан, это равносильно выбору конфигурации провайдера по умолчанию, локальное имя которой совпадает с префиксом имени типа ресурса:

Блок кода
resource "aws_instance" "foo" {
  provider = aws

  # ...
}

Ссылки на экземпляры провайдера​

Для явных ссылок на конфигурации провайдера OpenTofu использует специальный синтаксис ссылок на конфигурации провайдера вида <PROVIDER NAME>.<ALIAS>. Например, aws.west ссылается на блок provider "aws" с alias = "west".

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

  • Метааргумент provider блока resource или data
  • Метааргумент providers блока module

Для конфигурации провайдера, в которой не указан for_each, синтаксис ссылки на конфигурацию одновременно является ссылкой на её единственный экземпляр провайдера, поэтому в большинстве случаев ссылки на конфигурацию провайдера и на экземпляр провайдера можно считать эквивалентными.

Однако если конфигурация провайдера объявляет ноль или больше динамических экземпляров с помощью for_each, в синтаксис ссылки добавляется компонент, указывающий, какой экземпляр выбрать по ключам экземпляров конфигурации. Например, aws.by_region["eu-west-1"] ссылается на экземпляр aws.by_region с ключом экземпляра "eu-west-1".

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

Блок кода
variable "aws_regions" {
  type = map(object({
    vpc_cidr_block = string
  }))
}

provider "aws" {
  alias    = "by_region"
  for_each = var.aws_regions

  region = each.key
}

resource "aws_vpc" "private" {
  # This expression filters var.aws_regions to include only
  # the elements whose value is not null. Refer to the
  # warning in the text below for more information.
  for_each = {
    for region, config in var.aws_regions : region => config
    if config != null
  }
  provider = aws.by_region[each.key]

  cidr_block = each.value.vpc_cidr_block
}

Блок resource "aws_vpc" "private" использует for_each, чтобы объявить по одному экземпляру ресурса для каждого ненулевого элемента var.aws_regions. Затем аргумент provider использует each.key, чтобы выбрать для каждого экземпляра ресурса отдельный экземпляр aws.by_region, благодаря чему они будут объявлены в разных регионах.

Также можно выбрать динамический экземпляр из конфигурации провайдера для всех ресурсов дочернего модуля в блоке module. Дополнительную информацию см. в разделе Экземпляры модулей с разными экземплярами провайдеров.

Хотя выражение ключа экземпляра в квадратных скобках является динамическим, ссылка на конфигурацию провайдера остаётся статической. Это позволяет OpenTofu определить зависимости между блоками resource и provider до вычисления любых выражений. Зависимости позволяют OpenTofu вычислять динамические выражения в правильном порядке. Это означает, что все экземпляры определённого ресурса должны быть привязаны к экземплярам одного и того же блока конфигурации провайдера, но каждый из них может быть привязан к отдельному экземпляру провайдера.

Предупреждение

Выражение for_each для ресурса должно отличаться от выражения for_each для связанной с ним конфигурации провайдера.

OpenTofu использует экземпляр провайдера для планирования и применения всех действий, связанных с экземпляром ресурса, в том числе для удаления экземпляра ресурса, удалённого из конфигурации.

Поэтому связанный с любым экземпляром ресурса экземпляр провайдера должен оставаться в конфигурации ещё как минимум один цикл планирования и применения после удаления экземпляра ресурса. Иначе OpenTofu не сможет запланировать удаление экземпляра ресурса.

В приведённом выше примере нулевой элемент в var.aws_regions указывает, что экземпляр провайдера необходим, но с ним не должны быть связаны экземпляры ресурсов.

Таким образом, установка значения null для элемента определённого региона приведёт к тому, что OpenTofu предложит удалить экземпляр aws_vpc.private для этого региона, сохранив при этом экземпляр провайдера, необходимый для планирования и применения этого действия. После этого, когда все связанные экземпляры ресурсов будут удалены, элемент можно удалить полностью.

Удаление экземпляра провайдера​

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

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

Блок кода
variable "aws_active_regions" {
  type    = set(string)
  default = ["us-east-1", "sa-east-1"]
}

provider "aws" {
  alias    = "by_region"
  for_each = var.aws_active_regions
  region   = each.key
}

resource "aws_cloudwatch_log_group" "lambda_cloudfront" {
  name     = "/aws/lambda/${each.key}.lambda"
  provider = aws.by_region[each.key]
  for_each = var.aws_active_regions
}

Эта конфигурация вызовет следующее предупреждение:

Блок кода
╷
│ Warning: Provider configuration for_each matches resource
│
│   on main.tf line 24, in resource "aws_cloudwatch_log_group" "lambda_cloudfront":
│   24:   for_each = var.aws_regions
│
│ This provider configuration uses the same for_each expression as a
│ resource, which means that subsequent removal of elements from this
│ collection would cause a planning error.
│
│ OpenTofu relies on a provider instance to destroy resource instances
│ that are associated with it, and so the provider instance must
│ outlive all of its resource instances by at least one plan/apply
│ round. For removal of instances to succeed in future you must
│ structure the configuration so that the provider block's for_each
│ expression can produce a superset of the instances of the resources
│ associated with the provider configuration. Refer to the OpenTofu
│ documentation for specific suggestions.
│
│ To destroy this object before removing the provider configuration,
│ consider first performing a targeted destroy:
│     tofu apply -destroy -target=aws_cloudwatch_log_group.lambda_cloudfront
╵

Этот подход чреват ошибками, поскольку перед удалением самого экземпляра провайдера необходимо выполнить apply -destroy -target для всех связанных с ним ресурсов. Если попытаться удалить экземпляр провайдера, удалив ключ из aws_active_regions до уничтожения ресурсов, OpenTofu не позволит это сделать:

Блок кода
╷
│ Error: Provider instance not present
│
│ To work with aws_cloudwatch_log_group.lambda_cloudfront["sa-east-1"]
│ its original provider instance at
│ provider["registry.opentofu.org/hashicorp/aws"].by_region["sa-east-1"]
│ is required, but it has been removed. This occurs when an element is
│ removed from the provider configuration's for_each collection while
│ objects created by that the associated provider instance still exist
│ in the state. Re-add the for_each element to destroy
│ aws_cloudwatch_log_group.lambda_cloudfront["sa-east-1"], after which
│ you can remove the provider configuration again.
│
│ This is commonly caused by using the same for_each collection both
│ for a resource (or its containing module) and its associated provider
│ configuration. To successfully remove an instance of a resource it
│ must be possible to remove the corresponding element from the
│ resource's for_each collection while retaining the corresponding
│ element in the provider's for_each collection.
╵

В качестве альтернативы для выражения for_each ресурса можно использовать другое подмножество:

Блок кода
variable "aws_active_regions" {
  type = set(string)
  default = ["us-east-1", "sa-east-1"]
}

variable "aws_disabled_regions" {
  description = "A list of regions that should be disabled and all resources removed."
  type        = set(string)
  default     = []
}

// Superset of the provider configuration
provider "aws" {
  alias    = "by_region"
  for_each = var.aws_active_regions
  region   = each.key
}

// Resource using a subset of the provider's configuration
resource "aws_cloudwatch_log_group" "lambda_cloudfront" {
  name     = "/aws/lambda/${each.key}.lambda"
  provider = aws.by_region[each.key]
  for_each = setsubtract(var.aws_active_regions, var.aws_disabled_regions)
}

Если нужно удалить экземпляр провайдера (например, для определённого региона AWS), добавьте этот регион в aws_disabled_regions:

Блок кода
variable "aws_disabled_regions" {
  description = "A list of regions that should be disabled and all resources removed."
  type        = set(string)
  default     = ["us-east-1"]
}

При таком подходе достаточно выполнить tofu plan и tofu apply, чтобы отключить экземпляр провайдера и удалить все связанные с ним ресурсы.

Передача конфигураций провайдеров между модулями​

У каждого модуля есть собственное отдельное пространство имён конфигураций провайдеров, но родительский модуль может передавать некоторые или все свои конфигурации провайдеров по адресам конфигураций провайдеров, объявленным в дочернем модуле.

Дополнительную информацию см. в разделе Метааргумент providers в блоках module.

version (Устарело)​

Метааргумент version задаёт ограничение версии провайдера и работает так же, как аргумент version в блоке required_providers. Ограничение версии в конфигурации провайдера используется только в том случае, если в required_providers для этого провайдера ограничение не задано.

Всегда задавайте ограничения версий провайдеров в блоке required_providers.

Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.12/language/providers/configuration/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API