Add source_md5hash to avoid inconsistent plan on updates to FAST output files

This commit is contained in:
Wiktor Niesiobędzki
2025-12-18 08:48:20 +00:00
parent cc24046be8
commit f4b8992ea5
15 changed files with 139 additions and 121 deletions

View File

@@ -151,8 +151,9 @@ resource "local_file" "workflows" {
}
resource "google_storage_bucket_object" "workflows" {
for_each = local.output_files.storage_bucket == null ? {} : local.cicd_workflows_contents
bucket = local.of_outputs_bucket
name = "workflows/${each.key}.yaml"
content = each.value
for_each = local.output_files.storage_bucket == null ? {} : local.cicd_workflows_contents
bucket = local.of_outputs_bucket
name = "workflows/${each.key}.yaml"
content = each.value
source_md5hash = md5(each.value)
}

View File

@@ -57,6 +57,18 @@ locals {
? null
: pathexpand(local.output_files.local_path)
)
of_providers_content = {
for k, v in local.output_files.providers : k => templatestring(local.of_template, {
bucket = lookup(
local.of_buckets, v.bucket, v.bucket
)
prefix = lookup(v, "prefix", null)
service_account = lookup(
local.of_service_accounts, v.service_account, v.service_account
)
universe_domain = local.of_universe_domain
})
}
of_template = file("assets/providers.tf.tpl")
of_tfvars = {
globals = {
@@ -108,32 +120,15 @@ resource "local_file" "providers" {
for_each = local.of_path == null ? {} : local.output_files.providers
file_permission = "0644"
filename = "${local.of_path}/providers/${each.key}-providers.tf"
content = templatestring(local.of_template, {
bucket = lookup(
local.of_buckets, each.value.bucket, each.value.bucket
)
prefix = lookup(each.value, "prefix", null)
service_account = lookup(
local.of_service_accounts, each.value.service_account, each.value.service_account
)
universe_domain = local.of_universe_domain
})
content = local.of_providers_content[each.key]
}
resource "google_storage_bucket_object" "providers" {
for_each = local.output_files.storage_bucket == null ? {} : local.output_files.providers
bucket = local.of_outputs_bucket
name = "providers/${each.key}-providers.tf"
content = templatestring(local.of_template, {
bucket = lookup(
local.of_buckets, each.value.bucket, each.value.bucket
)
prefix = lookup(each.value, "prefix", null)
service_account = lookup(
local.of_service_accounts, each.value.service_account, each.value.service_account
)
universe_domain = local.of_universe_domain
})
for_each = local.output_files.storage_bucket == null ? {} : local.output_files.providers
bucket = local.of_outputs_bucket
name = "providers/${each.key}-providers.tf"
content = local.of_providers_content[each.key]
source_md5hash = md5(local.of_providers_content[each.key])
}
resource "local_file" "tfvars" {
@@ -144,8 +139,20 @@ resource "local_file" "tfvars" {
}
resource "google_storage_bucket_object" "tfvars" {
for_each = toset(local.output_files.storage_bucket == null ? [] : keys(local.of_tfvars))
bucket = local.of_outputs_bucket
name = "tfvars/0-${each.key}.auto.tfvars.json"
content = jsonencode(local.of_tfvars[each.key])
for_each = toset(local.output_files.storage_bucket == null ? [] : keys(local.of_tfvars))
bucket = local.of_outputs_bucket
name = "tfvars/0-${each.key}.auto.tfvars.json"
content = jsonencode(local.of_tfvars[each.key])
source_md5hash = md5(jsonencode(local.of_tfvars[each.key]))
}
resource "google_storage_bucket_object" "version" {
count = (
local.output_files.storage_bucket != null &&
fileexists("fast_version.txt") ? 1 : 0
)
bucket = local.output_files.storage_bucket
name = "versions/0-org-setup-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}

View File

@@ -474,6 +474,6 @@ Some references that might be useful in setting up this stage:
| name | description | sensitive | consumers |
|---|---|:---:|---|
| [tfvars](outputs.tf#L50) | Terraform variable files for the following stages. | ✓ | |
| [vpc_sc_perimeter_default](outputs.tf#L56) | Raw default perimeter resource. | ✓ | |
| [tfvars](outputs.tf#L52) | Terraform variable files for the following stages. | ✓ | |
| [vpc_sc_perimeter_default](outputs.tf#L58) | Raw default perimeter resource. | ✓ | |
<!-- END TFDOC -->

View File

@@ -28,9 +28,10 @@ resource "google_storage_bucket_object" "version" {
local.output_files.storage_bucket != null &&
fileexists("fast_version.txt") ? 1 : 0
)
bucket = local.output_files.storage_bucket
name = "versions/${local.defaults.stage_name}-version.txt"
source = "fast_version.txt"
bucket = local.output_files.storage_bucket
name = "versions/${local.defaults.stage_name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}
resource "local_file" "tfvars" {
@@ -41,10 +42,11 @@ resource "local_file" "tfvars" {
}
resource "google_storage_bucket_object" "tfvars" {
count = local.output_files.storage_bucket != null ? 1 : 0
bucket = local.output_files.storage_bucket
name = "tfvars/${local.defaults.stage_name}.auto.tfvars.json"
content = jsonencode(local.tfvars)
count = local.output_files.storage_bucket != null ? 1 : 0
bucket = local.output_files.storage_bucket
name = "tfvars/${local.defaults.stage_name}.auto.tfvars.json"
content = jsonencode(local.tfvars)
source_md5hash = md5(jsonencode(local.tfvars))
}
output "tfvars" {

View File

@@ -228,7 +228,7 @@ routers:
vpn-router:
region: $locations:primary
asn: 64514
# [...]
# [...]
```
### VPC Connectivity
@@ -333,10 +333,10 @@ Internally created resources are mapped to context namespaces, and use specific
| name | description | sensitive |
|---|---|:---:|
| [host_project_ids](outputs.tf#L68) | Project IDs. | |
| [host_project_numbers](outputs.tf#L73) | Project numbers. | |
| [subnet_proxy_only_self_links](outputs.tf#L78) | Subnet proxy-only self-links. | |
| [subnet_psc_self_links](outputs.tf#L83) | Subnet PSC self-links. | |
| [subnet_self_links](outputs.tf#L88) | Subnet self-links. | |
| [vpc_self_links](outputs.tf#L93) | VPC self-links. | |
| [host_project_ids](outputs.tf#L70) | Project IDs. | |
| [host_project_numbers](outputs.tf#L75) | Project numbers. | |
| [subnet_proxy_only_self_links](outputs.tf#L80) | Subnet proxy-only self-links. | |
| [subnet_psc_self_links](outputs.tf#L85) | Subnet PSC self-links. | |
| [subnet_self_links](outputs.tf#L90) | Subnet self-links. | |
| [vpc_self_links](outputs.tf#L95) | VPC self-links. | |
<!-- END TFDOC -->

View File

@@ -44,9 +44,10 @@ resource "google_storage_bucket_object" "version" {
local.output_files.storage_bucket != null &&
fileexists("fast_version.txt") ? 1 : 0
)
bucket = local.output_files.storage_bucket
name = "versions/${local.defaults.stage_name}-version.txt"
source = "fast_version.txt"
bucket = local.output_files.storage_bucket
name = "versions/${local.defaults.stage_name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}
resource "local_file" "tfvars" {
@@ -57,10 +58,11 @@ resource "local_file" "tfvars" {
}
resource "google_storage_bucket_object" "tfvars" {
count = local.output_files.storage_bucket != null ? 1 : 0
bucket = local.output_files.storage_bucket
name = "tfvars/${local.defaults.stage_name}.auto.tfvars.json"
content = jsonencode(local.tfvars)
count = local.output_files.storage_bucket != null ? 1 : 0
bucket = local.output_files.storage_bucket
name = "tfvars/${local.defaults.stage_name}.auto.tfvars.json"
content = jsonencode(local.tfvars)
source_md5hash = md5(jsonencode(local.tfvars))
}
# outputs

View File

@@ -99,6 +99,17 @@ locals {
for k, v in local._of_providers : k => v
if v.storage_bucket != null && v.service_account != null
}
of_providers_content = {
for k, v in local.of_providers : k => templatestring(local.of_template, {
bucket = lookup(
local.of_storage_buckets,
v.storage_bucket,
v.storage_bucket
)
prefix = v.prefix
service_account = v.service_account
})
}
# list of service accounts for dereferencing single providers
of_service_accounts = {
for k, v in module.factory.service_account_emails :
@@ -126,15 +137,7 @@ resource "local_file" "providers" {
filename = (
"${local.of_paths.local}/providers/${each.value.filename}-providers.tf"
)
content = templatestring(local.of_template, {
bucket = lookup(
local.of_storage_buckets,
each.value.storage_bucket,
each.value.storage_bucket
)
prefix = each.value.prefix
service_account = each.value.service_account
})
content = local.of_providers_content[each.key]
}
resource "local_file" "tfvars" {
@@ -149,25 +152,19 @@ resource "local_file" "tfvars" {
}
resource "google_storage_bucket_object" "providers" {
for_each = local.of_storage_bucket == null ? {} : local.of_providers
bucket = local.of_storage_bucket
name = "providers/${each.value.filename}-providers.tf"
content = templatestring(local.of_template, {
bucket = lookup(
local.of_storage_buckets,
each.value.storage_bucket,
each.value.storage_bucket
)
prefix = each.value.prefix
service_account = each.value.service_account
})
for_each = local.of_storage_bucket == null ? {} : local.of_providers
bucket = local.of_storage_bucket
name = "providers/${each.value.filename}-providers.tf"
content = local.of_providers_content[each.key]
source_md5hash = md5(local.of_providers_content[each.key])
}
resource "google_storage_bucket_object" "tfvars" {
for_each = toset(
local.of_storage_bucket == null ? [] : local.of_tfvars_projects
)
bucket = local.of_storage_bucket
name = "tfvars/${each.value}.auto.tfvars.json"
content = jsonencode(module.factory.projects[each.value])
bucket = local.of_storage_bucket
name = "tfvars/${each.value}.auto.tfvars.json"
content = jsonencode(module.factory.projects[each.value])
source_md5hash = md5(jsonencode(module.factory.projects[each.value]))
}

View File

@@ -20,8 +20,9 @@ output "projects" {
}
resource "google_storage_bucket_object" "version" {
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/2-${var.stage_name}-version.txt"
source = "fast_version.txt"
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/2-${var.stage_name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}

View File

@@ -200,7 +200,7 @@ A reference Certificate Authority Services (CAS) is also part of this stage, all
| name | description | sensitive | consumers |
|---|---|:---:|---|
| [ca_pools](outputs.tf#L64) | Certificate Authority Service pools and CAs. | | |
| [kms_keys_ids](outputs.tf#L69) | KMS keys IDs. | | |
| [tfvars](outputs.tf#L74) | Terraform variable files for the following stages. | ✓ | |
| [ca_pools](outputs.tf#L66) | Certificate Authority Service pools and CAs. | | |
| [kms_keys_ids](outputs.tf#L71) | KMS keys IDs. | | |
| [tfvars](outputs.tf#L76) | Terraform variable files for the following stages. | ✓ | |
<!-- END TFDOC -->

View File

@@ -42,9 +42,10 @@ resource "google_storage_bucket_object" "version" {
local.output_files.storage_bucket != null &&
fileexists("fast_version.txt") ? 1 : 0
)
bucket = local.output_files.storage_bucket
name = "versions/${local.defaults.stage_name}-version.txt"
source = "fast_version.txt"
bucket = local.output_files.storage_bucket
name = "versions/${local.defaults.stage_name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}
resource "local_file" "tfvars" {
@@ -55,10 +56,11 @@ resource "local_file" "tfvars" {
}
resource "google_storage_bucket_object" "tfvars" {
count = local.output_files.storage_bucket != null ? 1 : 0
bucket = local.output_files.storage_bucket
name = "tfvars/${local.defaults.stage_name}.auto.tfvars.json"
content = jsonencode(local.tfvars)
count = local.output_files.storage_bucket != null ? 1 : 0
bucket = local.output_files.storage_bucket
name = "tfvars/${local.defaults.stage_name}.auto.tfvars.json"
content = jsonencode(local.tfvars)
source_md5hash = md5(jsonencode(local.tfvars))
}
output "ca_pools" {

View File

@@ -370,9 +370,9 @@ The following table lists the available substitutions.
| name | description | sensitive | consumers |
|---|---|:---:|---|
| [aspect_types](outputs.tf#L198) | Aspect types defined in central project. | | |
| [central_project](outputs.tf#L203) | Central project attributes. | | |
| [data_domains](outputs.tf#L208) | Data domain attributes. | | |
| [policy_tags](outputs.tf#L213) | Policy tags defined in central project. | | |
| [secure_tags](outputs.tf#L218) | Secure tags defined in central project. | | |
| [aspect_types](outputs.tf#L201) | Aspect types defined in central project. | | |
| [central_project](outputs.tf#L206) | Central project attributes. | | |
| [data_domains](outputs.tf#L211) | Data domain attributes. | | |
| [policy_tags](outputs.tf#L216) | Policy tags defined in central project. | | |
| [secure_tags](outputs.tf#L221) | Secure tags defined in central project. | | |
<!-- END TFDOC -->

View File

@@ -164,10 +164,11 @@ resource "local_file" "tfvars" {
}
resource "google_storage_bucket_object" "tfvars" {
for_each = local.tfvars_dd
bucket = var.automation.outputs_bucket
name = "tfvars/${local.files_prefix}/${each.key}.auto.tfvars.json"
content = jsonencode(each.value)
for_each = local.tfvars_dd
bucket = var.automation.outputs_bucket
name = "tfvars/${local.files_prefix}/${each.key}.auto.tfvars.json"
content = jsonencode(each.value)
source_md5hash = md5(jsonencode(each.value))
}
# provider files for data domains and products
@@ -180,17 +181,19 @@ resource "local_file" "providers" {
}
resource "google_storage_bucket_object" "providers" {
for_each = local.providers
bucket = var.automation.outputs_bucket
name = "providers/${local.files_prefix}/${each.key}"
content = each.value
for_each = local.providers
bucket = var.automation.outputs_bucket
name = "providers/${local.files_prefix}/${each.key}"
content = each.value
source_md5hash = md5(each.value)
}
resource "google_storage_bucket_object" "version" {
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}
# regular outputs

View File

@@ -35,8 +35,9 @@ output "project_id" {
}
resource "google_storage_bucket_object" "version" {
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5()
}

View File

@@ -31,8 +31,9 @@ output "project_id" {
}
resource "google_storage_bucket_object" "version" {
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}

View File

@@ -18,8 +18,9 @@ output "project_id" {
}
resource "google_storage_bucket_object" "version" {
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
count = fileexists("fast_version.txt") ? 1 : 0
bucket = var.automation.outputs_bucket
name = "versions/3-${var.stage_config.name}-version.txt"
source = "fast_version.txt"
source_md5hash = filemd5("fast_version.txt")
}