Spec-Zone.ru › OpenTofu 1.11

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

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

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

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

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

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

  1. Блоки check с утверждениями проверяют инфраструктуру в целом. Кроме того, блоки check не препятствуют выполнению операций 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 проверяет пользовательские условия как можно раньше, но должен отложить проверку условий, зависящих от неизвестных значений, до этапа apply. Дополнительные сведения см. в разделе Условия, проверяемые только на этапе apply.

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

Для каждого предусловия и постусловия требуется аргумент 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 всегда будет настроена для архитектуры процессора x86_64.

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

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

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

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

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

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

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

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

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

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

В следующем примере блок 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. Непрерывная проверка уведомит вас о невыполнении условия, чтобы вы могли обновить сертификат и избежать ошибок при следующем обновлении инфраструктуры.

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

Для утверждений в блоках check, валидации входных переменных, предусловий и постусловий требуется аргумент 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 и шаблонные выражения. С помощью функции format можно преобразовать элементы типов null, list или map в отформатированную строку. Поддерживаются многострочные сообщения об ошибках; строки с начальными пробелами не будут переноситься по словам.

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

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

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

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

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

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

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

Использование эфемерных значений​

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

Блок кода
variable "my_ephemeral_variable" {
  type      = string
  ephemeral = true
}

resource "null_resource" "test" {
  // ...
  lifecycle {
    precondition {
      condition = var.my_ephemeral_variable != "forbidden-value"
      error_message = "cannot be used when this variable points to a value that is not allowed"
    }
  }
}

Использование эфемерных значений в error_message приведет к сбою формирования сообщения:

Блок кода
│ Warning: Error message refers to ephemeral values
│
│   on main.tf line 63, in resource "null_resources" "test":
│   63:       error_message = "cannot be used when this variable points to a value that is not allowed ${var.my_ephemeral_variable}"
│
│ The error expression used to explain this condition refers to ephemeral values, so OpenTofu will not display the
│ resulting message.
│
│ You can correct this by removing references to ephemeral values or by utilizing the builtin ephemeralasnull()
│ function.
╵
╷
│ Error: Resource precondition failed
│
│   on main.tf line 62, in resource "null_resource" "test":
│   62:       condition = var.my_ephemeral_variable != "forbidden-value"
│
│ This check failed, but has an invalid error message as described in the other accompanying messages.

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

Spec-Zone.ru

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