由于更新的架构,如何更新 google_bigquery_table_iam_member 以指向新的 table
How to update google_bigquery_table_iam_member to point to new table on recreation due to an updated schema
我有一个 BigQuery table 并且将一个服务帐户作为 iam 成员添加到此 table:
resource "google_bigquery_table" "table" {
dataset_id = dataset
table_id = table
project = project
schema = "jsonSchema.json"
}
resource "google_bigquery_table_iam_member" "access_right" {
project = google_bigquery_table.table.project
dataset_id = google_bigquery_table.table.dataset_id
table_id = google_bigquery_table.table.table_id
role = "roles/bigquery.dataEditor"
member = "serviceAccount:serviceAccount@GCPserviceAccount.com"
}
从 jsonSchema.json
中删除一列并应用更改会强制销毁 table 并创建一个新列:
Terraform will perform the following actions:
# module.module.google_bigquery_table.table must be replaced
-/+ resource "google_bigquery_table" "table" {
...
~ schema = jsonencode(
~ [ # forces replacement
# (8 unchanged elements hidden)
{
mode = "REQUIRED"
name = "column1"
type = "TIMESTAMP"
},
- {
- mode = "REQUIRED"
- name = "column2"
- type = "STRING"
},
]
)
...
Plan: 1 to add, 0 to change, 1 to destroy.
此时创建的google_bigquery_table_iam_member
资源仍然指向状态中的旧table。但是,在 GCP 中,服务帐户不再具有对不存在的 table 的访问权限,并且没有向新创建的 table.
授予新的访问权限
运行 terraform apply
第二次它注意到缺少访问权限
Terraform will perform the following actions:
# module.module.google_bigquery_table_iam_member.access_rights will be created
+ resource "google_bigquery_table_iam_member" "access_rights" {
+ dataset_id = "dataset"
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:serviceAccount@GCPserviceAccount.com"
+ project = "project"
+ role = "roles/bigquery.dataEditor"
+ table_id = "table"
}
Plan: 1 to add, 0 to change, 0 to destroy.
是否可以一步实现(应用单个地形)?
即
table
被销毁并重新创建。
access_right
资源更新,因此 SA 可以访问新的 table。
这是一种奇怪的行为,可能是由于提供者事先知道资源字段的结果并混淆了 terraforms 隐式依赖检测。
您可以尝试通过向 iam 资源添加显式 depends_on
来强制依赖以确保重新创建:
resource "google_bigquery_table_iam_member" "access_right" {
project = google_bigquery_table.table.project
dataset_id = google_bigquery_table.table.dataset_id
table_id = google_bigquery_table.table.table_id
role = "roles/bigquery.dataEditor"
member = "serviceAccount:serviceAccount@GCPserviceAccount.com"
depends_on = [google_bigquery_table.table]
}
在这种情况下,terraform 应该能够检测到变化,因为您现在还依赖于 etag
等只有在应用后才知道的变化字段。
为了更好地理解问题,初始应用的计划输出会有所帮助。
正如 OP 在评论部分提到的,解决方案是升级 Terraform 和 provider
版本。然而,当我执行一些测试时,我想分享它们的输出。
解决此问题的另一种方法是使用 recreate。下面的示例是如何工作的。
main.tf
### Creating Service Account
resource "google_service_account" "bigquerytest" {
project = "<MyProjectID>"
account_id = "bigquery-table"
display_name = "bigquery-table-test"
provider = google
}
### Re-Create table
resource "google_bigquery_table" "table" {
dataset_id = "test"
table_id = "bqtable"
project = "<MyProjectID>"
schema = file("/home/<myuser>/terrabq/jsonSchema.json")
deletion_protection=false
}
### DataEditor binding
resource "google_bigquery_table_iam_member" "access-right" {
project = "<MyProjectID>"
dataset_id = "<YourDataset_id>"
table_id = "bqtable"
role = "roles/bigquery.dataEditor"
member = "serviceAccount:${google_service_account.bigquerytest.email}"
}
jsonSchema.json
[
{
"mode": "NULLABLE",
"name": "source",
"type": "STRING"
},
{
"mode": "NULLABLE",
"name": "status",
"type": "STRING"
},
{
"mode": "NULLABLE",
"name": "test",
"type": "STRING"
},
{
"mode": "NULLABLE",
"name": "test4",
"type": "STRING"
}
]
场景:
创建一个具有特定架构的新 Table - bqtable
,创建 ServiceAccount
并为此 Table
.
提供适当的 IAM member
权限
输出:
...
Plan: 3 to add, 0 to change, 0 to destroy.
...
google_service_account.bigquerytest: Creating...
google_bigquery_table.table: Creating...
google_bigquery_table.table: Creation complete after 1s [id=projects/<myproject>/datasets/test/tables/bqtable]
google_service_account.bigquerytest: Creation complete after 1s [id=projects/<myproject>/serviceAccounts/bigquery-table@<myproject>.iam.gserviceaccount.com]
google_bigquery_table_iam_member.access-right: Creating...
google_bigquery_table_iam_member.access-right: Creation complete after 4s [id=projects/<myproject>/datasets/test/tables/bqtable/roles/bigquery.dataEditor/serviceAccount:bigquery-table@<myproject>.iam.gserviceaccount.com]
下一步是更改 jsonSchema.json
中的架构。
注意
- 在架构中添加列时,不会重新创建 table。它只会更新 table 并且在所有新列中将是
NULL
值。
# google_bigquery_table.table will be updated in-place
~ resource "google_bigquery_table" "table" {
在 BQ 中它看起来像这样:
- 当您从架构中删除列时
# google_bigquery_table.table must be replaced
-/+ resource "google_bigquery_table" "table" {
请记住,如果重新创建 Table
,其中的所有数据都将被清除。
发布场景:
如果您只是更改架构(删除列),将重新创建 table 但 IAM 规则不会更新。
计划输出可能是这样的:Plan: 1 to add, 0 to change, 1 to destroy
。
OP 能够通过 Terraform
和 provider
.
的更新版本解决此问题
但是,如果仍有问题,您可以使用 -replace
标记到 re-create 资源。
$ terraform apply -replace=google_bigquery_table_iam_member.access-right
terraform 采取的操作是:
# google_bigquery_table.table must be replaced
-/+ resource "google_bigquery_table" "table" {
...
# google_bigquery_table_iam_member.access-right will be replaced, as requested
-/+ resource "google_bigquery_table_iam_member" "access-right" {
~ etag = "<randomString>" -> (known after apply)
~ id = "projects/<myproject>/datasets/<mydataset>/tables/bqtable/roles/bigquery.dataEditor/serviceAccount:bigquery-table@<myproject>.iam.gserviceaccount.com" -> (known after apply)
~ table_id = "projects/<myproject>/datasets/<mydataset>/tables/bqtable" -> "bqtable"
# (4 unchanged attributes hidden)
}
Plan: 2 to add, 0 to change, 2 to destroy.
除了terraform中的depends_on
,主要用于资源的排序或推迟创建。
总结一下:
- 适用于 OP 的解决方案是更新 Terraform 和 Provider 版本
- 另一个解决方案是使用
terraform apply -replace=[resource.resourcename]
运行 此设置具有:
terraform version 1.1.4
google provider version 4.9.0
而不是:
terraform version 1.1.3
google provider version 4.5.0
解决了这个问题。
但是,如果您出于某种原因不能这样做,@PjoterS 有一个
我有一个 BigQuery table 并且将一个服务帐户作为 iam 成员添加到此 table:
resource "google_bigquery_table" "table" {
dataset_id = dataset
table_id = table
project = project
schema = "jsonSchema.json"
}
resource "google_bigquery_table_iam_member" "access_right" {
project = google_bigquery_table.table.project
dataset_id = google_bigquery_table.table.dataset_id
table_id = google_bigquery_table.table.table_id
role = "roles/bigquery.dataEditor"
member = "serviceAccount:serviceAccount@GCPserviceAccount.com"
}
从 jsonSchema.json
中删除一列并应用更改会强制销毁 table 并创建一个新列:
Terraform will perform the following actions:
# module.module.google_bigquery_table.table must be replaced
-/+ resource "google_bigquery_table" "table" {
...
~ schema = jsonencode(
~ [ # forces replacement
# (8 unchanged elements hidden)
{
mode = "REQUIRED"
name = "column1"
type = "TIMESTAMP"
},
- {
- mode = "REQUIRED"
- name = "column2"
- type = "STRING"
},
]
)
...
Plan: 1 to add, 0 to change, 1 to destroy.
此时创建的google_bigquery_table_iam_member
资源仍然指向状态中的旧table。但是,在 GCP 中,服务帐户不再具有对不存在的 table 的访问权限,并且没有向新创建的 table.
运行 terraform apply
第二次它注意到缺少访问权限
Terraform will perform the following actions:
# module.module.google_bigquery_table_iam_member.access_rights will be created
+ resource "google_bigquery_table_iam_member" "access_rights" {
+ dataset_id = "dataset"
+ etag = (known after apply)
+ id = (known after apply)
+ member = "serviceAccount:serviceAccount@GCPserviceAccount.com"
+ project = "project"
+ role = "roles/bigquery.dataEditor"
+ table_id = "table"
}
Plan: 1 to add, 0 to change, 0 to destroy.
是否可以一步实现(应用单个地形)? 即
table
被销毁并重新创建。access_right
资源更新,因此 SA 可以访问新的 table。
这是一种奇怪的行为,可能是由于提供者事先知道资源字段的结果并混淆了 terraforms 隐式依赖检测。
您可以尝试通过向 iam 资源添加显式 depends_on
来强制依赖以确保重新创建:
resource "google_bigquery_table_iam_member" "access_right" {
project = google_bigquery_table.table.project
dataset_id = google_bigquery_table.table.dataset_id
table_id = google_bigquery_table.table.table_id
role = "roles/bigquery.dataEditor"
member = "serviceAccount:serviceAccount@GCPserviceAccount.com"
depends_on = [google_bigquery_table.table]
}
在这种情况下,terraform 应该能够检测到变化,因为您现在还依赖于 etag
等只有在应用后才知道的变化字段。
为了更好地理解问题,初始应用的计划输出会有所帮助。
正如 OP 在评论部分提到的,解决方案是升级 Terraform 和 provider
版本。然而,当我执行一些测试时,我想分享它们的输出。
解决此问题的另一种方法是使用 recreate。下面的示例是如何工作的。
main.tf
### Creating Service Account
resource "google_service_account" "bigquerytest" {
project = "<MyProjectID>"
account_id = "bigquery-table"
display_name = "bigquery-table-test"
provider = google
}
### Re-Create table
resource "google_bigquery_table" "table" {
dataset_id = "test"
table_id = "bqtable"
project = "<MyProjectID>"
schema = file("/home/<myuser>/terrabq/jsonSchema.json")
deletion_protection=false
}
### DataEditor binding
resource "google_bigquery_table_iam_member" "access-right" {
project = "<MyProjectID>"
dataset_id = "<YourDataset_id>"
table_id = "bqtable"
role = "roles/bigquery.dataEditor"
member = "serviceAccount:${google_service_account.bigquerytest.email}"
}
jsonSchema.json
[
{
"mode": "NULLABLE",
"name": "source",
"type": "STRING"
},
{
"mode": "NULLABLE",
"name": "status",
"type": "STRING"
},
{
"mode": "NULLABLE",
"name": "test",
"type": "STRING"
},
{
"mode": "NULLABLE",
"name": "test4",
"type": "STRING"
}
]
场景:
创建一个具有特定架构的新 Table - bqtable
,创建 ServiceAccount
并为此 Table
.
IAM member
权限
输出:
...
Plan: 3 to add, 0 to change, 0 to destroy.
...
google_service_account.bigquerytest: Creating...
google_bigquery_table.table: Creating...
google_bigquery_table.table: Creation complete after 1s [id=projects/<myproject>/datasets/test/tables/bqtable]
google_service_account.bigquerytest: Creation complete after 1s [id=projects/<myproject>/serviceAccounts/bigquery-table@<myproject>.iam.gserviceaccount.com]
google_bigquery_table_iam_member.access-right: Creating...
google_bigquery_table_iam_member.access-right: Creation complete after 4s [id=projects/<myproject>/datasets/test/tables/bqtable/roles/bigquery.dataEditor/serviceAccount:bigquery-table@<myproject>.iam.gserviceaccount.com]
下一步是更改 jsonSchema.json
中的架构。
注意
- 在架构中添加列时,不会重新创建 table。它只会更新 table 并且在所有新列中将是
NULL
值。
# google_bigquery_table.table will be updated in-place
~ resource "google_bigquery_table" "table" {
在 BQ 中它看起来像这样:
- 当您从架构中删除列时
# google_bigquery_table.table must be replaced
-/+ resource "google_bigquery_table" "table" {
请记住,如果重新创建 Table
,其中的所有数据都将被清除。
发布场景:
如果您只是更改架构(删除列),将重新创建 table 但 IAM 规则不会更新。
计划输出可能是这样的:Plan: 1 to add, 0 to change, 1 to destroy
。
OP 能够通过 Terraform
和 provider
.
但是,如果仍有问题,您可以使用 -replace
标记到 re-create 资源。
$ terraform apply -replace=google_bigquery_table_iam_member.access-right
terraform 采取的操作是:
# google_bigquery_table.table must be replaced
-/+ resource "google_bigquery_table" "table" {
...
# google_bigquery_table_iam_member.access-right will be replaced, as requested
-/+ resource "google_bigquery_table_iam_member" "access-right" {
~ etag = "<randomString>" -> (known after apply)
~ id = "projects/<myproject>/datasets/<mydataset>/tables/bqtable/roles/bigquery.dataEditor/serviceAccount:bigquery-table@<myproject>.iam.gserviceaccount.com" -> (known after apply)
~ table_id = "projects/<myproject>/datasets/<mydataset>/tables/bqtable" -> "bqtable"
# (4 unchanged attributes hidden)
}
Plan: 2 to add, 0 to change, 2 to destroy.
除了terraform中的depends_on
,主要用于资源的排序或推迟创建。
总结一下:
- 适用于 OP 的解决方案是更新 Terraform 和 Provider 版本
- 另一个解决方案是使用
terraform apply -replace=[resource.resourcename]
运行 此设置具有:
terraform version 1.1.4
google provider version 4.9.0
而不是:
terraform version 1.1.3
google provider version 4.5.0
解决了这个问题。
但是,如果您出于某种原因不能这样做,@PjoterS 有一个