linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
home/terraform/lessons/tf-intermediate-10-preconditions

lesson ── terraform-intermediate ── ~14 мин ── 5 шагов

preconditions, postconditions и check блок

Terraform plan показывает что будет сделано, но не проверяет «а имеет ли это смысл». Например: бакет создаётся в us-west-2, а у тебя в HCL написано «должен быть в us-east-1», отдельно не ловится.

С TF 1.2+ есть precondition и postcondition внутри lifecycle, это declarative assertions. Если не выполняются, apply останавливается. С TF 1.5+ есть check блоки, мягкие проверки без блокировки apply.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    Базовый бакет для экспериментов

    bash
    cd /home/student/tf-checks
    cat > main.tf <<'EOF'
    variable "bucket_name_prefix" {
      type    = string
      default = "linuxlab-checks"
    }
    resource "random_id" "suffix" {
      byte_length = 4
    }
    resource "aws_s3_bucket" "demo" {
      bucket = "${var.bucket_name_prefix}-${random_id.suffix.hex}"
    }
    EOF
    terraform init
    terraform apply -auto-approve

    ✓ База создана. Добавим инварианты.

  2. 02

    precondition: проверяй входы

    Добавь lifecycle с preconditions в aws_s3_bucket.demo:

    hcl
    resource "aws_s3_bucket" "demo" {
      bucket = "${var.bucket_name_prefix}-${random_id.suffix.hex}"
      lifecycle {
        precondition {
          condition     = length(var.bucket_name_prefix) >= 3 && length(var.bucket_name_prefix) <= 40
          error_message = "bucket_name_prefix must be 3-40 chars (to fit total bucket name into S3 63-char limit)."
        }
      }
    }

    Проверь что это работает, поменяй default на короткое:

    bash
    sed -i 's/default = "linuxlab-checks"/default = "x"/' main.tf
    terraform plan

    Должна быть ошибка:

    Error: Resource precondition failed
      on main.tf line ..., in resource "aws_s3_bucket" "demo":
       ...: condition = ...
    bucket_name_prefix must be 3-40 chars ...

    Plan останавливается до похода в облако. Это валидация на стадии plan. См. tf-resource-lifecycle и tf-variable.

    Верни значение обратно:

    bash
    sed -i 's/default = "x"/default = "linuxlab-checks"/' main.tf

    ✓ precondition сработал. Plan теперь защищён от плохих входов.

  3. 03

    postcondition: проверяй output

    Postcondition, после получения атрибутов от провайдера. Проверим что бакет создан в правильном регионе:

    hcl
    resource "aws_s3_bucket" "demo" {
      bucket = "${var.bucket_name_prefix}-${random_id.suffix.hex}"
      lifecycle {
        precondition {
          condition     = length(var.bucket_name_prefix) >= 3 && length(var.bucket_name_prefix) <= 40
          error_message = "bucket_name_prefix must be 3-40 chars."
        }
        postcondition {
          condition     = self.region == "us-east-1"
          error_message = "Expected region us-east-1, got ${self.region}."
        }
      }
    }

    self внутри postcondition, это сам ресурс, доступны все его атрибуты. Это главное отличие от precondition (там нет self, ресурса ещё нет).

    Применим:

    bash
    terraform apply -auto-approve

    Plan и apply проходят (LocalStack возвращает us-east-1, как и сконфигурировано).

    ✓ postcondition сработал. Атрибут ресурса проверен.

  4. 04

    check блок: мягкая проверка

    check. TF 1.5+, отдельный top-level блок. Не блокирует apply при ошибке, только выводит warning:

    Добавь в конец main.tf:

    hcl
    check "bucket_versioning" {
      assert {
        condition     = aws_s3_bucket.demo.versioning != null && length(aws_s3_bucket.demo.versioning) > 0
        error_message = "Bucket has no versioning configured: warning, not blocker."
      }
    }
    bash
    terraform apply -auto-approve

    Должно вывести warning (для нашего бакета versioning не сконфигурирован):

    Warning: Check block assertion failed
      on main.tf line ...:
      ...
    Bucket has no versioning configured...

    Apply прошёл, только warning. Это разница с precondition (там апплай бы упал): check, для мониторинга drift и «нежелательных» состояний, которые не должны блокировать deployment. Например: «бакет должен быть versioning'ed, но если ещё не, не ломаем pipeline, шлём warning в alerting».

    ✓ check блок отработал warning'ом. Не блокирует apply.

    То же самое на OpenTofu

    OpenTofu держит CLI и state совместимыми с Terraform по командам этого шага: миграция обычно проходит через mv .terraform .terraform.bak; tofu init -upgrade. Но при первом переходе сделай backup state и прогон на feature-branch - расхождения концентрируются в новых фичах (variables в backend, state-encryption, OCI registry-backed модули). См. tf-opentofu-parity для полной матрицы.

    • → OpenTofu parity
  5. 05

    Когда что использовать

    Все три механизма похожи. Различия:

    МеханизмКогда работаетПоведение при failure
    variable.validationНа variableОшибка plan, до всего
    lifecycle.preconditionПеред созданием/изменением ресурсаОшибка plan
    lifecycle.postconditionПосле refresh, до записи stateОшибка apply
    check { assert }Параллельно applyWarning, apply продолжается

    Правила:

    • Входы юзера (variable содержимое) → variable.validation.
    • Логика «этот ресурс зависит от внешнего инварианта» → precondition.
    • «После создания значение должно быть таким» → postcondition.
    • Drift-monitoring и желаемые состояния → check.

    Не злоупотребляй. Каждая проверка = вес для plan'а. Если можно сделать невалидное состояние невозможным через типы, лучше так. Например type = number уже исключает «бакет создавать -1 раз» без validation.

    ✓ Различия ясны. Используй уместное.

    precondition между ресурсами

    Самый практичный кейс preconditions, связь ресурсов:

    hcl
    resource "aws_iam_role" "lambda" {
      name = "demo-lambda"
      # ...
    }
    resource "aws_lambda_function" "demo" {
      function_name = "demo"
      role          = aws_iam_role.lambda.arn
      lifecycle {
        precondition {
          condition     = startswith(aws_iam_role.lambda.assume_role_policy, "{")
          error_message = "IAM role must have a valid JSON assume_role_policy."
        }
      }
    }

    Это «защитный пояс», даже если IAM-роль создалась криво, лямбда не пойдёт за ней и не получит непонятную AWS-ошибку.

    Антипаттерн: писать precondition про то, что Terraform уже проверит на этапе типа. Если ты делаешь precondition с condition = var.foo != null, но variable "foo" { type = string } без default. Terraform и так не позволит передать null. Дубль.

    • → Lifecycle ресурса
    • → Variable и validation

Что ты узнал

precondition запускается до создания ресурса; postcondition, после того как state знает атрибуты; check { assert { } }, отдельный блок-валидатор, при ошибке только warning, не блокирует. Все три декларативны, ловят ошибки до облака.

команды

  • terraform planошибка precondition останавливает plan
  • terraform applypostcondition проверяется после refresh, до фиксации в state

концепции

  • · precondition блокирует: apply не пройдёт
  • · check блок только warning: для мониторинга drift, не для блокировки
  • · postcondition с self.X проверяет вычисленные атрибуты: то что variable validation не может

← предыдущий

locals и функции: убираем дублирование в HCL

следующий →

Drift detection, scheduled plan и алертинг

Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки