Skip to content

Commit

Permalink
fix: Use subscription names as the keys instead of numeric indexes (#67)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The state location for subscriptions has moved, see the upgrade guide for details.
  • Loading branch information
askoriy authored Apr 6, 2021
1 parent bf6a051 commit b07ab12
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 45 deletions.
29 changes: 29 additions & 0 deletions docs/upgrading_to_v2.0.md
Original file line number Diff line number Diff line change
@@ -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.
88 changes: 47 additions & 41 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -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 = [
Expand All @@ -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 = [
Expand All @@ -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 = [
Expand All @@ -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", "")
}
}
}
Expand All @@ -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", "")
}
}

Expand Down
8 changes: 4 additions & 4 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ 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"
}

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"
Expand Down

0 comments on commit b07ab12

Please sign in to comment.