Spec-Zone.ru › OpenTofu 1.9

Пользовательские условия

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

На этой странице рассматриваются следующие темы:

  • Создание проверок с помощью утверждений для проверки инфраструктуры в целом
  • Создание условий валидации для входных переменных
  • Создание предусловий и постусловий для ресурсов, источников данных и выходных значений
  • Написание эффективных выражений условий и сообщений об ошибках
  • Когда OpenTofu проверяет пользовательские условия в цикле планирования и применения

Выбор пользовательского условия для вашего случая​

Разные пользовательские условия OpenTofu лучше подходят для разных ситуаций. Чтобы выбрать наиболее подходящее пользовательское условие для вашего случая, следуйте этим общим рекомендациям:

  1. Блоки проверок с утверждениями проверяют инфраструктуру в целом. Кроме того, блоки проверок не останавливают и не блокируют выполнение операций OpenTofu.
  2. Условия валидации или постусловия выходных значений позволяют убедиться, что входные и выходные данные конфигурации соответствуют определённым требованиям.
  3. Предусловия и постусловия ресурсов позволяют проверить, что OpenTofu создаёт инфраструктуру согласно конфигурации с ожидаемыми результатами.

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

Валидация входных переменных​

Добавьте один или несколько блоков validation внутри блока variable, чтобы задать пользовательские условия. Для каждой проверки требуется аргумент condition — выражение, которое должно использовать значение переменной и возвращать true, если значение допустимо, или false, если оно недопустимо. В выражении могут использоваться переменные, локальные значения, ресурсы и т. д. Если во время validate/plan значение переменной неизвестно, проверка откладывается до тех пор, пока значение не станет известным на этапе apply.

Если условие возвращает false, OpenTofu выводит сообщение об ошибке, содержащее результат выражения error_message. Если вы объявите несколько проверок, OpenTofu вернёт сообщения об ошибках для всех условий, которые не прошли проверку.

В следующем примере проверяется, имеет ли идентификатор AMI допустимый синтаксис.

Блок кода
variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation {
    condition     = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
    error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
  }
}

Если результат выражения определяет решение о прохождении валидации, используйте функцию can, как показано в следующем примере.

Блок кода
variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation {
    # regex(...) fails if it cannot find a match
    condition     = can(regex("^ami-", var.image_id))
    error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
  }
}

Предусловия и постусловия​

Используйте блоки precondition и postcondition, чтобы создавать пользовательские правила для ресурсов, источников данных и выходных значений.

OpenTofu проверяет предусловие до вычисления связанного с ним объекта, а постусловие — после вычисления объекта. OpenTofu проверяет пользовательские условия как можно раньше, но должен отложить проверку условий, зависящих от неизвестных значений, до этапа применения. Подробнее см. в разделе «Условия, проверяемые только на этапе применения».

Использование​

Для каждого предусловия и постусловия требуется аргумент condition. Это выражение должно возвращать true, если условие выполнено, или false, если оно не выполнено. Выражение может ссылаться на любые другие объекты в том же модуле, если эти ссылки не создают циклических зависимостей. В постусловиях ресурсов также можно использовать объект self, чтобы ссылаться на атрибуты каждого экземпляра ресурса, в котором они заданы.

Если условие возвращает false, OpenTofu выводит сообщение об ошибке, содержащее результат выражения error_message. Если вы объявите несколько предусловий или постусловий, OpenTofu вернёт сообщения об ошибках для всех условий, которые не прошли проверку.

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

Блок кода
data "aws_ami" "example" {
  id = var.aws_ami_id

  lifecycle {
    # The AMI ID must refer to an existing AMI that has the tag "nomad-server".
    postcondition {
      condition     = self.tags["Component"] == "nomad-server"
      error_message = "tags[\"Component\"] must be \"nomad-server\"."
    }
  }
}

Ресурсы и источники данных​

Блок lifecycle внутри блока resource или data может содержать блоки precondition и postcondition.

  • OpenTofu проверяет блоки precondition после вычисления существующих аргументов count и for_each. Благодаря этому OpenTofu может отдельно проверить предусловие для каждого экземпляра, а затем сделать доступными для этих условий each.key, count.index и т. д. OpenTofu также проверяет предусловия до вычисления аргументов конфигурации ресурса. Проверка предусловий может иметь приоритет над ошибками вычисления аргументов.
  • OpenTofu проверяет блоки postcondition после планирования и применения изменений управляемого ресурса или после чтения данных из источника данных. Ошибки постусловий препятствуют внесению изменений в другие ресурсы, зависящие от ресурса, проверка которого завершилась ошибкой.

В большинстве случаев мы не рекомендуем включать в одну конфигурацию одновременно блоки data и resource, представляющие один и тот же объект. Это может помешать OpenTofu понять, что на результат блока data могут повлиять изменения в блоке resource. Однако если нужно проверить результат блока resource, который сам ресурс напрямую не предоставляет, можно безопасно использовать блок data для проверки этого объекта, если разместить проверку непосредственно в блоке postcondition блока data. Так OpenTofu узнает, что блок data проверяет объект, определённый в другом месте, и сможет выполнять действия в правильном порядке.

Выходные значения​

Блок output может содержать блок precondition.

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

OpenTofu проверяет предусловия выходного значения до вычисления выражения value для окончательного определения результата. Предусловия могут иметь приоритет над возможными ошибками в выражении value.

Примеры​

В следующем примере показаны варианты использования предусловий и постусловий. Предусловия и постусловия задают следующие предположения и гарантии.

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

  • Экземпляру EC2 должно быть назначено общедоступное DNS-имя узла. В Amazon Web Services общедоступные DNS-имена узлов назначаются экземплярам EC2, только если они находятся в виртуальной сети, настроенной определённым образом. Постусловие обнаружит, если выбранная виртуальная сеть настроена неправильно, и побудит пользователя проверить параметры сети.

  • Корневой том экземпляра EC2 будет зашифрован. Предусловие гарантирует шифрование корневого тома, хотя программное обеспечение, работающее на этом экземпляре EC2, вероятно, функционировало бы и на незашифрованном томе. Благодаря этому OpenTofu немедленно сообщит об ошибке, до того как какие-либо другие компоненты начнут зависеть от нового экземпляра EC2.

Блок кода
data "aws_ami" "example" {
  owners = ["amazon"]

  filter {
    name   = "image-id"
    values = ["ami-abc123"]
  }
}

resource "aws_instance" "example" {
  instance_type = "t3.micro"
  ami           = data.aws_ami.example.id

  lifecycle {
    # The AMI ID must refer to an AMI that contains an operating system
    # for the `x86_64` architecture.
    precondition {
      condition     = data.aws_ami.example.architecture == "x86_64"
      error_message = "The selected AMI must be for the x86_64 architecture."
    }

    # The EC2 instance must be allocated a public DNS hostname.
    postcondition {
      condition     = self.public_dns != ""
      error_message = "EC2 instance must be in a VPC that has public DNS hostnames enabled."
    }
  }
}

data "aws_ebs_volume" "example" {
  # Use data resources that refer to other resources to
  # load extra data that isn't directly exported by a resource.
  #
  # Read the details about the root storage volume for the EC2 instance
  # declared by aws_instance.example, using the exported ID.

  filter {
    name = "volume-id"
    values = [aws_instance.example.root_block_device.volume_id]
  }

  # Whenever a data resource is verifying the result of a managed resource
  # declared in the same configuration, you MUST write the checks as
  # postconditions of the data resource. This ensures OpenTofu will wait
  # to read the data resource until after any changes to the managed resource
  # have completed.
  lifecycle {
    # The EC2 instance will have an encrypted root volume.
    postcondition {
      condition     = self.encrypted
      error_message = "The server's root volume is not encrypted."
    }
  }
}

output "api_base_url" {
  value = "https://${aws_instance.example.private_dns}:8433/"
}

Выбор между предусловиями и постусловиями​

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

Используйте предусловия для предположений​

Предположение — это условие, которое должно быть истинным, чтобы конфигурацию определённого ресурса можно было использовать. Например, конфигурация aws_instance может исходить из предположения, что указанная AMI всегда будет настроена для архитектуры CPU x86_64.

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

Используйте постусловия для гарантий​

Гарантия — это характеристика или поведение объекта, на которые должна иметь возможность полагаться остальная часть конфигурации. Например, конфигурация aws_instance может гарантировать, что экземпляр EC2 будет работать в сети, назначающей ему частную DNS-запись.

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

Дополнительные факторы для принятия решения​

При создании предусловий и постусловий также следует учитывать следующие вопросы.

  • О каком ресурсе или выходном значении полезнее всего сообщить в сообщении об ошибке? OpenTofu всегда указывает ошибки в месте объявления условия.
  • Какой подход удобнее? Если у определённого ресурса много зависимостей, каждая из которых делает предположение об этом ресурсе, может быть практичнее объявить это предположение один раз как постусловие ресурса, а не объявлять его много раз в качестве предусловий для каждой зависимости.
  • Полезно ли объявить одинаковые или похожие условия одновременно как предусловия и постусловия? Это может пригодиться, если постусловие находится в другом модуле, чем предусловие: так модули смогут проверять друг друга, развиваясь независимо.

Проверки с утверждениями​

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

Чтобы проверить пользовательские условия, добавьте один или несколько блоков assert в блок check. Для каждого утверждения требуется аргумент condition — логическое выражение, которое должно возвращать true, если предполагаемое условие или гарантия выполнены, либо false, если нет. В выражении condition можно ссылаться на любые ресурсы, источники данных или переменные, доступные во внешнем блоке check.

В следующем примере блок проверки с утверждением используется для проверки доступности веб-сайта OpenTofu.

Блок кода
check "health_check" {
  data "http" "opentofu_org" {
    url = "https://www.opentofu.org"
  }

  assert {
    condition = data.http.opentofu_org.status_code == 200
    error_message = "${data.http.opentofu_org.url} returned an unhealthy status code"
  }
}

Если условие возвращает false, OpenTofu выводит сообщение об ошибке, содержащее результат выражения error_message. Если вы объявите несколько утверждений, OpenTofu вернёт сообщения об ошибках для всех условий, которые не прошли проверку.

Непрерывная проверка в облачном бэкенде​

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

Выражения условий​

Для утверждений в проверках, валидации входных переменных, предусловий и постусловий требуется аргумент condition. Это логическое выражение должно возвращать true, если предполагаемое условие или гарантия выполнены, и false, если нет.

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

Логические операторы​

Используйте логические операторы && (И), || (ИЛИ) и ! (НЕ), чтобы объединить несколько условий.

Блок кода
  condition = var.name != "" && lower(var.name) == var.name

Также можно использовать арифметические операторы (например, a + b), операторы равенства (например, a == b) и операторы сравнения (например, a < b). Подробнее см. в разделе «Арифметические и логические операторы».

Функция contains​

Используйте функцию contains, чтобы проверить, входит ли заданное значение в набор заранее определённых допустимых значений.

Блок кода
  condition = contains(["STAGE", "PROD"], var.environment)

Функция length​

Используйте функцию length, чтобы проверить длину коллекции и потребовать, чтобы список или карта не были пустыми.

Блок кода
  condition = length(var.items) != 0

Это лучше, чем напрямую сравнивать с другой коллекцией с помощью == или !=. Операторы сравнения могут возвращать true, только если оба операнда имеют совершенно одинаковый тип, что часто неоднозначно для пустых коллекций.

Выражения for​

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

Блок кода
  condition = alltrue([
    for v in var.instances : contains(["t2.micro", "m3.medium"], v.type)
  ])

Функция can​

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

Например, можно использовать can вместе с regex, чтобы проверить, соответствует ли строка определённому шаблону, поскольку regex возвращает ошибку, если строка ему не соответствует.

Блок кода
  condition = can(regex("^[a-z]+$", var.name))

Также можно использовать can с функциями преобразования типов, чтобы проверить, можно ли преобразовать значение к заданному типу или ограничению типа.

Блок кода
  # This remote output value must have a value that can
  # be used as a string, which includes strings themselves
  # but also allows numbers and boolean values.
  condition = can(tostring(data.terraform_remote_state.example.outputs["name"]))
Блок кода
  # This remote output value must be convertible to a list
  # type of with element type.
  condition = can(tolist(data.terraform_remote_state.example.outputs["items"]))

Также можно использовать can с обращением к атрибутам или операторами индексации, чтобы проверить, содержит ли коллекция или структурное значение определённый элемент или индекс.

Блок кода
  # var.example must have an attribute named "foo"
  condition = can(var.example.foo)
Блок кода
  # var.example must be a sequence with at least one element
  condition = can(var.example[0])
  # (although it would typically be clearer to write this as a
  # test like length(var.example) > 0 to better represent the
  # intent of the condition.)

Объект self​

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

Блок кода
resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = "ami-abc123"

  lifecycle {
    postcondition {
      condition     = self.instance_state == "running"
      error_message = "EC2 instance must be running."
    }
  }
}

Объекты each и count​

В блоках, где заданы for_each или count, используйте объекты each и count, чтобы ссылаться на другие ресурсы, развёрнутые в цепочке.

Блок кода
variable "vpc_cidrs" {
  type = set(string)
}

data "aws_vpc" "example" {
  for_each = var.vpc_cidrs

  filter {
    name   = "cidr"
    values = [each.key]
  }
}

resource "aws_internet_gateway" "example" {
  for_each = data.aws_vpc.example
  vpc_id = each.value.id

  lifecycle {
    precondition {
      condition     = data.aws_vpc.example[each.key].state == "available"
      error_message = "VPC ${each.key} must be available."
    }
  }
}

Сообщения об ошибках​

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

Блок кода
Error: Resource postcondition failed

  with data.aws_ami.example,
  on ec2.tf line 19, in data "aws_ami" "example":
  72:       condition     = self.tags["Component"] == "nomad-server"
    |----------------
    | self.tags["Component"] is "consul-server"

The selected AMI must be tagged with the Component value "nomad-server".

Аргумент error_message может быть любым выражением, результатом которого является строка. К таким выражениям относятся строковые литералы, heredoc и шаблонные выражения. Чтобы преобразовать значения типов null, list или map в форматированную строку, можно использовать функцию format. Поддерживаются многострочные сообщения об ошибках; строки с начальными пробелами не будут автоматически переноситься.

Мы рекомендуем составлять сообщения об ошибках из одного или нескольких полных предложений в стиле, похожем на сообщения об ошибках самого OpenTofu. OpenTofu показывает сообщение вместе с именем ресурса, обнаружившего проблему, и любыми внешними значениями, включёнными в выражение условия.

Условия, проверяемые только на этапе применения​

OpenTofu проверяет пользовательские условия как можно раньше.

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

  • Известно до применения: OpenTofu проверяет условие на этапе планирования. Например, OpenTofu может знать значение идентификатора образа во время планирования, если оно не создано другим ресурсом.
  • Известно после применения: OpenTofu откладывает проверку условия до этапа применения. Например, AWS назначает идентификатор корневого тома только при запуске экземпляра EC2, поэтому OpenTofu не может узнать это значение до применения.

На этапе применения невыполненное предусловие не позволит OpenTofu выполнить запланированные действия для связанного ресурса. Однако невыполненное постусловие остановит обработку после того, как OpenTofu уже выполнит эти действия. Такое постусловие не позволит выполнить последующие действия, зависящие от ресурса, но не отменит уже выполненные OpenTofu действия.

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

Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.9/language/expressions/custom-conditions/

Spec-Zone.ru

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