Skip to content

Commit 19c8a02

Browse files
feat: Use for_each instead of count to create resource (#15)
BREAKING CHANGE: Service accounts were changed to use for_each, causing a state migration. See the [upgrade guide](./docs/upgrading_to_v2.0.md) for details.
1 parent 191ef33 commit 19c8a02

File tree

9 files changed

+75
-61
lines changed

9 files changed

+75
-61
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ and this project adheres to
99

1010
## [Unreleased]
1111

12+
### Added
13+
14+
- Use `for_each` instead of `count` [#15]
15+
1216
## [2.0.2] - 2019-10-09
1317

1418
### Fixed
@@ -58,6 +62,7 @@ and this project adheres to
5862
[0.1.1]: https://github.com/terraform-google-modules/terraform-google-service-accounts/compare/v0.1.0...v0.1.1
5963
[0.1.0]: https://github.com/terraform-google-modules/terraform-google-service-accounts/releases/tag/v0.1.0
6064

65+
[#15]: https://github.com/terraform-google-modules/terraform-google-service-accounts/pull/15
6166
[#14]: https://github.com/terraform-google-modules/terraform-google-service-accounts/pull/14
6267
[#13]: https://github.com/terraform-google-modules/terraform-google-service-accounts/pull/13
6368
[#9]: https://github.com/terraform-google-modules/terraform-google-service-accounts/pull/9

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,16 @@ Functional examples are included in the
5757
| Name | Description |
5858
|------|-------------|
5959
| email | Service account email (for single use). |
60-
| emails | Service account emails. |
61-
| emails\_list | Service account emails. |
60+
| emails | Service account emails by name. |
61+
| emails\_list | Service account emails as list. |
6262
| iam\_email | IAM-format service account email (for single use). |
63-
| iam\_emails | IAM-format service account emails. |
64-
| iam\_emails\_list | IAM-format service account emails. |
63+
| iam\_emails | IAM-format service account emails by name. |
64+
| iam\_emails\_list | IAM-format service account emails as list. |
6565
| key | Service account key (for single use). |
6666
| keys | Map of service account keys. |
6767
| service\_account | Service account resource (for single use). |
68-
| service\_accounts | Service account resources. |
68+
| service\_accounts | Service account resources as list. |
69+
| service\_accounts\_map | Service account resources by name. |
6970

7071
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
7172

examples/multiple_service_accounts/versions.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
*/
1616

1717
terraform {
18-
required_version = ">= 0.12"
18+
required_version = ">= 0.12.6"
1919
}

examples/single_service_account/versions.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
*/
1616

1717
terraform {
18-
required_version = ">= 0.12"
18+
required_version = ">= 0.12.6"
1919
}

main.tf

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,84 +15,90 @@
1515
*/
1616

1717
locals {
18-
account_billing = var.grant_billing_role && var.billing_account_id != ""
19-
org_billing = var.grant_billing_role && var.billing_account_id == "" && var.org_id != ""
20-
prefix = var.prefix != "" ? "${var.prefix}-" : ""
21-
xpn = var.grant_xpn_roles && var.org_id != ""
22-
emails = [for account in google_service_account.service_accounts : account.email]
23-
iam_emails = [for email in local.emails : "serviceAccount:${email}"]
18+
account_billing = var.grant_billing_role && var.billing_account_id != ""
19+
org_billing = var.grant_billing_role && var.billing_account_id == "" && var.org_id != ""
20+
prefix = var.prefix != "" ? "${var.prefix}-" : ""
21+
xpn = var.grant_xpn_roles && var.org_id != ""
22+
service_accounts_list = [for name in var.names : google_service_account.service_accounts[name]]
23+
emails_list = [for account in local.service_accounts_list : account.email]
24+
iam_emails_list = [for email in local.emails_list : "serviceAccount:${email}"]
25+
names = toset(var.names)
26+
name_role_pairs = setproduct(local.names, toset(var.project_roles))
27+
project_roles_map_data = zipmap(
28+
[for pair in local.name_role_pairs : "${pair[0]}-${pair[1]}"],
29+
[for pair in local.name_role_pairs : {
30+
name = pair[0]
31+
role = pair[1]
32+
}]
33+
)
2434
}
2535

2636
# create service accounts
2737
resource "google_service_account" "service_accounts" {
28-
count = length(var.names)
29-
account_id = "${local.prefix}${lower(element(var.names, count.index))}"
38+
for_each = local.names
39+
account_id = "${local.prefix}${lower(each.value)}"
3040
display_name = "Terraform-managed service account"
3141
project = var.project_id
3242
}
3343

3444
# common roles
3545
resource "google_project_iam_member" "project-roles" {
36-
count = length(var.project_roles) * length(var.names)
46+
for_each = local.project_roles_map_data
3747

3848
project = element(
3949
split(
4050
"=>",
41-
element(var.project_roles, count.index % length(var.project_roles)),
51+
each.value.role
4252
),
4353
0,
4454
)
4555

4656
role = element(
4757
split(
4858
"=>",
49-
element(var.project_roles, count.index % length(var.project_roles)),
59+
each.value.role
5060
),
5161
1,
5262
)
5363

54-
member = "serviceAccount:${element(
55-
google_service_account.service_accounts.*.email,
56-
floor(count.index / length(var.project_roles)),
57-
)}"
64+
member = "serviceAccount:${google_service_account.service_accounts[each.value.name].email}"
5865
}
5966

6067
# conditionally assign billing user role at the org level
6168
resource "google_organization_iam_member" "billing_user" {
62-
count = local.org_billing ? length(var.names) : 0
63-
org_id = var.org_id
64-
role = "roles/billing.user"
65-
member = "serviceAccount:${google_service_account.service_accounts[count.index].email}"
69+
for_each = local.org_billing ? local.names : toset([])
70+
org_id = var.org_id
71+
role = "roles/billing.user"
72+
member = "serviceAccount:${google_service_account.service_accounts[each.value].email}"
6673
}
6774

6875
# conditionally assign billing user role on a specific billing account
6976
resource "google_billing_account_iam_member" "billing_user" {
70-
count = local.account_billing ? length(var.names) : 0
77+
for_each = local.account_billing ? local.names : toset([])
7178
billing_account_id = var.billing_account_id
7279
role = "roles/billing.user"
73-
member = "serviceAccount:${google_service_account.service_accounts[count.index].email}"
80+
member = "serviceAccount:${google_service_account.service_accounts[each.value].email}"
7481
}
7582

7683
# conditionally assign roles for shared VPC
7784
# ref: https://cloud.google.com/vpc/docs/shared-vpc
7885

7986
resource "google_organization_iam_member" "xpn_admin" {
80-
count = local.xpn ? length(var.names) : 0
81-
org_id = var.org_id
82-
role = "roles/compute.xpnAdmin"
83-
member = "serviceAccount:${google_service_account.service_accounts[count.index].email}"
87+
for_each = local.xpn ? local.names : toset([])
88+
org_id = var.org_id
89+
role = "roles/compute.xpnAdmin"
90+
member = "serviceAccount:${google_service_account.service_accounts[each.value].email}"
8491
}
8592

8693
resource "google_organization_iam_member" "organization_viewer" {
87-
count = local.xpn ? length(var.names) : 0
88-
org_id = var.org_id
89-
role = "roles/resourcemanager.organizationViewer"
90-
member = "serviceAccount:${google_service_account.service_accounts[count.index].email}"
94+
for_each = local.xpn ? local.names : toset([])
95+
org_id = var.org_id
96+
role = "roles/resourcemanager.organizationViewer"
97+
member = "serviceAccount:${google_service_account.service_accounts[each.value].email}"
9198
}
9299

93100
# keys
94101
resource "google_service_account_key" "keys" {
95-
count = var.generate_keys ? length(var.names) : 0
96-
service_account_id = google_service_account.service_accounts[count.index].email
102+
for_each = var.generate_keys ? local.names : toset([])
103+
service_account_id = google_service_account.service_accounts[each.value].email
97104
}
98-

outputs.tf

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,63 +16,65 @@
1616

1717
output "service_account" {
1818
description = "Service account resource (for single use)."
19-
value = google_service_account.service_accounts[0]
19+
value = local.service_accounts_list[0]
2020
}
2121

2222
output "email" {
2323
description = "Service account email (for single use)."
24-
value = google_service_account.service_accounts[0].email
24+
value = local.emails_list[0]
2525
}
2626

2727
output "iam_email" {
2828
description = "IAM-format service account email (for single use)."
29-
value = "serviceAccount:${google_service_account.service_accounts[0].email}"
29+
value = local.iam_emails_list[0]
3030
}
3131

3232
output "key" {
3333
description = "Service account key (for single use)."
34-
value = data.template_file.keys[0].rendered
34+
value = data.template_file.keys[var.names[0]]
3535
}
3636

3737
output "service_accounts" {
38-
description = "Service account resources."
38+
description = "Service account resources as list."
39+
value = local.service_accounts_list
40+
}
41+
42+
output "service_accounts_map" {
43+
description = "Service account resources by name."
3944
value = google_service_account.service_accounts
4045
}
4146

4247
output "emails" {
43-
description = "Service account emails."
44-
value = zipmap(var.names, slice(local.emails, 0, length(var.names)))
48+
description = "Service account emails by name."
49+
value = zipmap(var.names, local.emails_list)
4550
}
4651

4752
output "iam_emails" {
48-
description = "IAM-format service account emails."
49-
value = zipmap(var.names, slice(local.iam_emails, 0, length(var.names)))
53+
description = "IAM-format service account emails by name."
54+
value = zipmap(var.names, local.iam_emails_list)
5055
}
5156

5257
output "emails_list" {
53-
description = "Service account emails."
54-
value = local.emails
58+
description = "Service account emails as list."
59+
value = local.emails_list
5560
}
5661

5762
output "iam_emails_list" {
58-
description = "IAM-format service account emails."
59-
value = local.iam_emails
63+
description = "IAM-format service account emails as list."
64+
value = local.iam_emails_list
6065
}
6166

6267
data "template_file" "keys" {
63-
count = length(var.names)
68+
for_each = local.names
6469
template = "$${key}"
6570

6671
vars = {
67-
key = var.generate_keys ? base64decode(google_service_account_key.keys[count.index].private_key) : ""
72+
key = var.generate_keys ? base64decode(google_service_account_key.keys[each.value].private_key) : ""
6873
}
6974
}
7075

7176
output "keys" {
7277
description = "Map of service account keys."
7378
sensitive = true
74-
value = zipmap(
75-
var.names,
76-
slice(data.template_file.keys[*].rendered, 0, length(var.names))
77-
)
79+
value = { for k, v in data.template_file.keys : k => v.rendered }
7880
}

test/fixtures/multiple_service_accounts/versions.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
*/
1616

1717
terraform {
18-
required_version = ">= 0.12"
18+
required_version = ">= 0.12.6"
1919
}

test/fixtures/single_service_account/versions.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
*/
1616

1717
terraform {
18-
required_version = ">= 0.12"
18+
required_version = ">= 0.12.6"
1919
}

versions.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@
1515
*/
1616

1717
terraform {
18-
required_version = ">= 0.12"
18+
required_version = ">= 0.12.6"
1919
}

0 commit comments

Comments
 (0)