问题
I wrote some configuration today that uses "loops", but only afterwards I wondered if this is the right path to go, since terraform keeps the resources in the state file as a list/array.
Consider the following configuration:
locals {
users_list = [ "ab", "cd", "ef" ]
}
resource "aws_iam_user" "users" {
count = "${length(local.users_list)}"
name = "${local.users_list["${count.index}"]}"
path = "/"
}
Running 'terraform apply' will create the users, and create the following resources in the state file:
- aws_iam_user.users[0]
- aws_iam_user.users[1]
- aws_iam_user.users[2]
But if, for example, I remove one of the first two users, like so:
locals {
users_list = [ "cd", "ef" ]
}
then terraform will try to change the resources in the state file ( [0] --> "cd", [1] --> "ef" ), and the users themselves in AWS, which can be catastrophic, since every user will have his own keys, and doing so will create a mess. This is relevant to other resource types as well, although there are resources that deleting and creating again won't do such a mess, but still this is a wrong.
So, to my question, as in the title - maybe I got it all wrong? Or this is just the way it works? (making this whole "looping" mechanism useless)
回答1:
terraform before v0.11.x doesn't officially support loops in fact. The way to use with count.index
as loops is coming from the blog Terraform tips & tricks: loops, if-statements, and gotchas
From version 0.12 (still in beta currently), it supports loops with new key word for_each, but I still don't guarantee if it fixes the problem in your question.
So I show the detail what the problem it is, and how to fix it, people like @Aniket Chopade can understand where this problem comes from.
After change the locals,
$ terraform apply -auto-approve
aws_iam_user.users[0]: Refreshing state... (ID: ab)
aws_iam_user.users[1]: Refreshing state... (ID: cd)
aws_iam_user.users[2]: Refreshing state... (ID: ef)
aws_iam_user.users[2]: Destroying... (ID: ef)
aws_iam_user.users[1]: Modifying... (ID: cd)
name: "cd" => "ef"
aws_iam_user.users[0]: Modifying... (ID: ab)
name: "ab" => "cd"
aws_iam_user.users[2]: Destruction complete after 2s
Error: Error applying plan:
2 error(s) occurred:
* aws_iam_user.users[0]: 1 error(s) occurred:
* aws_iam_user.users.0: Error updating IAM User ab: EntityAlreadyExists: User with name cd already exists.
status code: 409, request id: 24853da7-452c-11e9-a853-bf4c89d8ebba
* aws_iam_user.users[1]: 1 error(s) occurred:
* aws_iam_user.users.1: Error updating IAM User cd: EntityAlreadyExists: User with name ef already exists.
status code: 409, request id: 24839027-452c-11e9-b3d5-3deb12943195
I have to taint these resources, mark them to be destroyed and apply again.
$ terraform taint aws_iam_user.users.1
The resource aws_iam_user.users.1 in the module root has been marked as tainted!
$ terraform taint aws_iam_user.users.0
The resource aws_iam_user.users.0 in the module root has been marked as tainted!
$ terraform apply -auto-approve
...
aws_iam_user.users[0]: Destroying... (ID: ab)
aws_iam_user.users[1]: Destroying... (ID: cd)
aws_iam_user.users[0]: Destruction complete after 2s
aws_iam_user.users[0]: Creating...
arn: "" => "<computed>"
force_destroy: "" => "false"
name: "" => "cd"
path: "" => "/"
unique_id: "" => "<computed>"
aws_iam_user.users[1]: Destruction complete after 2s
aws_iam_user.users[1]: Creating...
arn: "" => "<computed>"
force_destroy: "" => "false"
name: "" => "ef"
path: "" => "/"
unique_id: "" => "<computed>"
My conclusion is, in current situation, taint
the resources to force terraform create new resources if you change the order in a list.
来源:https://stackoverflow.com/questions/55132357/are-terraform-loops-useless-or-am-i-missing-something