lesson ── terraform-garden ── ~16 мин ── 4 шагов
Someone added two import blocks to adopt existing resources and stop creating duplicates. The cloud holds those resources under one set of names, but import.id was typed with mistakes: "logs" vs "loggs", "ci-role" vs "ci-role-old". The plan fails with "Cannot import non-existent remote object".
Find both mismatches, fix them, and prove the plan runs with no destroy.
интерактивный 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
terraform plan 2>&1 | tee /tmp/import.log
Two error lines should show up, something like:
Error: Cannot import non-existent remote object
with aws_s3_bucket.logs,
on main.tf line ...
And a matching one for aws_iam_role.ci. This means the imported
IDs garden-import-loggs / garden-ci-role-old are not present in
the cloud.
✓ Both errors are visible. Now check what is actually in the cloud.
aws --endpoint-url=http://localstack:4566 s3 ls | tee /tmp/s3.log
aws --endpoint-url=http://localstack:4566 iam list-roles \
--query 'Roles[].RoleName' --output text | tee /tmp/iam.log
This shows:
garden-import-logs (without the second g).garden-ci-role (without -old).These are your real ids. The typo is in the HCL, the cloud is correct.
✓ The real ids are found. Now fix the HCL.
Open main.tf and replace these lines:
import {to = aws_s3_bucket.logs
id = "garden-import-logs" # was: garden-import-loggs
}
and
import {to = aws_iam_role.ci
id = "garden-ci-role" # was: garden-ci-role-old
}
One symmetric way with sed:
sed -i 's/garden-import-loggs/garden-import-logs/' main.tf
sed -i 's/garden-ci-role-old/garden-ci-role/' main.tf
The S3 typo is an extra g. The IAM typo is an extra -old suffix.
✓ Typos are gone. Now check the plan.
terraform plan -out=plan.tfplan
terraform show plan.tfplan | head -40
The plan should now contain these lines:
# aws_s3_bucket.logs will be imported
# aws_iam_role.ci will be imported
There should be no # ... will be destroyed. A destroy would mean
the HCL describes the resource differently and the provider wants to
recreate it. Here the HCL matches the cloud, so you should get a
clean import.
Apply (optional):
terraform apply plan.tfplan
✓ Bucket and role are in state, with no destroy. The import block did its job.
OpenTofu has supported import blocks since 1.6. The behavior and
the messages are identical. The one difference is that
-generate-config-out is more stable on OT, because they patched
a few early bugs with unicode names sooner. See
tf-opentofu-parity.
Import adopts whatever you point at with id. If that id does not exist, the provider returns a 404 and Terraform complains about a "non-existent remote object". The cure is to check the id by hand through the provider CLI (aws s3 ls, aws iam list-roles), and better still, to wrap a guard around it with a data source.
команды
aws --endpoint-url=http://localstack:4566 s3 lscheck the S3 bucket names before importaws --endpoint-url=http://localstack:4566 iam list-roles --query 'Roles[].RoleName'check the IAM role namesterraform plan -generate-config-out=imported.tfgenerate HCL for the resource you are importing (TF 1.5+)концепции