diff --git a/docs/upgrading_to_v2.0.md b/docs/upgrading_to_v2.0.md new file mode 100644 index 0000000..54b330c --- /dev/null +++ b/docs/upgrading_to_v2.0.md @@ -0,0 +1,29 @@ +# Upgrading to v2.0 + +The v2.0 release of *terraform-google-pubsub* is a backwards incompatible release. + +## Migration Instructions + + + +### Pubsub Subscription for_each +The `google_pubsub_subscription` resource has been updated to use `for_each` instead of `count`. This allows adding/removing subscriptions without causing a diff on unrelated subscriptions. + +Updating to this new format requires a state migration. +All `google_pubsub_subscription.pull_subscriptions` and `google_pubsub_subscription.push_subscriptions` resources with numerical indexes in the state need to be moved to resources with named indexes, where each index is the name of the subscription. + +For example: + +```bash +terraform state mv 'google_pubsub_subscription.pull_subscriptions[0]' 'google_pubsub_subscription.pull_subscriptions["pull-subscription1-name"]' +terraform state mv 'google_pubsub_subscription.pull_subscriptions[1]' 'google_pubsub_subscription.pull_subscriptions["pull-subscription2-name"]' + +terraform state mv 'google_pubsub_subscription.push_subscriptions[0]' 'google_pubsub_subscription.push_subscriptions["push-subscription1-name"]' +terraform state mv 'google_pubsub_subscription.push_subscriptions[1]' 'google_pubsub_subscription.push_subscriptions["push-subscription2-name"]' + +``` + +### Topic and subscription IAM member + +The `google_pubsub_topic_iam_member` and `google_pubsub_subscription_iam_member` resources also have been updated to use `for_each` instead of `count`. +But recreating these resources with `terraform apply` command instead of state migration is usually fine for most cases. diff --git a/main.tf b/main.tf index 64ac44d..4966d78 100644 --- a/main.tf +++ b/main.tf @@ -34,9 +34,10 @@ resource "google_project_iam_member" "token_creator_binding" { } resource "google_pubsub_topic_iam_member" "push_topic_binding" { - count = var.create_topic ? length(var.push_subscriptions) : 0 + for_each = var.create_topic ? { for i in var.push_subscriptions : i.name => i } : {} + project = var.project_id - topic = lookup(var.push_subscriptions[count.index], "dead_letter_topic", "projects/${var.project_id}/topics/${var.topic}") + topic = lookup(each.value, "dead_letter_topic", "projects/${var.project_id}/topics/${var.topic}") role = "roles/pubsub.publisher" member = "serviceAccount:${local.pubsub_svc_account_email}" depends_on = [ @@ -45,9 +46,10 @@ resource "google_pubsub_topic_iam_member" "push_topic_binding" { } resource "google_pubsub_topic_iam_member" "pull_topic_binding" { - count = var.create_topic ? length(var.pull_subscriptions) : 0 + for_each = var.create_topic ? { for i in var.pull_subscriptions : i.name => i } : {} + project = var.project_id - topic = lookup(var.pull_subscriptions[count.index], "dead_letter_topic", "projects/${var.project_id}/topics/${var.topic}") + topic = lookup(each.value, "dead_letter_topic", "projects/${var.project_id}/topics/${var.topic}") role = "roles/pubsub.publisher" member = "serviceAccount:${local.pubsub_svc_account_email}" depends_on = [ @@ -56,9 +58,10 @@ resource "google_pubsub_topic_iam_member" "pull_topic_binding" { } resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" { - count = var.create_topic ? length(var.pull_subscriptions) : 0 + for_each = var.create_topic ? { for i in var.pull_subscriptions : i.name => i } : {} + project = var.project_id - subscription = var.pull_subscriptions[count.index].name + subscription = each.value.name role = "roles/pubsub.subscriber" member = "serviceAccount:${local.pubsub_svc_account_email}" depends_on = [ @@ -67,9 +70,10 @@ resource "google_pubsub_subscription_iam_member" "pull_subscription_binding" { } resource "google_pubsub_subscription_iam_member" "push_subscription_binding" { - count = var.create_topic ? length(var.push_subscriptions) : 0 + for_each = var.create_topic ? { for i in var.push_subscriptions : i.name => i } : {} + project = var.project_id - subscription = var.push_subscriptions[count.index].name + subscription = each.value.name role = "roles/pubsub.subscriber" member = "serviceAccount:${local.pubsub_svc_account_email}" depends_on = [ @@ -93,74 +97,75 @@ resource "google_pubsub_topic" "topic" { } resource "google_pubsub_subscription" "push_subscriptions" { - count = var.create_topic ? length(var.push_subscriptions) : 0 - name = var.push_subscriptions[count.index].name + for_each = var.create_topic ? { for i in var.push_subscriptions : i.name => i } : {} + + name = each.value.name topic = google_pubsub_topic.topic.0.name project = var.project_id labels = var.subscription_labels ack_deadline_seconds = lookup( - var.push_subscriptions[count.index], + each.value, "ack_deadline_seconds", local.default_ack_deadline_seconds, ) message_retention_duration = lookup( - var.push_subscriptions[count.index], + each.value, "message_retention_duration", null, ) retain_acked_messages = lookup( - var.push_subscriptions[count.index], + each.value, "retain_acked_messages", null, ) filter = lookup( - var.push_subscriptions[count.index], + each.value, "filter", null, ) enable_message_ordering = lookup( - var.push_subscriptions[count.index], + each.value, "enable_message_ordering", null, ) dynamic "expiration_policy" { // check if the 'expiration_policy' key exists, if yes, return a list containing it. - for_each = contains(keys(var.push_subscriptions[count.index]), "expiration_policy") ? [var.push_subscriptions[count.index].expiration_policy] : [] + for_each = contains(keys(each.value), "expiration_policy") ? [each.value.expiration_policy] : [] content { ttl = expiration_policy.value } } dynamic "dead_letter_policy" { - for_each = (lookup(var.push_subscriptions[count.index], "dead_letter_topic", "") != "") ? [var.push_subscriptions[count.index].dead_letter_topic] : [] + for_each = (lookup(each.value, "dead_letter_topic", "") != "") ? [each.value.dead_letter_topic] : [] content { - dead_letter_topic = lookup(var.push_subscriptions[count.index], "dead_letter_topic", "") - max_delivery_attempts = lookup(var.push_subscriptions[count.index], "max_delivery_attempts", "5") + dead_letter_topic = lookup(each.value, "dead_letter_topic", "") + max_delivery_attempts = lookup(each.value, "max_delivery_attempts", "5") } } dynamic "retry_policy" { - for_each = (lookup(var.push_subscriptions[count.index], "maximum_backoff", "") != "") ? [var.push_subscriptions[count.index].maximum_backoff] : [] + for_each = (lookup(each.value, "maximum_backoff", "") != "") ? [each.value.maximum_backoff] : [] content { - maximum_backoff = lookup(var.push_subscriptions[count.index], "maximum_backoff", "") - minimum_backoff = lookup(var.push_subscriptions[count.index], "minimum_backoff", "") + maximum_backoff = lookup(each.value, "maximum_backoff", "") + minimum_backoff = lookup(each.value, "minimum_backoff", "") } } push_config { - push_endpoint = var.push_subscriptions[count.index]["push_endpoint"] + push_endpoint = each.value["push_endpoint"] // FIXME: This should be programmable, but nested map isn't supported at this time. // https://github.com/hashicorp/terraform/issues/2114 attributes = { - x-goog-version = lookup(var.push_subscriptions[count.index], "x-goog-version", "v1") + x-goog-version = lookup(each.value, "x-goog-version", "v1") } dynamic "oidc_token" { - for_each = (lookup(var.push_subscriptions[count.index], "oidc_service_account_email", "") != "") ? [true] : [] + for_each = (lookup(each.value, "oidc_service_account_email", "") != "") ? [true] : [] content { - service_account_email = lookup(var.push_subscriptions[count.index], "oidc_service_account_email", "") - audience = lookup(var.push_subscriptions[count.index], "audience", "") + service_account_email = lookup(each.value, "oidc_service_account_email", "") + audience = lookup(each.value, "audience", "") } } } @@ -170,57 +175,58 @@ resource "google_pubsub_subscription" "push_subscriptions" { } resource "google_pubsub_subscription" "pull_subscriptions" { - count = var.create_topic ? length(var.pull_subscriptions) : 0 - name = var.pull_subscriptions[count.index].name + for_each = var.create_topic ? { for i in var.pull_subscriptions : i.name => i } : {} + + name = each.value.name topic = google_pubsub_topic.topic.0.name project = var.project_id labels = var.subscription_labels ack_deadline_seconds = lookup( - var.pull_subscriptions[count.index], + each.value, "ack_deadline_seconds", local.default_ack_deadline_seconds, ) message_retention_duration = lookup( - var.pull_subscriptions[count.index], + each.value, "message_retention_duration", null, ) retain_acked_messages = lookup( - var.pull_subscriptions[count.index], + each.value, "retain_acked_messages", null, ) filter = lookup( - var.pull_subscriptions[count.index], + each.value, "filter", null, ) enable_message_ordering = lookup( - var.pull_subscriptions[count.index], + each.value, "enable_message_ordering", null, ) dynamic "expiration_policy" { // check if the 'expiration_policy' key exists, if yes, return a list containing it. - for_each = contains(keys(var.pull_subscriptions[count.index]), "expiration_policy") ? [var.pull_subscriptions[count.index].expiration_policy] : [] + for_each = contains(keys(each.value), "expiration_policy") ? [each.value.expiration_policy] : [] content { ttl = expiration_policy.value } } dynamic "dead_letter_policy" { - for_each = (lookup(var.pull_subscriptions[count.index], "dead_letter_topic", "") != "") ? [var.pull_subscriptions[count.index].dead_letter_topic] : [] + for_each = (lookup(each.value, "dead_letter_topic", "") != "") ? [each.value.dead_letter_topic] : [] content { - dead_letter_topic = lookup(var.pull_subscriptions[count.index], "dead_letter_topic", "") - max_delivery_attempts = lookup(var.pull_subscriptions[count.index], "max_delivery_attempts", "5") + dead_letter_topic = lookup(each.value, "dead_letter_topic", "") + max_delivery_attempts = lookup(each.value, "max_delivery_attempts", "5") } } dynamic "retry_policy" { - for_each = (lookup(var.pull_subscriptions[count.index], "maximum_backoff", "") != "") ? [var.pull_subscriptions[count.index].maximum_backoff] : [] + for_each = (lookup(each.value, "maximum_backoff", "") != "") ? [each.value.maximum_backoff] : [] content { - maximum_backoff = lookup(var.pull_subscriptions[count.index], "maximum_backoff", "") - minimum_backoff = lookup(var.pull_subscriptions[count.index], "minimum_backoff", "") + maximum_backoff = lookup(each.value, "maximum_backoff", "") + minimum_backoff = lookup(each.value, "minimum_backoff", "") } } diff --git a/outputs.tf b/outputs.tf index ba44ff5..8be3747 100644 --- a/outputs.tf +++ b/outputs.tf @@ -36,8 +36,8 @@ output "uri" { output "subscription_names" { value = concat( - google_pubsub_subscription.push_subscriptions.*.name, - google_pubsub_subscription.pull_subscriptions.*.name, + values({ for k, v in google_pubsub_subscription.push_subscriptions : k => v.name }), + values({ for k, v in google_pubsub_subscription.pull_subscriptions : k => v.name }), ) description = "The name list of Pub/Sub subscriptions" @@ -45,8 +45,8 @@ output "subscription_names" { output "subscription_paths" { value = concat( - google_pubsub_subscription.push_subscriptions.*.path, - google_pubsub_subscription.pull_subscriptions.*.path, + values({ for k, v in google_pubsub_subscription.push_subscriptions : k => v.path }), + values({ for k, v in google_pubsub_subscription.pull_subscriptions : k => v.path }), ) description = "The path list of Pub/Sub subscriptions"