lesson ── terraform-garden ── ~20 мин ── 4 шагов
The root module was upgraded to AWS provider v5. The child module legacy-bucket/
is written in v3 style: acl, versioning {}, and server_side_encryption_*
all sit inside the aws_s3_bucket resource. In v4 those inline blocks were
removed, and everything became separate resources.
terraform init will fail on a version-constraint conflict (>= 3.0, < 4.0
and ~> 5.0 are incompatible). Even if you resolve that, plan will fail on
the inline blocks.
Decide: either rewrite the module in modern style, or explicitly pin the old provider for the module. The first path is the right one.
интерактивный 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
The log will contain a message like:
Error: Failed to query available provider packages
...
no available releases match the given constraints
>= 3.0, < 4.0, ~> 5.0
Root asks for v5, the child for v3. These ranges do not overlap.
✓ The conflict is visible. Now modernize the module.
Change the version range in the module so it accepts v5+:
sed -i 's|version = ">= 3.0, < 4.0"|version = ">= 5.0"|' modules/legacy-bucket/main.tf
After that, init should pass:
terraform init -upgrade 2>&1 | tee /tmp/init2.log
But plan will still fail: the inline blocks acl, versioning {}, and
server_side_encryption_* do not exist in v5.
✓ The version constraint is updated. init passes, but the HCL is still legacy.
Replace the contents of modules/legacy-bucket/main.tf with the modern style:
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
The main difference: instead of acl = "private", you use
aws_s3_bucket_ownership_controls with BucketOwnerEnforced (in v4+, ACLs
are officially deprecated). versioning and encryption are separate resources.
More on splitting things out in tf-refactor-patterns and tf-resource-block.
If you leave even one inline block (versioning {} inside aws_s3_bucket), there will be no plan. v5 does not accept them at all.
✓ The module is rewritten for v5. Now run plan.
cd /home/student/tf-garden
terraform init -upgrade
terraform plan -out=plan.tfplan
terraform apply plan.tfplan
Plan should show "Plan: 4 to add" (bucket + ownership + versioning
module.logs.aws_s3_bucket.this.✓ The module is modernized, the resources are in state. The pipeline is green.
OpenTofu also supports AWS provider v5. In practice it is the same HashiCorp binary under a different license, not rebuilt: they reuse the official provider releases. So this module migration is valid for both terraform 1.9 and tofu 1.8+. See tf-opentofu-parity for the full list of differences.
A major provider version breaks inline resource configs: in v4+, aws_s3_bucket is a bare bucket, and everything else (acl, versioning, encryption, lifecycle, public access block) becomes a separate resource. This is a pattern across the whole provider, not a one-off break.
команды
terraform init -upgradere-read modules and providers; needed after you change version in required_providersterraform providerssee which providers are requested and from which filesterraform state replace-provider OLD NEWswap the provider on existing resources in state without a destroyконцепции