terraform-provider-postgresql
terraform-provider-postgresql copied to clipboard
Role name can't be changed when grants are present | Cycle detected
Hi there,
Thank you for opening an issue. Please provide the following information:
Terraform Version
Terraform v1.0.7 on linux_amd64
- provider registry.terraform.io/cyrilgdn/postgresql v1.14.0
- provider registry.terraform.io/hashicorp/external v2.1.0
- provider registry.terraform.io/hashicorp/google v3.84.0
- provider registry.terraform.io/hashicorp/random v3.1.0
Affected Resource(s)
Please list the resources as a list, for example:
- postgresql_role
- postgresql_grant
https://gist.github.com/romanstingler/9996c4f8aec4f32d11c022161d5d2f7c
Expected Behavior
If the provider / terraform wants to update the role in-place, there is no change in internal ID, so I wouldn't expect the grants to be force replaced. Otherwise, the provider / terraform must delete all the grants as long as the change on the role hasn't been executed.
Actual Behavior
Terraform / Provider detects a Cycle and can't update the role name
Steps to Reproduce
Please list the steps required to reproduce the issue, for example:
- Create a postgres user/role
- Grant permissions to this user
- terraform apply to GCP
- change user/role name
- terraform plan shows force replacements for grants and in-place update for role
- terraform apply detects cycle (adding depends_on =[postgres_role.role] to postgres_grant doesn't fix this)
I am also seeing this. Since the provider is doing a force replacement of the grants, I found the workaround is to do a targeted destroy of the resources before trying to do a terraform plan or terraform apply.
Taking the below role as an example:
resource "postgresql_role" "somerole" {
name = "a_role"
login = true
connection_limit = 20
password = "a_password"
search_path = ["public"]
inherit = false
}
If we create a grant as below:
resource "postgresql_grant" "public_schema_privs" {
role = postgresql_role.somerole.name
database = "a_database"
schema = "public"
object_type = "schema"
privileges = ["CREATE", "USAGE"]
}
Then later when we want to rename the role, we get a cycle error as OP mentioned.
This issue requires us to destroy the grant resources with a targeted destroy, such as: terraform destroy -target=postgresql_grant.public_schema_privs in order to workaround the error.
I am also testing the possibility to use the replace_triggered_by lifecycle block argument which is a new argument in Terraform 1.2. I am hoping that it can be used to force the grants to be destroyed and recreated in order to workaround this when another resource like the role changes but I am not sure if it will be enough to stop the cycle error.
It's important to note that the above are only partial config examples and cannot reproduce this by themselves. The cycle error I'm getting involves the grant being destroyed and other resources outside of this provider which do NOT depend on this grant. In fact, when doing a terraform graph -draw-cycles, we do not see any red lines.
Testing of the replace_triggered_by resource actually went the opposite direction. It ended up creating the cycle detected error, so it seems that any destruction of the grant resource without doing a targeted destroy will cause this circular dependency. The OP is correct that there should not be a requirement to destroy and recreate the resource in Terraform state, it should be an update in place, just as the role name being updated is an update in place.
After thinking about this some more, I suspect what is causing this is using the role resource name postgresql_role.somerole.name as the role in the grant. This is logically how Terraform is supposed to work.
But I think that what's happening is that the provider has a dependency on the role for the grant, so when you change the role name, it's also trying to update the grant with the new role name, but in the flow of postgres logic it's not possible to do. You're creating a new role and deleting the old one, so the old grants go away and new grants are created for the new role.
I think the solution here is going to be to add create_before_destroy to the lifecycle block for the role resource.
This way, you create a new role and the grant can be updated to that, then the old role can be destroyed.