Recreating of push_topic_binding every time on version 2
gjermundgaraba opened this issue · 14 comments
It seems like the resource "google_pubsub_topic_iam_member" "push_topic_binding" is being recreated needlessly every time because of "unknown" member.
# module.google_pubsub["REMOVED"].google_pubsub_topic_iam_member.push_topic_binding["REMOVED"] must be replaced
-/+ resource "google_pubsub_topic_iam_member" "push_topic_binding" {
~ etag = "REMOVED" -> (known after apply)
~ id = "REMOVED" -> (known after apply)
~ member = "serviceAccount:service-REMOVED@gcp-sa-pubsub.iam.gserviceaccount.com" -> (known after apply) # forces replacement
# (3 unchanged attributes hidden)
}
The pubsub topics and everything was set up in a new project, so there is no lingering old state that should cause this. I am not an expert in terraform, but it seems to be related to the way the pubsub_svc_account_email is created from the data block:
pubsub_svc_account_email = "service-${data.google_project.project.number}@gcp-sa-pubsub.iam.gserviceaccount.com"
Here is my setup as well for reference in case I have done something wrong that might cause this:
module "google_pubsub" {
depends_on = [
module.project_setup,
google_project_iam_member.pubsub_service_account_roles,
module.empower_platform_cloud_build_setup,
module.cloud_run]
for_each = local.pubsub_topics_and_subscriptions
source = "terraform-google-modules/pubsub/google"
version = "~> 2.0"
topic = each.key
create_topic = each.value.create_topic
project_id = var.project
push_subscriptions = [for subscription in each.value.subscriptions: {
name = "subscription-${each.key}-${subscription.service_name}"
oidc_service_account_email = google_service_account.pubsub_subscription_service_account.email
ack_deadline_seconds = 200
push_endpoint = "${lookup(module.cloud_run.deployed_cloud_run_services, subscription.service_name).url}${subscription.root_path}/pubsub/${each.key}"
enable_message_ordering = true
}]
}
Thanks for the report, this does look like a bug. We should add ignore_changes
on the field.
I believe the issue is that both pull_topic_binding & push_topic_binding loop through the subscriptions to create the bindings when this should be a one-time thing. Additionally, don't think we need them both since it's the same service account binding to the same role i.e. roles/pubsub.publisher in both cases. Something like topic_binding should do.
@morgante - let me know what you think. I can submit a PR for it.
We need to loop through the subscriptions, but we can ignore changes to the member. A PR would be welcome.
PR is up for review.
I believe this is being triggered due to module depends_on in your setup. Module depends_on is deferring the read to apply time so even with the ignore_changes
if any resources in the depends_on
change, there will an extra read operation. Adding ignore changes throughout will prevent recreate operation though.
@morgante I think another approach could be to let optionally users pass in pubsub_svc_account_email
while preserving existing default behavior. This means we wont have to have ignore_changes
throughout the module.
Module depends_on is deferring the read to apply time so even with the ignore_changes if any resources in the depends_on change, there will an extra read operation. Adding ignore changes throughout will prevent recreate operation though.
Good point, I think maybe the dependencies might not all be needed? (Especially not explicitly.)
@morgante I think another approach could be to let optionally users pass in pubsub_svc_account_email while preserving existing default behavior. This means we wont have to have ignore_changes throughout the module.
I'd rather not force users to look that up manually.
Good point, I think maybe the dependencies might not all be needed?
Yeah I agree, if there was no module depends_on and only implicit deps the dag should be evaluated properly. This is also seems to be Terraform's official stance on this issue hashicorp/terraform#26383 (comment)
@bjaanes could you elaborate on why you need these explicit dependencies
depends_on = [
module.project_setup,
google_project_iam_member.pubsub_service_account_roles,
module.empower_platform_cloud_build_setup,
module.cloud_run]
@bjaanes could you elaborate on why you need these explicit dependencies
I technically might not. It is just a practice I developed on my own so I can easily see dependencies and understand the order of things.
There might be one exception if I hadn't set this up exactly like I do, which is the module.project_setup which sets up all the roles and permissions needed for the terraform service account I am using. However, in this particular case it should be OK since the "module.cloud_run.deployed_cloud_run_services" has an explicit dependency on the project_setup part.
If you have suggestions on doing this better I would of course appreciate any feedback on that ;)
@bjaanes thanks for the context. Could you check if this error still happens without the explicit dependencies?
@bharathkkb I just did an update before and after removing the explicit dependencies and it does indeed solve the problem.
I am experiencing something similar: I am upgrading from 1.9.0 to 2.0.0 and noticed that a lot of resources are being destroyed/created.
Namely google_pubsub_subscription
s and google_pubsub_subscription_iam_member
s. Is there a workaround for this to prevent this from happening?
@esn89 Please share a copy of your config and Terraform plan for us to understand why it's being recreated.
A copy of the config is here:
module "pubsub-01" {
source = "git::https://github.com/terraform-google-modules/terraform-google-pubsub.git?ref=v2.0.0"
project_id = var.project_id
topic = var.topics[0]
pull_subscriptions = [
{
name = "test1"
expiration_policy = ""
ack_deadline_seconds = 20
},
{
name = "test1"
expiration_policy = ""
ack_deadline_seconds = 20
},
]
}
# ...so on and so forth for each of the topics in the variables of "topics". Not looped
module "pubsub-02" {
source = "git::https://github.com/terraform-google-modules/terraform-google-pubsub.git?ref=v2.0.0"
project_id = var.project_id
topic = var.topics[0]
pull_subscriptions = [
{
name = "test2"
expiration_policy = ""
ack_deadline_seconds = 20
},
{
name = "test2"
expiration_policy = ""
ack_deadline_seconds = 20
},
]
}
Inside of variables.tf:
variable "topics" {
description = "Metadata Topics"
type = list(any)
default = ["test1", "test2", "test3", "test4", "test5"]
}
The plan:
# module.pubsub-01.google_pubsub_subscription.pull_subscriptions will be destroyed
- resource "google_pubsub_subscription" "pull_subscriptions" {
- ack_deadline_seconds = 20 -> null
- enable_message_ordering = false -> null
- id = "projects/myproject/subscriptions/test1" -> null
- labels = {} -> null
- message_retention_duration = "604800s" -> null
- name = "test1" -> null
- path = "projects/myproject/subscriptions/test1" -> null
- project = "myproject" -> null
- retain_acked_messages = false -> null
- topic = "projects/myproject/topics/schema" -> null
- expiration_policy {}
}
# module.pubsub-01.google_pubsub_subscription.pull_subscriptions[1] will be destroyed
- resource "google_pubsub_subscription" "pull_subscriptions" {
- ack_deadline_seconds = 20 -> null
- enable_message_ordering = false -> null
- id = "projects/myproject/subscriptions/test2" -> null
- labels = {} -> null
- message_retention_duration = "604800s" -> null
- name = "test2" -> null
- path = "projects/myproject/subscriptions/test2" -> null
- project = "myproject" -> null
- retain_acked_messages = false -> null
- topic = "projects/myproject/topics/schema" -> null
- expiration_policy {}
}
# module.pubsub-01.google_pubsub_subscription.pull_subscriptions["test1"] will be created
+ resource "google_pubsub_subscription" "pull_subscriptions" {
+ ack_deadline_seconds = 20
+ id = (known after apply)
+ message_retention_duration = "604800s"
+ name = "test1"
+ path = (known after apply)
+ project = "myproject"
+ topic = "schema"
+ expiration_policy {}
}
# module.pubsub-01.google_pubsub_subscription.pull_subscriptions["test2"] will be created
+ resource "google_pubsub_subscription" "pull_subscriptions" {
+ ack_deadline_seconds = 20
+ id = (known after apply)
+ message_retention_duration = "604800s"
+ name = "test2"
+ path = (known after apply)
+ project = "myproject"
+ topic = "schema"
+ expiration_policy {}
}
# module.pubsub-01.google_pubsub_subscription_iam_member.pull_subscription_binding will be destroyed
- resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
- etag = "BwXApy5W2/Q=" -> null
- id = "projects/myproject/subscriptions/test1/roles/pubsub.subscriber/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.subscriber" -> null
- subscription = "test1" -> null
}
# module.pubsub-01.google_pubsub_subscription_iam_member.pull_subscription_binding[1] will be destroyed
- resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
- etag = "BwXApy5SJ7o=" -> null
- id = "projects/myproject/subscriptions/test2/roles/pubsub.subscriber/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.subscriber" -> null
- subscription = "test2" -> null
}
# module.pubsub-01.google_pubsub_subscription_iam_member.pull_subscription_binding["test1"] will be created
+ resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.subscriber"
+ subscription = "test1"
}
# module.pubsub-01.google_pubsub_subscription_iam_member.pull_subscription_binding["test2"] will be created
+ resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.subscriber"
+ subscription = "test2"
}
# module.pubsub-01.google_pubsub_topic_iam_member.pull_topic_binding will be destroyed
- resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
- etag = "BwXApy4NRek=" -> null
- id = "projects/myproject/topics/schema/roles/pubsub.publisher/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.publisher" -> null
- topic = "projects/myproject/topics/schema" -> null
}
# module.pubsub-01.google_pubsub_topic_iam_member.pull_topic_binding[1] will be destroyed
- resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
- etag = "BwXApy4NRek=" -> null
- id = "projects/myproject/topics/schema/roles/pubsub.publisher/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.publisher" -> null
- topic = "projects/myproject/topics/schema" -> null
}
# module.pubsub-01.google_pubsub_topic_iam_member.pull_topic_binding["test1"] will be created
+ resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.publisher"
+ topic = "projects/myproject/topics/schema"
}
# module.pubsub-01.google_pubsub_topic_iam_member.pull_topic_binding["test2"] will be created
+ resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.publisher"
+ topic = "projects/myproject/topics/schema"
}
# module.pubsub-02.google_pubsub_subscription.pull_subscriptions will be destroyed
- resource "google_pubsub_subscription" "pull_subscriptions" {
- ack_deadline_seconds = 20 -> null
- enable_message_ordering = false -> null
- id = "projects/myproject/subscriptions/1-application" -> null
- labels = {} -> null
- message_retention_duration = "604800s" -> null
- name = "1-application" -> null
- path = "projects/myproject/subscriptions/1-application" -> null
- project = "myproject" -> null
- retain_acked_messages = false -> null
- topic = "projects/myproject/topics/application" -> null
- expiration_policy {}
}
# module.pubsub-02.google_pubsub_subscription.pull_subscriptions[1] will be destroyed
- resource "google_pubsub_subscription" "pull_subscriptions" {
- ack_deadline_seconds = 20 -> null
- enable_message_ordering = false -> null
- id = "projects/myproject/subscriptions/2-application" -> null
- labels = {} -> null
- message_retention_duration = "604800s" -> null
- name = "2-application" -> null
- path = "projects/myproject/subscriptions/2-application" -> null
- project = "myproject" -> null
- retain_acked_messages = false -> null
- topic = "projects/myproject/topics/application" -> null
- expiration_policy {}
}
# module.pubsub-02.google_pubsub_subscription.pull_subscriptions["1-application"] will be created
+ resource "google_pubsub_subscription" "pull_subscriptions" {
+ ack_deadline_seconds = 20
+ id = (known after apply)
+ message_retention_duration = "604800s"
+ name = "1-application"
+ path = (known after apply)
+ project = "myproject"
+ topic = "application"
+ expiration_policy {}
}
# module.pubsub-02.google_pubsub_subscription.pull_subscriptions["2-application"] will be created
+ resource "google_pubsub_subscription" "pull_subscriptions" {
+ ack_deadline_seconds = 20
+ id = (known after apply)
+ message_retention_duration = "604800s"
+ name = "2-application"
+ path = (known after apply)
+ project = "myproject"
+ topic = "application"
+ expiration_policy {}
}
# module.pubsub-02.google_pubsub_subscription_iam_member.pull_subscription_binding will be destroyed
- resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
- etag = "BwXApy4F6OE=" -> null
- id = "projects/myproject/subscriptions/1-application/roles/pubsub.subscriber/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.subscriber" -> null
- subscription = "1-application" -> null
}
# module.pubsub-02.google_pubsub_subscription_iam_member.pull_subscription_binding[1] will be destroyed
- resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
- etag = "BwXApy4HWYQ=" -> null
- id = "projects/myproject/subscriptions/2-application/roles/pubsub.subscriber/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.subscriber" -> null
- subscription = "2-application" -> null
}
# module.pubsub-02.google_pubsub_subscription_iam_member.pull_subscription_binding["1-application"] will be created
+ resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.subscriber"
+ subscription = "1-application"
}
# module.pubsub-02.google_pubsub_subscription_iam_member.pull_subscription_binding["2-application"] will be created
+ resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.subscriber"
+ subscription = "2-application"
}
# module.pubsub-02.google_pubsub_topic_iam_member.pull_topic_binding will be destroyed
- resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
- etag = "BwXApy22N5A=" -> null
- id = "projects/myproject/topics/application/roles/pubsub.publisher/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.publisher" -> null
- topic = "projects/myproject/topics/application" -> null
}
# module.pubsub-02.google_pubsub_topic_iam_member.pull_topic_binding[1] will be destroyed
- resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
- etag = "BwXApy22N5A=" -> null
- id = "projects/myproject/topics/application/roles/pubsub.publisher/serviceaccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com" -> null
- project = "myproject" -> null
- role = "roles/pubsub.publisher" -> null
- topic = "projects/myproject/topics/application" -> null
}
# module.pubsub-02.google_pubsub_topic_iam_member.pull_topic_binding["1-application"] will be created
+ resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.publisher"
+ topic = "projects/myproject/topics/application"
}
# module.pubsub-02.google_pubsub_topic_iam_member.pull_topic_binding["2-application"] will be created
+ resource "google_pubsub_topic_iam_member" "pull_topic_binding" {
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:service-123412341234@gcp-sa-pubsub.iam.gserviceaccount.com"
+ project = "myproject"
+ role = "roles/pubsub.publisher"
+ topic = "projects/myproject/topics/application"
}
This is from changing the module version from 1.9.0 to 2.0.0.
As noted in the upgrade guide, the state location for subscriptions has moved. You will need to do a one-time migration, but it should not attempt to recreate them once you have.