lesson ── terraform-garden ── ~20 мин ── 4 шагов
Root-модуль обновили до AWS provider v5. Child-модуль legacy-bucket/
написан в стиле v3, acl, versioning {}, server_side_encryption_*
внутри ресурса aws_s3_bucket. В v4 эти inline-блоки удалили: всё
превратилось в отдельные ресурсы.
terraform init свалится с конфликтом version-constraints (>= 3.0, < 4.0
и ~> 5.0, несовместимы). Даже если разрешишь, plan упадёт на
inline-блоках.
Реши: либо переписать модуль в современный стиль, либо явно зафиксировать старый провайдер для модуля. Правильный путь, первый.
интерактивный sandbox
Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.
stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя
cd /home/student/tf-garden
terraform init 2>&1 | tee /tmp/init.log
В логе будет сообщение типа:
Error: Failed to query available provider packages
...
no available releases match the given constraints
>= 3.0, < 4.0, ~> 5.0
Root просит v5, child, v3. Эти диапазоны не пересекаются.
✓ Конфликт виден. Теперь, модернизация модуля.
Замени версионный диапазон в модуле, пусть принимает v5+:
sed -i 's|version = ">= 3.0, < 4.0"|version = ">= 5.0"|' modules/legacy-bucket/main.tf
После, init должен пройти:
terraform init -upgrade 2>&1 | tee /tmp/init2.log
Но plan всё равно упадёт, inline-блоки acl, versioning {},
server_side_encryption_* в v5 не существуют.
✓ Version-constraint обновлён. init проходит, но HCL ещё legacy.
Замени содержимое modules/legacy-bucket/main.tf на современный стиль:
cat > modules/legacy-bucket/main.tf <<'EOF'
terraform { required_providers { aws = {source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
variable "name" {type = string
}
resource "aws_s3_bucket" "this" {bucket = var.name
}
resource "aws_s3_bucket_ownership_controls" "this" {bucket = aws_s3_bucket.this.id
rule {object_ownership = "BucketOwnerEnforced"
}
}
resource "aws_s3_bucket_versioning" "this" {bucket = aws_s3_bucket.this.id
versioning_configuration {status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {bucket = aws_s3_bucket.this.id
rule { apply_server_side_encryption_by_default {sse_algorithm = "AES256"
}
}
}
output "arn" {value = aws_s3_bucket.this.arn
}
EOF
Главное отличие: вместо acl = "private", aws_s3_bucket_ownership_controls
с BucketOwnerEnforced (в v4+ ACL'и официально deprecated). versioning и
encryption, отдельные ресурсы.
Подробнее про разнесение, tf-refactor-patterns и tf-resource-block.
Если оставишь хотя бы один inline-блок (versioning {} внутри aws_s3_bucket), плана не будет. v5 их не принимает совсем.
✓ Модуль переписан под v5. Теперь, plan.
cd /home/student/tf-garden
terraform init -upgrade
terraform plan -out=plan.tfplan
terraform apply plan.tfplan
Plan должен показать «Plan: 4 to add» (бакет + ownership + versioning
module.logs.aws_s3_bucket.this.✓ Модуль модернизирован, ресурсы в state. Pipeline зелёный.
OpenTofu тоже поддерживает AWS provider v5, фактически это тот же бинарь от HashiCorp под другой лицензией не пересобирается, они переиспользуют официальные релизы провайдеров. Поэтому миграция этого модуля валидна как для terraform 1.9, так и для tofu 1.8+. См. tf-opentofu-parity для полного списка различий.
Major-version провайдера ломает inline-конфиги ресурсов: aws_s3_bucket в v4+, это голый бакет, всё остальное (acl, versioning, encryption, lifecycle, public access block), отдельные ресурсы. Это паттерн на весь провайдер, не разовая поломка.
команды
terraform init -upgradeперечитать модули и провайдеры; нужно после изменения version в required_providersterraform providersпосмотреть какие провайдеры запрошены и из каких файловterraform state replace-provider OLD NEWсменить провайдера у существующих ресурсов в state без destroyконцепции