Skip to content

Commit 15298c2

Browse files
mnahkiesVhaosg-awmalik
authored
fix!: pass iam_user_emails as map to postgres module (#414)
Co-authored-by: Kareem Daggash <[email protected]> Co-authored-by: Awais Malik <[email protected]>
1 parent 59b32af commit 15298c2

File tree

7 files changed

+120
-25
lines changed

7 files changed

+120
-25
lines changed

docs/upgrading_to_sql_db_15.0.0.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Upgrading to SQL DB 15.0.0
2+
3+
The 15.0.0 release of SQL DB is a backward incompatible release.
4+
This incompatibility affects `postgresql` submodule that uses IAM authentication.
5+
6+
## Migration Instructions
7+
8+
### `iam_user_emails` moved to `iam_users` and changed to be an list(object)
9+
10+
Prior to the `15.0.0` release, the `postgresql` submodule took a `list(string)` for `iam_user_emails`.
11+
12+
This meant that it was not possible to create a `google_service_account` and corresponding `google_sql_user`
13+
in a single `terraform apply` because the `email` is `(known after apply)` and was used in the resource address.
14+
See [issue 413](https://github.com/terraform-google-modules/terraform-google-sql-db/issues/413) for more details.
15+
16+
In the `15.0.0` release, the input/output variable has been renamed from `iam_user_emails` to `iam_users`, and
17+
now accepts a `list(object({id=string, email=string}))`, where `id` is used in the resource address.
18+
19+
This allows a value that is known at `plan` time to be passed, for example `google_service_account.my_service_account.account_id`
20+
would be a good candidate for this.
21+
22+
```diff
23+
module "pg" {
24+
source = "GoogleCloudPlatform/sql-db/google//modules/postgresql"
25+
- version = "~> 14.0"
26+
+ version = "~> 15.0"
27+
28+
name = "test"
29+
database_version = "POSTGRES_14"
30+
project_id = var.project_id
31+
zone = "europe-west1-b"
32+
region = "europe-west1"
33+
tier = "db-custom-1-3840"
34+
35+
database_flags = [
36+
{
37+
name = "cloudsql.iam_authentication"
38+
value = "on"
39+
}
40+
]
41+
42+
- iam_user_emails = [
43+
- "test-sa@${var.project_id}.iam.gserviceaccount.com",
44+
45+
- ]
46+
+ iam_users = [
47+
+ {
48+
+ id = "test-sa",
49+
+ email = "test-sa@${var.project_id}.iam.gserviceaccount.com",
50+
+ },
51+
+ {
52+
+ id = "john.doe",
53+
+ email = "[email protected]",
54+
+ },
55+
+ ]
56+
}
57+
58+
+ moved {
59+
+ from = module.pg.google_sql_user.iam_account["test-sa@${var.project_id}.iam.gserviceaccount.com true"]
60+
+ to = module.pg.google_sql_user.iam_account["test-sa"]
61+
+ }
62+
63+
+ moved {
64+
+ from = module.pg.google_sql_user.iam_account["[email protected] false"]
65+
+ to = module.pg.google_sql_user.iam_account["john.doe"]
66+
+ }
67+
68+
```
69+
70+
We recommend using `moved` blocks as [documented here](https://developer.hashicorp.com/terraform/language/modules/develop/refactoring)
71+
to explicitly migrate your state. You can find the list of state addresses to move using:
72+
73+
```shell
74+
terraform state list | grep google_sql_user.iam_account
75+
```
76+
77+
If you do not wish to use `moved` blocks, you can instead migrate your state using `terraform state mv`:
78+
```shell
79+
terraform state mv \
80+
'module.pg.google_sql_user.iam_account["test-sa@$my-project-id.iam.gserviceaccount.com true"]' \
81+
'module.pg.google_sql_user.iam_account["test-sa"]'
82+
```

examples/postgresql-public-iam/main.tf

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,14 @@ module "postgresql-db" {
6969
]
7070

7171
# Supports creation of both IAM Users and IAM Service Accounts with provided emails
72-
iam_user_emails = [
73-
var.cloudsql_pg_sa,
74-
72+
iam_users = [
73+
{
74+
id = "cloudsql_pg_sa",
75+
email = var.cloudsql_pg_sa
76+
},
77+
{
78+
id = "dbadmin",
79+
80+
}
7581
]
7682
}

modules/postgresql/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Note: CloudSQL provides [disk autoresize](https://cloud.google.com/sql/docs/mysq
3232
| enable\_random\_password\_special | Enable special characters in generated random passwords. | `bool` | `false` | no |
3333
| encryption\_key\_name | The full path to the encryption key used for the CMEK disk encryption | `string` | `null` | no |
3434
| follow\_gae\_application | A Google App Engine application whose zone to remain in. Must be in the same region as this instance. | `string` | `null` | no |
35-
| iam\_user\_emails | A list of IAM users to be created in your cluster | `list(string)` | `[]` | no |
35+
| iam\_users | A list of IAM users to be created in your CloudSQL instance | <pre>list(object({<br> id = string,<br> email = string<br> }))</pre> | `[]` | no |
3636
| insights\_config | The insights\_config settings for the database. | <pre>object({<br> query_string_length = number<br> record_application_tags = bool<br> record_client_address = bool<br> })</pre> | `null` | no |
3737
| ip\_configuration | The ip configuration for the master instances. | <pre>object({<br> authorized_networks = list(map(string))<br> ipv4_enabled = bool<br> private_network = string<br> require_ssl = bool<br> allocated_ip_range = string<br> enable_private_path_for_google_cloud_services = optional(bool)<br> })</pre> | <pre>{<br> "allocated_ip_range": null,<br> "authorized_networks": [],<br> "enable_private_path_for_google_cloud_services": false,<br> "ipv4_enabled": true,<br> "private_network": null,<br> "require_ssl": null<br>}</pre> | no |
3838
| maintenance\_window\_day | The day of week (1-7) for the master instance maintenance. | `number` | `1` | no |
@@ -64,7 +64,7 @@ Note: CloudSQL provides [disk autoresize](https://cloud.google.com/sql/docs/mysq
6464
|------|-------------|
6565
| additional\_users | List of maps of additional users and passwords |
6666
| generated\_user\_password | The auto generated default user password if not input password was provided |
67-
| iam\_user\_emails | The list of the IAM users with the access to the Cloudsql instance |
67+
| iam\_users | The list of the IAM users with access to the CloudSQL instance |
6868
| instance\_connection\_name | The connection name of the master instance to be used in connection strings |
6969
| instance\_first\_ip\_address | The first IPv4 address of the addresses assigned. |
7070
| instance\_ip\_address | The IPv4 address assigned for the master instance |

modules/postgresql/main.tf

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@ locals {
2626

2727
databases = { for db in var.additional_databases : db.name => db }
2828
users = { for u in var.additional_users : u.name => u }
29-
iam_users = [for iu in var.iam_user_emails : {
30-
email = iu,
31-
is_account_sa = trimsuffix(iu, "gserviceaccount.com") == iu ? false : true
32-
}]
29+
iam_users = {
30+
for user in var.iam_users : user.id => {
31+
email = user.email,
32+
is_account_sa = trimsuffix(user.email, "gserviceaccount.com") == user.email ? false : true
33+
}
34+
}
3335

3436
// HA method using REGIONAL availability_type requires point in time recovery to be enabled
3537
point_in_time_recovery_enabled = var.availability_type == "REGIONAL" ? lookup(var.backup_configuration, "point_in_time_recovery_enabled", true) : lookup(var.backup_configuration, "point_in_time_recovery_enabled", false)
@@ -262,10 +264,8 @@ resource "google_sql_user" "additional_users" {
262264
}
263265

264266
resource "google_sql_user" "iam_account" {
265-
for_each = {
266-
for iu in local.iam_users :
267-
"${iu.email} ${iu.is_account_sa}" => iu
268-
}
267+
for_each = local.iam_users
268+
269269
project = var.project_id
270270
name = each.value.is_account_sa ? (
271271
trimsuffix(each.value.email, ".gserviceaccount.com")

modules/postgresql/metadata.yaml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,13 @@ spec:
180180
- name: follow_gae_application
181181
description: A Google App Engine application whose zone to remain in. Must be in the same region as this instance.
182182
type: string
183-
- name: iam_user_emails
184-
description: A list of IAM users to be created in your cluster
185-
type: list(string)
183+
- name: iam_users
184+
description: A list of IAM users to be created in your CloudSQL instance
185+
type: |-
186+
list(object({
187+
id = string
188+
email = string
189+
}))
186190
default: []
187191
- name: insights_config
188192
description: The insights_config settings for the database.
@@ -331,8 +335,8 @@ spec:
331335
description: List of maps of additional users and passwords
332336
- name: generated_user_password
333337
description: The auto generated default user password if not input password was provided
334-
- name: iam_user_emails
335-
description: The list of the IAM users with the access to the Cloudsql instance
338+
- name: iam_users
339+
description: The list of the IAM users with access to the CloudSQL instance
336340
- name: instance_connection_name
337341
description: The connection name of the master instance to be used in connection strings
338342
- name: instance_first_ip_address

modules/postgresql/outputs.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ output "additional_users" {
108108
sensitive = true
109109
}
110110

111-
output "iam_user_emails" {
112-
description = "The list of the IAM users with the access to the Cloudsql instance"
113-
value = var.iam_user_emails
111+
output "iam_users" {
112+
description = "The list of the IAM users with access to the CloudSQL instance"
113+
value = var.iam_users
114114
}
115115

116116
// Resources

modules/postgresql/variables.tf

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,13 @@ variable "additional_users" {
322322
}
323323
}
324324

325-
variable "iam_user_emails" {
326-
description = "A list of IAM users to be created in your cluster"
327-
type = list(string)
328-
default = []
325+
variable "iam_users" {
326+
description = "A list of IAM users to be created in your CloudSQL instance"
327+
type = list(object({
328+
id = string,
329+
email = string
330+
}))
331+
default = []
329332
}
330333

331334
variable "create_timeout" {

0 commit comments

Comments
 (0)