admin管理员组文章数量:1123769
I have the following piece of code in TFE v.1.13. It works as intended but feels a bit repetitive:
resource "aws_ecr_repository" "repository-a" {
name = "repo-a"
#skipped
}
resource "aws_ecr_repository" "repository-b" {
name = "repo-b"
#skipped
}
resource "aws_ecr_repository" "repository-c" {
name = "repo-c"
#skipped
}
So, I have refactored it as follows:
locals {
repo_table = [
{
repo_id = "repo-id-a"
repo_name = "repo-a"
},
{
repo_id = "repo-id-b"
repo_name = "repo-b"
},
{
repo_id = "repo-id-c"
repo_name = "repo-c"
}
]
}
resource "aws_ecr_repository" "repositories" {
for_each = {for repo in local.repo_table : repo.repo_id => repo }
name = each.value.repo_name
#skipped
}
I got the following pair of errors on apply for each of the three:
Error: ECR Repository (repo-a) not empty, consider using force_delete: RepositoryNotEmptyException: The repository with name 'repo-a' in registry with id '123456789' cannot be deleted because it still contains images
Error: creating ECR Repository (repo-a): RepositoryAlreadyExistsException: The repository with name 'repo-a' already exists in the registry with id '123456789'
So, Terraform tries to delete and recreate each of them, but it can't do that because there are images in there. Is there any way to refactor the code but avoid deleting existing images/repos ?
I have the following piece of code in TFE v.1.13. It works as intended but feels a bit repetitive:
resource "aws_ecr_repository" "repository-a" {
name = "repo-a"
#skipped
}
resource "aws_ecr_repository" "repository-b" {
name = "repo-b"
#skipped
}
resource "aws_ecr_repository" "repository-c" {
name = "repo-c"
#skipped
}
So, I have refactored it as follows:
locals {
repo_table = [
{
repo_id = "repo-id-a"
repo_name = "repo-a"
},
{
repo_id = "repo-id-b"
repo_name = "repo-b"
},
{
repo_id = "repo-id-c"
repo_name = "repo-c"
}
]
}
resource "aws_ecr_repository" "repositories" {
for_each = {for repo in local.repo_table : repo.repo_id => repo }
name = each.value.repo_name
#skipped
}
I got the following pair of errors on apply for each of the three:
Error: ECR Repository (repo-a) not empty, consider using force_delete: RepositoryNotEmptyException: The repository with name 'repo-a' in registry with id '123456789' cannot be deleted because it still contains images
Error: creating ECR Repository (repo-a): RepositoryAlreadyExistsException: The repository with name 'repo-a' already exists in the registry with id '123456789'
So, Terraform tries to delete and recreate each of them, but it can't do that because there are images in there. Is there any way to refactor the code but avoid deleting existing images/repos ?
Share Improve this question edited yesterday Marko E 18k4 gold badges26 silver badges35 bronze badges asked yesterday AlexKAlexK 1,2798 silver badges20 bronze badges4 Answers
Reset to default 1Since the repositories already exist in the state terraform keeps, you cannot just remove the old blocks and recreate the repositories with the same names, as they are already known to terraform. You could try using a combination of locals (which you already have) and import
block. Based on your question, the import would look something like the following:
locals {
repo_table = [
{
repo_id = "repo-id-a"
repo_name = "repo-a"
},
{
repo_id = "repo-id-b"
repo_name = "repo-b"
},
{
repo_id = "repo-id-c"
repo_name = "repo-c"
}
]
}
import {
for_each = local.repo_table
to = aws_ecr_repository.repositories[each.key]
id = each.value.repo_name
}
resource "aws_ecr_repository" "repositories" {
for_each = local.repo_table
name = each.value.repo_name
}
After you do this, you should be able to remove the import
block entirely, and nothing would change.
From the information you’ve shared, the issue happens because Terraform treats the new for_each
resources as new resources and tries to delete and recreate the repositories. Since your repositories contain images, the deletion will fail.
Here’s how I suggest you fix this:
Keep your refactored code: Your updated code using for_each is correct, so no changes are needed there.
Import existing repositories into the Terraform state: You need to tell Terraform these repositories already exist by running:
terraform import aws_ecr_repository.repositories["repo-id-a"] repo-a
terraform import aws_ecr_repository.repositories["repo-id-b"] repo-b
terraform import aws_ecr_repository.repositories["repo-id-c"] repo-c
Use terraform plan to confirm Terraform recognizes the repositories as existing and doesn’t plan to delete or recreate them. If everything looks good, run terraform apply.
Prevent accidental deletions: To safeguard your repositories, you can add the following to the resource configuration:
lifecycle {
prevent_destroy = true
}
Hope it helps.
When you move the resource, then you must also move the corresponding state address:
terraform state mv aws_ecr_repository.repository-a 'aws_ecr_repository.repositories["repo-id-a"]'
terraform state mv aws_ecr_repository.repository-b 'aws_ecr_repository.repositories["repo-id-b"]'
terraform state mv aws_ecr_repository.repository-c 'aws_ecr_repository.repositories["repo-id-c"]'
A few more notes:
- When the resource name contains a map with a key such as above, then the
'
characters are necessary to cast it as a literal string for the shell interpreter as otherwise the command will fail. terraform plan
assists with inspecting the new state addresses for thestate mv
subcommand.- An easier refactor would probably be a
set(string)
with the repo names, but that would still cause the moved state issue you encountered.
Terraform's main mechanism for dealing with change is to compare the prior state (as produced by the previous plan/apply round, if any) with the desired state (as described by the configuration) and then propose a set of actions to try to reach a point where the two are "converged", meaning that the actual state matches the desired state.
For some differences there are several possible ways to interpret and them. That is true in your case: your prior state includes resource instances like aws_ecr_repository.repository-a
and aws_ecr_repository.repository-b
, while your desired state includes instances like aws_ecr_repository.repositories["repo-id-a"]
and aws_ecr_repository.repositories["repo-id-b"]
, and Terraform can't automatically infer any relationship between those and so by default it guesses that your intention is to destroy the old ones and create the new ones.
However, you can influence Terraform's proposals by giving it more information. In this case, you can use moved
blocks to tell Terraform that you intended this difference to be understood as a renaming of the addresses of the existing objects in Terraform, like this:
moved {
from = aws_ecr_repository.repository-a
to = aws_ecr_repository.repositories["repo-id-a"]
}
moved {
from = aws_ecr_repository.repository-b
to = aws_ecr_repository.repositories["repo-id-b"]
}
moved {
from = aws_ecr_repository.repository-c
to = aws_ecr_repository.repositories["repo-id-c"]
}
This extra information then allows Terraform to make a different proposal: to leave the existing objects unchanged and just bind them to different addresses in the Terraform state.
You can find out more about this feature in Refactoring.
版权声明:本文标题:amazon web services - Terraform attempts to recreate ECR repositories after code refactoring - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736593371a1945111.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论