Reputation: 498
I have a BigQuery table and an add a service account as an iam member to this 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:[email protected]"
}
Removing a column from jsonSchema.json
and applying the changes enforces the destruction of the table and the creation of a new one:
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.
At this point the google_bigquery_table_iam_member
resource created is still pointing to the old table in the state. However, in GCP the service account no longer has access to the non existing table and no new access has been given to the newly created table.
Running terraform apply
a second time it notices the missing access
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:[email protected]"
+ project = "project"
+ role = "roles/bigquery.dataEditor"
+ table_id = "table"
}
Plan: 1 to add, 0 to change, 0 to destroy.
Is it possible to achieve this in a single step (a single terraform apply)? i.e.
table
gets destroyed and recreated.access_right
resource updates so the SA has access to the new table.Upvotes: 2
Views: 1131
Reputation: 498
Running this setup with:
terraform version 1.1.4
google provider version 4.9.0
Rather than:
terraform version 1.1.3
google provider version 4.5.0
eliminated the issue.
However, if you for some reason cannot do that, @PjoterS has an alternative solution
Upvotes: 1
Reputation: 14092
As mentioned in the comment section by OP, the solution was to upgrade Terraform and the provider
versions. However as I performed a few tests I wanted to share output of them.
Another option to solve this issue is to use recreate. Below Example how it works.
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"
}
]
Scenario:
Create a new Table - bqtable
with specific schema, create ServiceAccount
and proper IAM member
permission for this Table
.
Output:
...
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]
Next step is to change the schema in jsonSchema.json
.
NULL
value. # google_bigquery_table.table will be updated in-place
~ resource "google_bigquery_table" "table" {
In BQ it would looks like that:
# google_bigquery_table.table must be replaced
-/+ resource "google_bigquery_table" "table" {
Please keep in mind that if the Table
will be recreated, all data from it will be purged.
If you will just change the schema (remove column), the table will be recreated but IAM rules weren't updated.
Plan output was probably like that: Plan: 1 to add, 0 to change, 1 to destroy
.
OP was able to solve this issue with an updated version of Terraform
and provider
.
However, if you still have issues, you can use -replace
flag to re-create resource.
$ terraform apply -replace=google_bigquery_table_iam_member.access-right
Actions taken by terraform was:
# 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.
In Addition to depends_on
in terraform, it's used mainly for ordering or to postpone creation of resources.
To sum up:
terraform apply -replace=[resource.resourcename]
Upvotes: 1
Reputation: 3127
This is weird behavior maybe caused by the provider knowing the result of the resource fields beforehand and confusing terraforms implicit dependency detection.
You can try to force the dependency by adding an explicit depends_on
to the iam resource to ensure recreation:
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:[email protected]"
depends_on = [google_bigquery_table.table]
}
in this case terraform should be able to detect changes as you now also depend on changing fields like etag
that are only known after apply.
To better understand the issue a plan output of an initial apply would help.
Upvotes: 0