diff --git a/blueprints/apigee/bigquery-analytics/main.tf b/blueprints/apigee/bigquery-analytics/main.tf index d1534ad77..ef8d65cc3 100644 --- a/blueprints/apigee/bigquery-analytics/main.tf +++ b/blueprints/apigee/bigquery-analytics/main.tf @@ -24,8 +24,8 @@ module "project" { ? var.project_create.parent : null ) - name = var.project_id - project_create = var.project_create != null + name = var.project_id + project_reuse = var.project_create != null ? null : {} services = [ "apigee.googleapis.com", "bigquery.googleapis.com", diff --git a/blueprints/apigee/hybrid-gke/main.tf b/blueprints/apigee/hybrid-gke/main.tf index 5be174ef5..713670f59 100644 --- a/blueprints/apigee/hybrid-gke/main.tf +++ b/blueprints/apigee/hybrid-gke/main.tf @@ -24,8 +24,8 @@ module "project" { ? var.project_create.parent : null ) - project_create = var.project_create != null - name = var.project_id + project_reuse = var.project_create != null ? null : {} + name = var.project_id services = [ "apigee.googleapis.com", "apigeeconnect.googleapis.com", diff --git a/blueprints/cloud-operations/adfs/main.tf b/blueprints/cloud-operations/adfs/main.tf index 27286bbfc..3d7adaac9 100644 --- a/blueprints/cloud-operations/adfs/main.tf +++ b/blueprints/cloud-operations/adfs/main.tf @@ -24,9 +24,9 @@ module "project" { ? var.project_create.parent : null ) - project_create = var.project_create != null - prefix = var.project_create == null ? null : var.prefix - name = var.project_id + project_reuse = var.project_create != null ? null : {} + prefix = var.project_create == null ? null : var.prefix + name = var.project_id services = [ "compute.googleapis.com", "dns.googleapis.com", diff --git a/blueprints/cloud-operations/asset-inventory-feed-remediation/main.tf b/blueprints/cloud-operations/asset-inventory-feed-remediation/main.tf index dab591c59..7c8c56ced 100644 --- a/blueprints/cloud-operations/asset-inventory-feed-remediation/main.tf +++ b/blueprints/cloud-operations/asset-inventory-feed-remediation/main.tf @@ -20,9 +20,9 @@ locals { } module "project" { - source = "../../../modules/project" - name = var.project_id - project_create = var.project_create + source = "../../../modules/project" + name = var.project_id + project_reuse = var.project_create != true ? {} : null services = [ "cloudasset.googleapis.com", "cloudbuild.googleapis.com", diff --git a/blueprints/cloud-operations/compute-quota-monitoring/main.tf b/blueprints/cloud-operations/compute-quota-monitoring/main.tf index 0136aa329..84a302691 100644 --- a/blueprints/cloud-operations/compute-quota-monitoring/main.tf +++ b/blueprints/cloud-operations/compute-quota-monitoring/main.tf @@ -29,7 +29,7 @@ module "project" { name = var.project_id billing_account = try(var.project_create_config.billing_account, null) parent = try(var.project_create_config.parent, null) - project_create = var.project_create_config != null + project_reuse = var.project_create_config != null ? null : {} services = [ "cloudasset.googleapis.com", "cloudbuild.googleapis.com", diff --git a/blueprints/cloud-operations/dns-fine-grained-iam/main.tf b/blueprints/cloud-operations/dns-fine-grained-iam/main.tf index fc25b257a..18e030eec 100644 --- a/blueprints/cloud-operations/dns-fine-grained-iam/main.tf +++ b/blueprints/cloud-operations/dns-fine-grained-iam/main.tf @@ -22,9 +22,9 @@ locals { } module "project" { - source = "../../../modules/project" - name = var.project_id - project_create = var.project_create + source = "../../../modules/project" + name = var.project_id + project_reuse = var.project_create != true ? {} : null services = [ "compute.googleapis.com", "dns.googleapis.com", diff --git a/blueprints/cloud-operations/iam-delegated-role-grants/main.tf b/blueprints/cloud-operations/iam-delegated-role-grants/main.tf index e835dbb5a..9fc9d6e2b 100644 --- a/blueprints/cloud-operations/iam-delegated-role-grants/main.tf +++ b/blueprints/cloud-operations/iam-delegated-role-grants/main.tf @@ -48,9 +48,9 @@ locals { } module "project" { - source = "../../../modules/project" - name = var.project_id - project_create = var.project_create + source = "../../../modules/project" + name = var.project_id + project_reuse = var.project_create != true ? {} : null } # make direct grants non-authoritative since project administrators diff --git a/blueprints/cloud-operations/network-quota-monitoring/deploy-cloudrun-job/main.tf b/blueprints/cloud-operations/network-quota-monitoring/deploy-cloudrun-job/main.tf index cc0b4293e..478e17d54 100644 --- a/blueprints/cloud-operations/network-quota-monitoring/deploy-cloudrun-job/main.tf +++ b/blueprints/cloud-operations/network-quota-monitoring/deploy-cloudrun-job/main.tf @@ -25,7 +25,7 @@ module "project" { name = var.project_id billing_account = try(var.project_create_config.billing_account_id, null) parent = try(var.project_create_config.parent_id, null) - project_create = var.project_create_config != null + project_reuse = var.project_create_config != null ? null : {} services = [ "artifactregistry.googleapis.com", "cloudasset.googleapis.com", diff --git a/blueprints/cloud-operations/onprem-sa-key-management/main.tf b/blueprints/cloud-operations/onprem-sa-key-management/main.tf index 40786ea18..1eec60332 100644 --- a/blueprints/cloud-operations/onprem-sa-key-management/main.tf +++ b/blueprints/cloud-operations/onprem-sa-key-management/main.tf @@ -19,10 +19,10 @@ locals { } module "project" { - source = "../../../modules/project" - name = var.project_id - project_create = var.project_create - services = var.services + source = "../../../modules/project" + name = var.project_id + project_reuse = var.project_create != true ? {} : null + services = var.services } module "integration-sa" { diff --git a/blueprints/cloud-operations/packer-image-builder/main.tf b/blueprints/cloud-operations/packer-image-builder/main.tf index 641ebd52d..fccb08128 100644 --- a/blueprints/cloud-operations/packer-image-builder/main.tf +++ b/blueprints/cloud-operations/packer-image-builder/main.tf @@ -26,7 +26,7 @@ module "project" { name = var.project_id parent = var.root_node billing_account = var.billing_account - project_create = var.project_create + project_reuse = var.project_create ? null : {} services = [ "compute.googleapis.com" ] diff --git a/blueprints/cloud-operations/scheduled-asset-inventory-export-bq/main.tf b/blueprints/cloud-operations/scheduled-asset-inventory-export-bq/main.tf index ab77d8df9..fa2a3c506 100644 --- a/blueprints/cloud-operations/scheduled-asset-inventory-export-bq/main.tf +++ b/blueprints/cloud-operations/scheduled-asset-inventory-export-bq/main.tf @@ -25,7 +25,7 @@ module "project" { name = var.project_id parent = var.root_node billing_account = try(var.billing_account, null) - project_create = var.project_create + project_reuse = var.project_create ? null : {} services = [ "bigquery.googleapis.com", "cloudasset.googleapis.com", diff --git a/blueprints/cloud-operations/terraform-cloud-dynamic-credentials/gcp-workload-identity-provider/main.tf b/blueprints/cloud-operations/terraform-cloud-dynamic-credentials/gcp-workload-identity-provider/main.tf index ef56a44d6..09057da53 100644 --- a/blueprints/cloud-operations/terraform-cloud-dynamic-credentials/gcp-workload-identity-provider/main.tf +++ b/blueprints/cloud-operations/terraform-cloud-dynamic-credentials/gcp-workload-identity-provider/main.tf @@ -20,7 +20,7 @@ module "project" { source = "../../../../modules/project" name = var.project_id - project_create = var.project_create + project_reuse = var.project_create ? null : {} parent = var.parent billing_account = var.billing_account services = [ diff --git a/blueprints/cloud-operations/unmanaged-instances-healthcheck/main.tf b/blueprints/cloud-operations/unmanaged-instances-healthcheck/main.tf index 33c6654e6..c3e37aadc 100644 --- a/blueprints/cloud-operations/unmanaged-instances-healthcheck/main.tf +++ b/blueprints/cloud-operations/unmanaged-instances-healthcheck/main.tf @@ -22,7 +22,7 @@ module "project" { name = var.project_id parent = var.root_node billing_account = var.billing_account - project_create = var.project_create + project_reuse = var.project_create ? null : {} services = [ "vpcaccess.googleapis.com", "compute.googleapis.com", diff --git a/blueprints/cloud-operations/vm-migration/host-target-projects/README.md b/blueprints/cloud-operations/vm-migration/host-target-projects/README.md index a2e9a71d2..831bf0fab 100644 --- a/blueprints/cloud-operations/vm-migration/host-target-projects/README.md +++ b/blueprints/cloud-operations/vm-migration/host-target-projects/README.md @@ -57,7 +57,6 @@ module "test-target-project" { source = "./fabric/modules/project" billing_account = "1234-ABCD-1234" name = "test-target-project" - project_create = true } # tftest modules=5 resources=28 diff --git a/blueprints/cloud-operations/vm-migration/host-target-projects/main.tf b/blueprints/cloud-operations/vm-migration/host-target-projects/main.tf index ffe19839d..ef16ec6a4 100644 --- a/blueprints/cloud-operations/vm-migration/host-target-projects/main.tf +++ b/blueprints/cloud-operations/vm-migration/host-target-projects/main.tf @@ -33,7 +33,7 @@ module "host-project" { "servicecontrol.googleapis.com", "vmmigration.googleapis.com", ] - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} iam_bindings_additive = { admin_sa_key_admin = { role = "roles/iam.serviceAccountKeyAdmin" @@ -62,10 +62,10 @@ module "m4ce-service-account" { } module "target-projects" { - for_each = toset(var.migration_target_projects) - source = "../../../../modules/project" - name = each.key - project_create = false + for_each = toset(var.migration_target_projects) + source = "../../../../modules/project" + name = each.key + project_reuse = {} services = [ "servicemanagement.googleapis.com", "servicecontrol.googleapis.com", diff --git a/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/README.md b/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/README.md index 3349709ea..72fccbe50 100644 --- a/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/README.md +++ b/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/README.md @@ -65,14 +65,12 @@ module "test-target-project" { source = "./fabric/modules/project" billing_account = "1234-ABCD-1234" name = "test-target-project" - project_create = true } module "test-sharedvpc-host-project" { source = "./fabric/modules/project" billing_account = "1234-ABCD-1234" name = "test-sharedvpc-host-project" - project_create = true } # tftest modules=7 resources=29 diff --git a/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/main.tf b/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/main.tf index 037b8115d..b86d18694 100644 --- a/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/main.tf +++ b/blueprints/cloud-operations/vm-migration/host-target-sharedvpc/main.tf @@ -32,7 +32,7 @@ module "host-project" { "servicecontrol.googleapis.com", "vmmigration.googleapis.com", ] - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} iam_bindings_additive = { admin_sa_key_admin = { role = "roles/iam.serviceAccountKeyAdmin" @@ -60,10 +60,10 @@ module "m4ce-service-account" { } module "target-projects" { - for_each = toset(var.migration_target_projects) - source = "../../../../modules/project" - name = each.key - project_create = false + for_each = toset(var.migration_target_projects) + source = "../../../../modules/project" + name = each.key + project_reuse = {} services = [ "cloudresourcemanager.googleapis.com", "compute.googleapis.com", @@ -84,10 +84,10 @@ module "target-projects" { } module "sharedvpc_host_project" { - for_each = toset(var.sharedvpc_host_projects) - source = "../../../../modules/project" - name = each.key - project_create = false + for_each = toset(var.sharedvpc_host_projects) + source = "../../../../modules/project" + name = each.key + project_reuse = {} iam_bindings_additive = { admin_compute_viewer = { role = "roles/compute.viewer" diff --git a/blueprints/cloud-operations/vm-migration/single-project/main.tf b/blueprints/cloud-operations/vm-migration/single-project/main.tf index 4b67936e4..94fb70ef5 100644 --- a/blueprints/cloud-operations/vm-migration/single-project/main.tf +++ b/blueprints/cloud-operations/vm-migration/single-project/main.tf @@ -33,7 +33,7 @@ module "landing-project" { "servicecontrol.googleapis.com", "vmmigration.googleapis.com" ] - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} iam_bindings_additive = { admin_sa_key_admin = { role = "roles/iam.serviceAccountKeyAdmin" diff --git a/blueprints/cloud-operations/workload-identity-federation/google-cloud.tf b/blueprints/cloud-operations/workload-identity-federation/google-cloud.tf index 0924d08bd..8fb767ef7 100644 --- a/blueprints/cloud-operations/workload-identity-federation/google-cloud.tf +++ b/blueprints/cloud-operations/workload-identity-federation/google-cloud.tf @@ -31,7 +31,7 @@ module "prj" { "iamcredentials.googleapis.com", "sts.googleapis.com", ] - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} iam_bindings_additive = { sa_viewer = { member = module.sa.iam_email diff --git a/blueprints/data-solutions/bq-ml/main.tf b/blueprints/data-solutions/bq-ml/main.tf index 6a9ace6e6..a26e8ee5b 100644 --- a/blueprints/data-solutions/bq-ml/main.tf +++ b/blueprints/data-solutions/bq-ml/main.tf @@ -34,7 +34,7 @@ module "project" { name = var.project_id parent = try(var.project_create.parent, null) billing_account = try(var.project_create.billing_account_id, null) - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} prefix = var.project_create == null ? null : var.prefix services = [ "aiplatform.googleapis.com", diff --git a/blueprints/data-solutions/cloudsql-multiregion/main.tf b/blueprints/data-solutions/cloudsql-multiregion/main.tf index 855c8685a..af6a7c50d 100644 --- a/blueprints/data-solutions/cloudsql-multiregion/main.tf +++ b/blueprints/data-solutions/cloudsql-multiregion/main.tf @@ -47,7 +47,7 @@ module "project" { name = var.project_id parent = try(var.project_create.parent, null) billing_account = try(var.project_create.billing_account_id, null) - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} prefix = var.project_create == null ? null : var.prefix iam_bindings_additive = merge( var.data_eng_principal == null ? {} : { diff --git a/blueprints/data-solutions/cmek-via-centralized-kms/main.tf b/blueprints/data-solutions/cmek-via-centralized-kms/main.tf index dbb033622..d86f5e9d7 100644 --- a/blueprints/data-solutions/cmek-via-centralized-kms/main.tf +++ b/blueprints/data-solutions/cmek-via-centralized-kms/main.tf @@ -29,7 +29,7 @@ module "project-service" { name = var.project_config.project_ids.service parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = var.project_config.billing_account_id == null ? null : var.prefix services = [ "compute.googleapis.com", @@ -54,7 +54,7 @@ module "project-kms" { name = var.project_config.project_ids.encryption parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = var.project_config.billing_account_id == null ? null : var.prefix services = [ "cloudkms.googleapis.com", diff --git a/blueprints/data-solutions/data-platform-foundations/01-dropoff.tf b/blueprints/data-solutions/data-platform-foundations/01-dropoff.tf index e0d50080a..152d20045 100644 --- a/blueprints/data-solutions/data-platform-foundations/01-dropoff.tf +++ b/blueprints/data-solutions/data-platform-foundations/01-dropoff.tf @@ -45,7 +45,7 @@ module "drop-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects diff --git a/blueprints/data-solutions/data-platform-foundations/02-load.tf b/blueprints/data-solutions/data-platform-foundations/02-load.tf index 453003da8..32dfe191e 100644 --- a/blueprints/data-solutions/data-platform-foundations/02-load.tf +++ b/blueprints/data-solutions/data-platform-foundations/02-load.tf @@ -39,7 +39,7 @@ module "load-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects diff --git a/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf b/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf index b2976da5d..5663c3b1d 100644 --- a/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf +++ b/blueprints/data-solutions/data-platform-foundations/03-orchestration.tf @@ -61,7 +61,7 @@ module "orch-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects diff --git a/blueprints/data-solutions/data-platform-foundations/04-transformation.tf b/blueprints/data-solutions/data-platform-foundations/04-transformation.tf index 2bdf9ee2c..2a45def1a 100644 --- a/blueprints/data-solutions/data-platform-foundations/04-transformation.tf +++ b/blueprints/data-solutions/data-platform-foundations/04-transformation.tf @@ -40,7 +40,7 @@ module "transf-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects diff --git a/blueprints/data-solutions/data-platform-foundations/05-datawarehouse.tf b/blueprints/data-solutions/data-platform-foundations/05-datawarehouse.tf index 886100c72..f58dc034a 100644 --- a/blueprints/data-solutions/data-platform-foundations/05-datawarehouse.tf +++ b/blueprints/data-solutions/data-platform-foundations/05-datawarehouse.tf @@ -68,7 +68,7 @@ module "dwh-lnd-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects @@ -88,7 +88,7 @@ module "dwh-cur-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects @@ -108,7 +108,7 @@ module "dwh-conf-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects diff --git a/blueprints/data-solutions/data-platform-foundations/06-common.tf b/blueprints/data-solutions/data-platform-foundations/06-common.tf index 992a6c03c..6ebf2adf1 100644 --- a/blueprints/data-solutions/data-platform-foundations/06-common.tf +++ b/blueprints/data-solutions/data-platform-foundations/06-common.tf @@ -50,7 +50,7 @@ module "common-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects diff --git a/blueprints/data-solutions/data-platform-foundations/07-exposure.tf b/blueprints/data-solutions/data-platform-foundations/07-exposure.tf index ad4f39d1a..8418080ff 100644 --- a/blueprints/data-solutions/data-platform-foundations/07-exposure.tf +++ b/blueprints/data-solutions/data-platform-foundations/07-exposure.tf @@ -18,7 +18,7 @@ module "exp-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.project_create + project_reuse = var.project_config.project_create ? null : {} prefix = local.use_projects ? null : var.prefix name = ( local.use_projects diff --git a/blueprints/data-solutions/data-platform-minimal/01-landing.tf b/blueprints/data-solutions/data-platform-minimal/01-landing.tf index c2f40303e..e9a036102 100644 --- a/blueprints/data-solutions/data-platform-minimal/01-landing.tf +++ b/blueprints/data-solutions/data-platform-minimal/01-landing.tf @@ -44,7 +44,7 @@ module "land-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = ( var.project_config.billing_account_id == null ? null : var.prefix ) diff --git a/blueprints/data-solutions/data-platform-minimal/02-processing.tf b/blueprints/data-solutions/data-platform-minimal/02-processing.tf index 47be526f9..d19695f5f 100644 --- a/blueprints/data-solutions/data-platform-minimal/02-processing.tf +++ b/blueprints/data-solutions/data-platform-minimal/02-processing.tf @@ -90,7 +90,7 @@ module "processing-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = ( var.project_config.billing_account_id == null ? null : var.prefix ) diff --git a/blueprints/data-solutions/data-platform-minimal/03-curated.tf b/blueprints/data-solutions/data-platform-minimal/03-curated.tf index 6888b21cf..f825065a5 100644 --- a/blueprints/data-solutions/data-platform-minimal/03-curated.tf +++ b/blueprints/data-solutions/data-platform-minimal/03-curated.tf @@ -84,7 +84,7 @@ module "cur-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = ( var.project_config.billing_account_id == null ? null : var.prefix ) diff --git a/blueprints/data-solutions/data-platform-minimal/04-common.tf b/blueprints/data-solutions/data-platform-minimal/04-common.tf index 37699df9f..0431d774c 100644 --- a/blueprints/data-solutions/data-platform-minimal/04-common.tf +++ b/blueprints/data-solutions/data-platform-minimal/04-common.tf @@ -59,7 +59,7 @@ module "common-project" { source = "../../../modules/project" parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = ( var.project_config.billing_account_id == null ? null : var.prefix ) diff --git a/blueprints/data-solutions/data-playground/main.tf b/blueprints/data-solutions/data-playground/main.tf index 9662544b3..15e97729a 100644 --- a/blueprints/data-solutions/data-playground/main.tf +++ b/blueprints/data-solutions/data-playground/main.tf @@ -56,7 +56,7 @@ module "project" { name = var.project_id parent = try(var.project_create.parent, null) billing_account = try(var.project_create.billing_account_id, null) - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} prefix = var.project_create == null ? null : var.prefix services = [ "aiplatform.googleapis.com", diff --git a/blueprints/data-solutions/gcs-to-bq-with-least-privileges/main.tf b/blueprints/data-solutions/gcs-to-bq-with-least-privileges/main.tf index e79cc72a9..661f98c6b 100644 --- a/blueprints/data-solutions/gcs-to-bq-with-least-privileges/main.tf +++ b/blueprints/data-solutions/gcs-to-bq-with-least-privileges/main.tf @@ -69,7 +69,7 @@ module "project" { name = var.project_config.project_id parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = var.project_config.billing_account_id == null ? null : var.prefix services = [ "bigquery.googleapis.com", diff --git a/blueprints/data-solutions/shielded-folder/kms.tf b/blueprints/data-solutions/shielded-folder/kms.tf index 83f1c5fcb..b0a1da94b 100644 --- a/blueprints/data-solutions/shielded-folder/kms.tf +++ b/blueprints/data-solutions/shielded-folder/kms.tf @@ -60,8 +60,10 @@ module "sec-project" { name = var.project_config.project_ids["sec-core"] parent = module.folder.id billing_account = var.project_config.billing_account_id - project_create = ( + project_reuse = ( var.project_config.billing_account_id != null && var.enable_features.encryption + ? null + : {} ) prefix = ( var.project_config.billing_account_id == null ? null : var.prefix diff --git a/blueprints/data-solutions/shielded-folder/log-export.tf b/blueprints/data-solutions/shielded-folder/log-export.tf index 5f8353d2c..fee9b7bd7 100644 --- a/blueprints/data-solutions/shielded-folder/log-export.tf +++ b/blueprints/data-solutions/shielded-folder/log-export.tf @@ -61,7 +61,7 @@ module "log-export-project" { name = var.project_config.project_ids["audit-logs"] parent = module.folder.id billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = ( var.project_config.billing_account_id == null ? null : var.prefix ) diff --git a/blueprints/data-solutions/sqlserver-alwayson/main.tf b/blueprints/data-solutions/sqlserver-alwayson/main.tf index 38486268d..6f7a922c4 100644 --- a/blueprints/data-solutions/sqlserver-alwayson/main.tf +++ b/blueprints/data-solutions/sqlserver-alwayson/main.tf @@ -67,7 +67,7 @@ module "project" { name = var.project_id parent = try(var.project_create.parent, null) billing_account = try(var.project_create.billing_account_id, null) - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} prefix = var.project_create == null ? null : var.prefix services = [ "compute.googleapis.com", diff --git a/blueprints/data-solutions/vertex-mlops/main.tf b/blueprints/data-solutions/vertex-mlops/main.tf index cfab4877d..18c01019b 100644 --- a/blueprints/data-solutions/vertex-mlops/main.tf +++ b/blueprints/data-solutions/vertex-mlops/main.tf @@ -193,7 +193,7 @@ module "project" { name = var.project_config.project_id parent = var.project_config.parent billing_account = var.project_config.billing_account_id - project_create = var.project_config.billing_account_id != null + project_reuse = var.project_config.billing_account_id != null ? null : {} prefix = var.prefix iam_by_principals = local.iam_principals iam_bindings_additive = { diff --git a/blueprints/gcve/monitoring/main.tf b/blueprints/gcve/monitoring/main.tf index 4c5e6789a..efa53ddf4 100644 --- a/blueprints/gcve/monitoring/main.tf +++ b/blueprints/gcve/monitoring/main.tf @@ -33,7 +33,7 @@ module "project" { parent = try(var.project_create.parent, null) billing_account = try(var.project_create.billing_account, null) name = var.project_id - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} services = [ "compute.googleapis.com", "monitoring.googleapis.com", diff --git a/blueprints/gke/autopilot/main.tf b/blueprints/gke/autopilot/main.tf index 84b7fe06e..87cfb4e15 100644 --- a/blueprints/gke/autopilot/main.tf +++ b/blueprints/gke/autopilot/main.tf @@ -24,8 +24,8 @@ module "project" { ? var.project_create.parent : null ) - project_create = var.project_create != null - name = var.project_id + project_reuse = var.project_create != null ? null : {} + name = var.project_id services = [ "artifactregistry.googleapis.com", "cloudbuild.googleapis.com", diff --git a/blueprints/gke/binauthz/main.tf b/blueprints/gke/binauthz/main.tf index 5ee0b59c0..df95ce068 100644 --- a/blueprints/gke/binauthz/main.tf +++ b/blueprints/gke/binauthz/main.tf @@ -32,9 +32,9 @@ module "project" { ? var.project_create.parent : null ) - project_create = var.project_create != null - prefix = var.project_create == null ? null : var.prefix - name = var.project_id + project_reuse = var.project_create != null ? null : {} + prefix = var.project_create == null ? null : var.prefix + name = var.project_id services = [ "artifactregistry.googleapis.com", "binaryauthorization.googleapis.com", diff --git a/blueprints/gke/patterns/autopilot-cluster/main.tf b/blueprints/gke/patterns/autopilot-cluster/main.tf index 51dd759e5..90d6c76d9 100644 --- a/blueprints/gke/patterns/autopilot-cluster/main.tf +++ b/blueprints/gke/patterns/autopilot-cluster/main.tf @@ -130,10 +130,10 @@ module "vpc" { } module "fleet-project" { - source = "../../../../modules/project" - count = var.fleet_project_id == null ? 0 : 1 - name = var.fleet_project_id - project_create = false + source = "../../../../modules/project" + count = var.fleet_project_id == null ? 0 : 1 + name = var.fleet_project_id + project_reuse = {} } module "fleet" { diff --git a/blueprints/networking/glb-and-armor/main.tf b/blueprints/networking/glb-and-armor/main.tf index 22a7c3c7c..d65de5ce5 100644 --- a/blueprints/networking/glb-and-armor/main.tf +++ b/blueprints/networking/glb-and-armor/main.tf @@ -33,7 +33,7 @@ module "project" { services = [ "compute.googleapis.com" ] - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} } diff --git a/blueprints/networking/glb-hybrid-neg-internal/main.tf b/blueprints/networking/glb-hybrid-neg-internal/main.tf index 3a7551ffb..ca4a9513a 100644 --- a/blueprints/networking/glb-hybrid-neg-internal/main.tf +++ b/blueprints/networking/glb-hybrid-neg-internal/main.tf @@ -32,8 +32,8 @@ module "project_landing" { ? var.projects_create.parent : null ) - prefix = var.prefix - project_create = var.projects_create != null + prefix = var.prefix + project_reuse = var.projects_create != null ? null : {} services = [ "compute.googleapis.com", diff --git a/blueprints/networking/ilb-next-hop/main.tf b/blueprints/networking/ilb-next-hop/main.tf index 0f7cfe0e5..66ca6ac4d 100644 --- a/blueprints/networking/ilb-next-hop/main.tf +++ b/blueprints/networking/ilb-next-hop/main.tf @@ -23,9 +23,9 @@ locals { } module "project" { - source = "../../../modules/project" - name = var.project_id - project_create = var.project_create + source = "../../../modules/project" + name = var.project_id + project_reuse = var.project_create ? null : {} services = [ "compute.googleapis.com", "dns.googleapis.com", diff --git a/blueprints/networking/private-cloud-function-from-onprem/main.tf b/blueprints/networking/private-cloud-function-from-onprem/main.tf index 377801e00..d11a78cb0 100644 --- a/blueprints/networking/private-cloud-function-from-onprem/main.tf +++ b/blueprints/networking/private-cloud-function-from-onprem/main.tf @@ -21,7 +21,7 @@ locals { module "project" { source = "../../../modules/project" name = var.project_id - project_create = var.project_create == null ? false : true + project_reuse = var.project_create == null ? {} : null billing_account = try(var.project_create.billing_account_id, null) parent = try(var.project_create.parent, null) services = [ diff --git a/blueprints/networking/psc-glb-and-armor/consumer.tf b/blueprints/networking/psc-glb-and-armor/consumer.tf index e525046ca..e1f31fda0 100644 --- a/blueprints/networking/psc-glb-and-armor/consumer.tf +++ b/blueprints/networking/psc-glb-and-armor/consumer.tf @@ -15,9 +15,9 @@ */ module "consumer-project" { - source = "../../../modules/project" - name = var.consumer_project_id - project_create = var.project_create_config != null + source = "../../../modules/project" + name = var.consumer_project_id + project_reuse = var.project_create_config != null ? null : {} billing_account = try(var.project_create_config.billing_account, null) parent = try(var.project_create_config.parent, null) diff --git a/blueprints/networking/psc-glb-and-armor/modules/producer/main.tf b/blueprints/networking/psc-glb-and-armor/modules/producer/main.tf index dd982e8c9..3e25d9b14 100644 --- a/blueprints/networking/psc-glb-and-armor/modules/producer/main.tf +++ b/blueprints/networking/psc-glb-and-armor/modules/producer/main.tf @@ -15,9 +15,9 @@ */ module "producer-project" { - source = "../../../../../modules/project" - name = var.producer_project_id - project_create = var.project_create_config != null + source = "../../../../../modules/project" + name = var.producer_project_id + project_reuse = var.project_create_config != null ? null : {} billing_account = try(var.project_create_config.billing_account, null) parent = try(var.project_create_config.parent, null) diff --git a/blueprints/networking/psc-hybrid/main.tf b/blueprints/networking/psc-hybrid/main.tf index 39be8c923..c2f3b9e60 100644 --- a/blueprints/networking/psc-hybrid/main.tf +++ b/blueprints/networking/psc-hybrid/main.tf @@ -53,9 +53,9 @@ locals { } module "project" { - source = "../../../modules/project" - name = var.project_id - project_create = var.project_create + source = "../../../modules/project" + name = var.project_id + project_reuse = var.project_create ? null : {} services = [ "compute.googleapis.com" ] diff --git a/blueprints/networking/vpc-connectivity-lab/main.tf b/blueprints/networking/vpc-connectivity-lab/main.tf index 92b04da4a..bc99dc601 100644 --- a/blueprints/networking/vpc-connectivity-lab/main.tf +++ b/blueprints/networking/vpc-connectivity-lab/main.tf @@ -21,8 +21,12 @@ module "project" { name = var.project_id parent = try(var.project_create_config.parent_id, null) billing_account = try(var.project_create_config.billing_account_id, null) - project_create = try(var.project_create_config.billing_account_id, null) != null - prefix = var.prefix + project_reuse = ( + try(var.project_create_config.billing_account_id, null) != null + ? null + : {} + ) + prefix = var.prefix services = [ "compute.googleapis.com", "dns.googleapis.com", diff --git a/blueprints/secops/bindplane-gke/main.tf b/blueprints/secops/bindplane-gke/main.tf index 6f84c781d..8c47fe3b1 100644 --- a/blueprints/secops/bindplane-gke/main.tf +++ b/blueprints/secops/bindplane-gke/main.tf @@ -32,9 +32,9 @@ module "project" { ? var.project_create.parent : null ) - prefix = var.prefix - project_create = var.project_create != null - name = var.project_id + prefix = var.prefix + project_reuse = var.project_create != null ? null : {} + name = var.project_id services = concat([ "compute.googleapis.com", "iap.googleapis.com", diff --git a/blueprints/secops/secops-gke-forwarder/main.tf b/blueprints/secops/secops-gke-forwarder/main.tf index bc3c8e870..0a65090ad 100644 --- a/blueprints/secops/secops-gke-forwarder/main.tf +++ b/blueprints/secops/secops-gke-forwarder/main.tf @@ -32,9 +32,9 @@ module "project" { ? var.project_create.parent : null ) - prefix = var.prefix - project_create = var.project_create != null - name = var.project_id + prefix = var.prefix + project_reuse = var.project_create != null ? null : {} + name = var.project_id services = concat([ "compute.googleapis.com", "iap.googleapis.com", diff --git a/blueprints/serverless/cloud-run-corporate/main.tf b/blueprints/serverless/cloud-run-corporate/main.tf index ce6e8bb10..cc3b44b15 100644 --- a/blueprints/serverless/cloud-run-corporate/main.tf +++ b/blueprints/serverless/cloud-run-corporate/main.tf @@ -46,7 +46,7 @@ locals { module "project_main" { source = "../../../modules/project" name = var.prj_main_id - project_create = var.prj_main_create != null + project_reuse = var.prj_main_create != null ? null : {} billing_account = try(var.prj_main_create.billing_account_id, null) parent = try(var.prj_main_create.parent, null) # Enable Shared VPC by default, some use cases will use this project as host @@ -67,7 +67,7 @@ module "project_onprem" { source = "../../../modules/project" count = var.prj_onprem_id != null ? 1 : 0 name = var.prj_onprem_id - project_create = var.prj_onprem_create != null + project_reuse = var.prj_onprem_create != null ? null : {} billing_account = try(var.prj_onprem_create.billing_account_id, null) parent = try(var.prj_onprem_create.parent, null) services = [ @@ -81,7 +81,7 @@ module "project_prj1" { source = "../../../modules/project" count = var.prj_prj1_id != null ? 1 : 0 name = var.prj_prj1_id - project_create = var.prj_prj1_create != null + project_reuse = var.prj_prj1_create != null ? null : {} billing_account = try(var.prj_prj1_create.billing_account_id, null) parent = try(var.prj_prj1_create.parent, null) services = [ @@ -95,7 +95,7 @@ module "project_svc1" { source = "../../../modules/project" count = var.prj_svc1_id != null ? 1 : 0 name = var.prj_svc1_id - project_create = var.prj_svc1_create != null + project_reuse = var.prj_svc1_create != null ? null : {} billing_account = try(var.prj_svc1_create.billing_account_id, null) parent = try(var.prj_svc1_create.parent, null) shared_vpc_service_config = { diff --git a/blueprints/serverless/cloud-run-explore/main.tf b/blueprints/serverless/cloud-run-explore/main.tf index c32923f86..402cc2f0a 100644 --- a/blueprints/serverless/cloud-run-explore/main.tf +++ b/blueprints/serverless/cloud-run-explore/main.tf @@ -35,7 +35,7 @@ module "project" { "compute.googleapis.com", "iap.googleapis.com" ] - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} } # Cloud Run service diff --git a/blueprints/serverless/cloud-run-microservices/main.tf b/blueprints/serverless/cloud-run-microservices/main.tf index 0da49b778..aca35cdd9 100644 --- a/blueprints/serverless/cloud-run-microservices/main.tf +++ b/blueprints/serverless/cloud-run-microservices/main.tf @@ -29,7 +29,7 @@ module "main-project" { source = "../../../modules/project" name = var.project_configs.main.project_id prefix = var.prefix - project_create = var.project_configs.main.billing_account_id != null + project_reuse = var.project_configs.main.billing_account_id != null ? null : {} billing_account = try(var.project_configs.main.billing_account_id, null) parent = try(var.project_configs.main.parent, null) # Enable Shared VPC by default, a use case will use this project as host @@ -49,7 +49,7 @@ module "service-project" { count = local.two_projects == true ? 1 : 0 name = var.project_configs.service.project_id prefix = var.prefix - project_create = var.project_configs.service.billing_account_id != null + project_reuse = var.project_configs.service.billing_account_id != null ? null : {} billing_account = try(var.project_configs.service.billing_account_id, null) parent = try(var.project_configs.service.parent, null) shared_vpc_service_config = { diff --git a/blueprints/third-party-solutions/f5-bigip/f5-bigip-ha-active-deployment/main.tf b/blueprints/third-party-solutions/f5-bigip/f5-bigip-ha-active-deployment/main.tf index a364eab07..ad946906e 100644 --- a/blueprints/third-party-solutions/f5-bigip/f5-bigip-ha-active-deployment/main.tf +++ b/blueprints/third-party-solutions/f5-bigip/f5-bigip-ha-active-deployment/main.tf @@ -23,9 +23,9 @@ locals { } module "project" { - source = "../../../../modules/project" - name = var.project_id - project_create = var.project_create + source = "../../../../modules/project" + name = var.project_id + project_reuse = var.project_create ? null : {} services = [ "compute.googleapis.com" ] diff --git a/blueprints/third-party-solutions/gitlab/main.tf b/blueprints/third-party-solutions/gitlab/main.tf index aec06222f..1b839d7fd 100644 --- a/blueprints/third-party-solutions/gitlab/main.tf +++ b/blueprints/third-party-solutions/gitlab/main.tf @@ -20,7 +20,7 @@ module "project" { billing_account = try(var.project_create.billing_account_id, null) prefix = var.project_create == null ? null : var.prefix name = var.project_id - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} services = [ "compute.googleapis.com", "memcache.googleapis.com", diff --git a/blueprints/third-party-solutions/phpipam/main.tf b/blueprints/third-party-solutions/phpipam/main.tf index 36ee52e3c..0dc826ae0 100644 --- a/blueprints/third-party-solutions/phpipam/main.tf +++ b/blueprints/third-party-solutions/phpipam/main.tf @@ -55,7 +55,7 @@ module "project" { name = var.project_id parent = try(var.project_create.parent, null) prefix = var.project_create == null ? null : var.prefix - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} services = [ "iap.googleapis.com", "logging.googleapis.com", diff --git a/blueprints/third-party-solutions/wordpress/cloudrun/main.tf b/blueprints/third-party-solutions/wordpress/cloudrun/main.tf index 7f11359ea..56a7b6bae 100644 --- a/blueprints/third-party-solutions/wordpress/cloudrun/main.tf +++ b/blueprints/third-party-solutions/wordpress/cloudrun/main.tf @@ -44,7 +44,7 @@ module "project" { name = var.project_id parent = try(var.project_create.parent, null) billing_account = try(var.project_create.billing_account_id, null) - project_create = var.project_create != null + project_reuse = var.project_create != null ? null : {} prefix = var.project_create == null ? null : var.prefix iam = ( var.project_create != true || var.admin_principal == null diff --git a/fast/addons/1-resman-tenants/tenant-fast-automation.tf b/fast/addons/1-resman-tenants/tenant-fast-automation.tf index ff9b6aac9..385aa248c 100644 --- a/fast/addons/1-resman-tenants/tenant-fast-automation.tf +++ b/fast/addons/1-resman-tenants/tenant-fast-automation.tf @@ -88,10 +88,16 @@ module "tenant-automation-project" { module "tenant-automation-project-iam" { - source = "../../../modules/project" - for_each = local.fast_tenants - name = module.tenant-automation-project[each.key].project_id - project_create = false + source = "../../../modules/project" + for_each = local.fast_tenants + name = module.tenant-automation-project[each.key].project_id + project_reuse = { + use_data_source = false + project_attributes = { + name = module.tenant-automation-project[each.key].name + number = module.tenant-automation-project[each.key].number + } + } # human (groups) IAM bindings iam_by_principals = { (each.value.principals.gcp-devops) = [ diff --git a/fast/addons/2-networking-ngfw/main.tf b/fast/addons/2-networking-ngfw/main.tf index 87b03d3cd..16d5a0122 100644 --- a/fast/addons/2-networking-ngfw/main.tf +++ b/fast/addons/2-networking-ngfw/main.tf @@ -22,10 +22,10 @@ locals { } module "project" { - source = "../../../modules/project" - count = var._fast_debug.skip_datasources == true ? 0 : 1 - name = local.aliased_project_id - project_create = false + source = "../../../modules/project" + count = var._fast_debug.skip_datasources == true ? 0 : 1 + name = local.aliased_project_id + project_reuse = {} service_agents_config = { services_enabled = [ "networksecurity.googleapis.com" diff --git a/fast/addons/2-networking-swp/main.tf b/fast/addons/2-networking-swp/main.tf index 105859adf..00b1596b9 100644 --- a/fast/addons/2-networking-swp/main.tf +++ b/fast/addons/2-networking-swp/main.tf @@ -36,10 +36,10 @@ locals { } module "project" { - source = "../../../modules/project" - count = var._fast_debug.skip_datasources == true ? 0 : 1 - name = local.aliased_project_id - project_create = false + source = "../../../modules/project" + count = var._fast_debug.skip_datasources == true ? 0 : 1 + name = local.aliased_project_id + project_reuse = {} service_agents_config = { services_enabled = [ "networksecurity.googleapis.com" diff --git a/fast/stages/1-resman/tenant-root.tf b/fast/stages/1-resman/tenant-root.tf index e5d79c717..38403ff54 100644 --- a/fast/stages/1-resman/tenant-root.tf +++ b/fast/stages/1-resman/tenant-root.tf @@ -32,10 +32,10 @@ module "root-folder" { } module "automation-project" { - source = "../../../modules/project" - count = var.root_node != null ? 1 : 0 - name = var.automation.project_id - project_create = false + source = "../../../modules/project" + count = var.root_node != null ? 1 : 0 + name = var.automation.project_id + project_reuse = {} # do not assign tagViewer or tagUser roles here on tag keys and values as # they are managed authoritatively and will break multitenant stages tags = merge(local.tags, { diff --git a/fast/stages/2-project-factory/README.md b/fast/stages/2-project-factory/README.md index ba1e8b845..69762c44d 100644 --- a/fast/stages/2-project-factory/README.md +++ b/fast/stages/2-project-factory/README.md @@ -370,6 +370,7 @@ The approach is not shown here but reasonably easy to implement. The main projec | name | description | sensitive | consumers | |---|---|:---:|---| -| [projects](outputs.tf#L32) | Created projects. | | | -| [service_accounts](outputs.tf#L46) | Created service accounts. | | | +| [buckets](outputs.tf#L32) | Created buckets. | | | +| [projects](outputs.tf#L39) | Created projects. | | | +| [service_accounts](outputs.tf#L53) | Created service accounts. | | | diff --git a/fast/stages/2-project-factory/outputs.tf b/fast/stages/2-project-factory/outputs.tf index 2ac905c56..dfaa581d2 100644 --- a/fast/stages/2-project-factory/outputs.tf +++ b/fast/stages/2-project-factory/outputs.tf @@ -29,6 +29,13 @@ locals { } } +output "buckets" { + description = "Created buckets." + value = { + for k, v in module.projects.buckets : k => v + } +} + output "projects" { description = "Created projects." value = { @@ -47,8 +54,8 @@ output "service_accounts" { description = "Created service accounts." value = { for k, v in module.projects.service_accounts : k => { - email = v.email - iam_emanil = v.iam_email + email = v.email + iam_email = v.iam_email } } } diff --git a/modules/project-factory/README.md b/modules/project-factory/README.md index 937f5fb79..8ca679382 100644 --- a/modules/project-factory/README.md +++ b/modules/project-factory/README.md @@ -6,10 +6,10 @@ It supports - filesystem-driven folder hierarchy exposing the full configuration options available in the [folder module](../folder/) - multiple project creation and management exposing the full configuration options available in the [project module](../project/), including KMS key grants and VPC-SC perimeter membership -- optional per-project [service account management](#service-accounts) including basic IAM grants +- optional per-project [service account and bucket management](#service-accounts-and-buckets) including basic IAM grants - optional [billing budgets](#billing-budgets) factory and budget/project associations - cross-referencing of hierarchy folders in projects -- optional per-project IaC configuration (TODO) +- optional per-project IaC configuration The factory is implemented as a thin data translation layer for the underlying modules, so that no "magic" or hidden side effects are implemented in code, and debugging or integration of new features are simple. @@ -20,14 +20,16 @@ The code is meant to be executed by a high level service accounts with powerful - Shared VPC connection if service project attachment is desired - billing cost manager permissions to manage budgets and monitoring permissions if notifications should also be managed here +## Contents + - [Folder hierarchy](#folder-hierarchy) - [Projects](#projects) - [Factory-wide project defaults, merges, optionals](#factory-wide-project-defaults-merges-optionals) - - [Service accounts](#service-accounts) + - [Service accounts and buckets](#service-accounts-and-buckets) - [Automation project and resources](#automation-project-and-resources) - [Billing budgets](#billing-budgets) -- [Substitutions in YAML configurations attributes](#substitutions-in-yaml-configurations-attributes) +- [Interpolation in YAML configuration attributes](#interpolation-in-yaml-configuration-attributes) - [Example](#example) - [Files](#files) - [Variables](#variables) @@ -61,11 +63,11 @@ In addition to the YAML-based project configurations, the factory accepts three Some examples on where to use each of the three sets are [provided below](#example). -### Service accounts +### Service accounts and buckets -Service accounts can be managed as part of each project's YAML configuration. This allows creation of default service accounts used for GCE instances, in firewall rules, or for application-level credentials without resorting to a separate Terraform configuration. +Service accounts and GCS buckets can be managed as part of each project's YAML configuration. This allows creation of default service accounts used for GCE instances, in firewall rules, or for application-level credentials without resorting to a separate Terraform configuration. -Each service account is represented by one key and a set of optional key/value pairs in the `service_accounts` top-level YAML map, which exposes most of the variables available in the `iam-service-account` module: +Each service account is represented by one key and a set of optional key/value pairs in the `service_accounts` top-level YAML map, which exposes most of the variables available in the `iam-service-account` module. Both the `display_name` and `iam_self_roles` attributes are optional. ```yaml service_accounts: @@ -77,21 +79,31 @@ service_accounts: iam_project_roles: my-host-project: - roles/compute.networkUser + terraform-rw: {} ``` -Both the `display_name` and `iam_self_roles` attributes are optional. +Each bucket is represented by one key and a set of optional key/value pairs in the `buckets` top-level YAML map, which exposes most of the variables available in the `gcs` module. Bucket location, storage class and a few other attributes can be defaulted/enforced via project factory level variables. + +```yaml +buckets: + state: + location: europe-west8 + iam: + roles/storage.admin: + - terraform-rw +``` ### Automation project and resources -Project configurations also support defining service accounts and storage buckets to support automation, created in a separate controlling project so as to be outside of the sphere of control of the managed project. +Other than creating automation resources within the project via the `service_accounts` and `buckets` attributes, this module also support management of automation resources created in a separate controlling project. This allows grating broad roles on the project, while still making sure that the automation resources used for Terraform cannot be manipulated from the same identities. Automation resources are defined via the `automation` attribute in project configurations, which supports: -- a mandatory `project` attribute to define the external controlling project -- an optional `service_accounts` list where each element will define a service account in the controlling project -- an optional `buckets` map where each key will define a bucket in the controlling project, and the map of roles/principals in the corresponding value assigned on the created bucket; principals can refer to the created service accounts by key +- a mandatory `project` attribute to define the external controlling project; this attribute does not support interpolation and needs to be explicit +- an optional `service_accounts` list where each element defines a service account in the controlling project +- an optional `buckets` map where each key defines a bucket in the controlling project, and the map of roles/principals in the corresponding value assigned on the created bucket; principals can refer to the created service accounts by key -Service accounts and buckets will be prefixed with the project name, and use the key specified in the YAML file as a suffix. +Service accounts and buckets are be prefixed with the project name, and use the key specified in the YAML file as a suffix. ```yaml # file name: prod-app-example-0 @@ -152,16 +164,16 @@ billing_budgets: A simple billing budget example is show in the [example](#example) below. -## Substitutions in YAML configurations attributes +## Interpolation in YAML configuration attributes -Substitutions allow referring via short mnemonic names to resources which are either created at runtime, or externally manages. +Interpolation allow referring via short mnemonic names to resources which are either created at runtime, or externally managed. This feature has two main benefits: - being able to refer to resource ids which cannot be known before creation, for example project automation service accounts in IAM bindings - making YAML configuration files more easily readable and portable, by using mnemonic keys which are not specific to an organization or project -One example of both types of substitutions is in this project snippet. The automation service account is used in IAM bindings via its `rw` key, while the parent folder is set by referring to its path in the hierarchy factory. +One example of both types of contexts is in this project snippet. The automation service account is used in IAM bindings via its `rw` key, while the parent folder is set by referring to its path in the hierarchy factory. ```yaml parent: teams/team-a @@ -181,28 +193,28 @@ automation: - rw ``` -Substitutions come from two separate context sources: an internal set for resources managed by the project factory (folders, service accounts, etc.), and an external user-defined set passed in via the `factories_config.context` variable. +Interpolations leverage contexts from two separate sources: an internal set for resources managed by the project factory (folders, service accounts, etc.), and an external user-defined set passed in via the `factories_config.context` variable. -Internal substitutions are: +The following table lists the available context interpolations. External contexts are passed in via the `factories_config.contexts` variable. IAM principals are interpolated in all IAM attributes except `iam_by_principal`. First two columns show for which attribute of which resource context is interpolated. `external contexts` column show in which map passed as `var.factories_config.context` key will be looked up. -- hierarchy folders, used to set project parents via the filesystem path of folders (e.g. `teams/team-a`) -- automation service accounts, used in project IAM bindings via their keys; this does not work in folder IAM bindings +* Internally created folders creates keys under `${folder_name_1}[/${folder_name_2}/${folder_name_3}]` +* IAM principals are resolved within context of managed project -External substitution are: - -- the map of folder ids in `factories_config.context.folder_ids`, used to set top-level folder parents; the `default` key if present is used when no explicit parent has been set in the YAML file -- the map of IAM principals in `factories_config.context.iam_principals`, used in IAM bindings for folders and projects; the exception is the `iam_by_principals` attribute which uses no interpolation to prevent dynamic cycles -- the map of tag value ids in `factories_config.context.tag_values` used in tag bindings for folders and projects -- the map of Shared VPC host project ids in `factories_config.context.vpc_host_projects` used in service project configurations for projects - -External substitution maps are optional, and there's no harm in not defining them if not used. - -Some caveats on substitutions: - -- project-own service accounts are not part of substitutions to prevent cycles, you can use the `iam_project_roles` and `iam_self_roles` attributes for additive IAM on projects -- project shared vpc configurations and project-own service accounts only support external substitutions to prevent cycles -- projects for automation service accounts and buckets do not support substitutions to prevent cycles -- no substitutions are implemented (yet) for budgets +| resource | attribute | external contexts | internal contexts | +| ------------------- | --------------- | ------------------- | -------------------------- | +| folder | parent | `folder_ids` | internally created folders | +| folder | IAM principals | `iam_principals` | | +| folder | tag bindings | `tag_values` | | +| project | parent | `folder_ids` | internally created folders | +| project | Shared VPC host | `vpc_host_projects` | | +| project | Shared VPC IAM | `iam_principals` | | +| project | tag bindings | `tag_values` | | +| project | IAM principals | `iam_principals` | project service accounts | +| | | | IaC service accounts | +| bucket | IAM principals | `iam_principals` | project service accounts | +| service account | IAM projects | `vpc_host_projects` | | +| IaC bucket | IAM principals | `iam_principals` | IaC service accounts | +| IaC service account | IAM principals | `iam_principals` | | ## Example @@ -266,7 +278,7 @@ module "project-factory" { } } } -# tftest modules=15 resources=56 files=0,1,2,3,4,5,6,7,8 inventory=example.yaml +# tftest modules=16 resources=56 files=0,1,2,3,4,5,6,7,8 inventory=example.yaml ``` A simple hierarchy of folders: @@ -432,7 +444,7 @@ update_rules: | [factory-folders.tf](./factory-folders.tf) | Folder hierarchy factory locals. | | | [factory-projects.tf](./factory-projects.tf) | Projects factory locals. | | | [folders.tf](./folders.tf) | Folder hierarchy factory resources. | folder | -| [main.tf](./main.tf) | Projects and billing budgets factory resources. | billing-account · iam-service-account · project | +| [main.tf](./main.tf) | Projects and billing budgets factory resources. | billing-account · gcs · iam-service-account · project | | [outputs.tf](./outputs.tf) | Module outputs. | | | [variables.tf](./variables.tf) | Module variables. | | @@ -449,9 +461,10 @@ update_rules: | name | description | sensitive | |---|---|:---:| -| [folders](outputs.tf#L17) | Folder ids. | | -| [projects](outputs.tf#L22) | Created projects. | | -| [service_accounts](outputs.tf#L44) | Service account emails. | | +| [buckets](outputs.tf#L17) | Bucket names. | | +| [folders](outputs.tf#L24) | Folder ids. | | +| [projects](outputs.tf#L29) | Created projects. | | +| [service_accounts](outputs.tf#L51) | Service account emails. | | ## Tests diff --git a/modules/project-factory/automation.tf b/modules/project-factory/automation.tf index 02c4218e4..fd4646cad 100644 --- a/modules/project-factory/automation.tf +++ b/modules/project-factory/automation.tf @@ -85,9 +85,15 @@ module "automation-buckets" { lookup(each.value, "location", null), var.data_defaults.storage_location ) - storage_class = lookup(each.value, "storage_class", "STANDARD") - uniform_bucket_level_access = lookup(each.value, "uniform_bucket_level_access", true) - versioning = lookup(each.value, "versioning", false) + storage_class = lookup( + each.value, "storage_class", "STANDARD" + ) + uniform_bucket_level_access = lookup( + each.value, "uniform_bucket_level_access", true + ) + versioning = lookup( + each.value, "versioning", false + ) } module "automation-service-accounts" { diff --git a/modules/project-factory/factory-projects.tf b/modules/project-factory/factory-projects.tf index a204a44a0..5d407111b 100644 --- a/modules/project-factory/factory-projects.tf +++ b/modules/project-factory/factory-projects.tf @@ -163,9 +163,40 @@ locals { var.data_defaults.logging_data_access ) # non-project resources + buckets = try(v.buckets, {}) service_accounts = try(v.service_accounts, {}) }) } + buckets = flatten([ + for k, v in local.projects : [ + for name, opts in v.buckets : { + project = k + name = name + description = lookup(opts, "description", "Terraform-managed.") + encryption_key = lookup(opts, "encryption_key", null) + iam = lookup(opts, "iam", {}) + iam_bindings = lookup(opts, "iam_bindings", {}) + iam_bindings_additive = lookup(opts, "iam_bindings_additive", {}) + labels = lookup(opts, "labels", {}) + location = lookup(opts, "location", null) + prefix = coalesce( + var.data_overrides.prefix, + try(v.prefix, null), + var.data_defaults.prefix + ) + storage_class = lookup( + opts, "storage_class", "STANDARD" + ) + uniform_bucket_level_access = lookup( + opts, "uniform_bucket_level_access", true + ) + versioning = lookup( + opts, "versioning", false + ) + + } + ] + ]) service_accounts = flatten([ for k, v in local.projects : [ for name, opts in v.service_accounts : { diff --git a/modules/project-factory/main.tf b/modules/project-factory/main.tf index f350503f3..8596c828c 100644 --- a/modules/project-factory/main.tf +++ b/modules/project-factory/main.tf @@ -59,46 +59,6 @@ module "projects" { notification_channels = var.factories_config.context.notification_channels } } - iam = { - for k, v in lookup(each.value, "iam", {}) : k => [ - for vv in v : try( - # automation service account - local.context.iam_principals["${each.key}/${vv}"], - # other context - local.context.iam_principals[vv], - # passthrough - vv - ) - ] - } - iam_bindings = { - for k, v in lookup(each.value, "iam_bindings", {}) : k => merge(v, { - members = [ - for vv in v.members : try( - # automation service account - local.context.iam_principals["${each.key}/${vv}"], - # other context - local.context.iam_principals[vv], - # passthrough - vv - ) - ] - }) - } - iam_bindings_additive = { - for k, v in lookup(each.value, "iam_bindings_additive", {}) : k => merge(v, { - member = try( - # automation service account - local.context.iam_principals["${each.key}/${v.member}"], - # other context - local.context.iam_principals[v.member], - # passthrough - v.member - ) - }) - } - # IAM by principals would trigger dynamic key errors so we don't interpolate - iam_by_principals = try(each.value.iam_by_principals, {}) labels = merge( each.value.labels, var.data_merges.labels ) @@ -145,6 +105,114 @@ module "projects" { vpc_sc = each.value.vpc_sc } +module "projects-iam" { + source = "../project" + for_each = local.projects + name = module.projects[each.key].project_id + project_reuse = { + use_data_source = false + project_attributes = { + name = module.projects[each.key].name + number = module.projects[each.key].number + } + } + iam = { + for k, v in lookup(each.value, "iam", {}) : k => [ + for vv in v : try( + # project service accounts + module.service-accounts["${each.key}/${vv}"].iam_email, + # automation service account + local.context.iam_principals["${each.key}/${vv}"], + # other context + local.context.iam_principals[vv], + # passthrough + vv + ) + ] + } + iam_bindings = { + for k, v in lookup(each.value, "iam_bindings", {}) : k => merge(v, { + members = [ + for vv in v.members : try( + # project service accounts + module.service-accounts["${each.key}/${vv}"].iam_email, + # automation service account + local.context.iam_principals["${each.key}/${vv}"], + # other context + local.context.iam_principals[vv], + # passthrough + vv + ) + ] + }) + } + iam_bindings_additive = { + for k, v in lookup(each.value, "iam_bindings_additive", {}) : k => merge(v, { + member = try( + # project service accounts + module.service-accounts["${each.key}/${v.member}"].iam_email, + # automation service account + local.context.iam_principals["${each.key}/${v.member}"], + # other context + local.context.iam_principals[v.member], + # passthrough + v.member + ) + }) + } + # IAM by principals would trigger dynamic key errors so we don't interpolate + iam_by_principals = try(each.value.iam_by_principals, {}) +} + +module "buckets" { + source = "../gcs" + for_each = { + for k in local.buckets : "${k.project}/${k.name}" => k + } + project_id = module.projects[each.value.project].project_id + prefix = each.value.prefix + name = "${each.value.project}-${each.value.name}" + encryption_key = each.value.encryption_key + iam = { + for k, v in each.value.iam : k => [ + for vv in v : try( + module.service-accounts["${each.value.project}/${vv}"].iam_email, + var.factories_config.context.iam_principals[vv], + vv + ) + ] + } + iam_bindings = { + for k, v in each.value.iam_bindings : k => merge(v, { + members = [ + for vv in v.members : try( + module.service-accounts["${each.value.project}/${vv}"].iam_email, + var.factories_config.context.iam_principals[vv], + vv + ) + ] + }) + } + iam_bindings_additive = { + for k, v in each.value.iam_bindings_additive : k => merge(v, { + member = try( + module.service-accounts["${each.value.project}/${v.member}"].iam_email, + var.factories_config.context.iam_principals[v.member], + v.member + ) + }) + } + labels = each.value.labels + location = coalesce( + var.data_overrides.storage_location, + lookup(each.value, "location", null), + var.data_defaults.storage_location + ) + storage_class = each.value.storage_class + uniform_bucket_level_access = each.value.uniform_bucket_level_access + versioning = each.value.versioning +} + module "service-accounts" { source = "../iam-service-account" for_each = { diff --git a/modules/project-factory/outputs.tf b/modules/project-factory/outputs.tf index 21e4fcd2b..a76c7f880 100644 --- a/modules/project-factory/outputs.tf +++ b/modules/project-factory/outputs.tf @@ -14,6 +14,13 @@ * limitations under the License. */ +output "buckets" { + description = "Bucket names." + value = { + for k, v in module.buckets : k => v.name + } +} + output "folders" { description = "Folder ids." value = local.hierarchy @@ -43,7 +50,5 @@ output "projects" { output "service_accounts" { description = "Service account emails." - value = { - for k, v in module.service-accounts : k => v.email - } + value = module.service-accounts } diff --git a/modules/project-factory/schemas/project.schema.json b/modules/project-factory/schemas/project.schema.json index 82a2aa16e..1517a8fc8 100644 --- a/modules/project-factory/schemas/project.schema.json +++ b/modules/project-factory/schemas/project.schema.json @@ -15,49 +15,7 @@ "type": "string" }, "buckets": { - "type": "object", - "additionalProperties": false, - "patternProperties": { - "^[a-z0-9-]+$": { - "type": "object", - "additionalProperties": false, - "properties": { - "description": { - "type": "string" - }, - "iam": { - "$ref": "#/$defs/iam" - }, - "iam_bindings": { - "$ref": "#/$defs/iam_bindings" - }, - "iam_bindings_additive": { - "$ref": "#/$defs/iam_bindings_additive" - }, - "labels": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "location": { - "type": "string" - }, - "prefix": { - "type": "string" - }, - "storage_class": { - "type": "string" - }, - "uniform_bucket_level_access": { - "type": "boolean" - }, - "versioning": { - "type": "boolean" - } - } - } - } + "$ref": "#/$defs/buckets" }, "service_accounts": { "type": "object", @@ -112,6 +70,9 @@ "type": "string" } }, + "buckets": { + "$ref": "#/$defs/buckets" + }, "contacts": { "type": "object", "additionalProperties": false, @@ -381,6 +342,51 @@ } }, "$defs": { + "buckets": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^[a-z0-9-]+$": { + "type": "object", + "additionalProperties": false, + "properties": { + "description": { + "type": "string" + }, + "iam": { + "$ref": "#/$defs/iam" + }, + "iam_bindings": { + "$ref": "#/$defs/iam_bindings" + }, + "iam_bindings_additive": { + "$ref": "#/$defs/iam_bindings_additive" + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "location": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "storage_class": { + "type": "string" + }, + "uniform_bucket_level_access": { + "type": "boolean" + }, + "versioning": { + "type": "boolean" + } + } + } + } + }, "iam": { "type": "object", "additionalProperties": false, diff --git a/modules/project/README.md b/modules/project/README.md index 878b9e4f5..4f3eeb828 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -29,7 +29,7 @@ This module implements the creation and management of one GCP project including - [Quotas factory](#quotas-factory) - [VPC Service Controls](#vpc-service-controls) - [Project Related Outputs](#project-related-outputs) - - [Managing project related configuration without creating it](#managing-project-related-configuration-without-creating-it) +- [Managing project related configuration without creating it](#managing-project-related-configuration-without-creating-it) - [Observability](#observability) - [Observability factory](#observability-factory) - [Files](#files) @@ -752,6 +752,7 @@ module "project" { } # tftest modules=1 resources=3 inventory=logging-data-access.yaml e2e ``` + ## Log Scopes ```hcl @@ -1203,9 +1204,14 @@ output "default_service_accounts" { # tftest modules=1 resources=3 inventory=outputs.yaml e2e ``` -### Managing project related configuration without creating it +## Managing project related configuration without creating it -The module offers managing all related resources without ever touching the project itself by using `project_create = false` +The module also supports configuring an existing project, via the `project_reuse` variable. Two different behaviours are possible when a project is reused: + +- using a data source to fetch project data (name and number) dynamically +- avoiding use of a data source when project data is known + +The first use case is the most common one, and is what the module defaults to when the `project_reuse` variable is not null. The second use case is used when project creation and configuration are split in two separate modules in the same Terraform root module, e.g. to avoid dependency cycles. ```hcl module "create-project" { @@ -1217,14 +1223,19 @@ module "create-project" { } module "project" { - source = "./fabric/modules/project" - depends_on = [module.create-project] - billing_account = var.billing_account_id - name = "project" - parent = var.folder_id - prefix = var.prefix - project_create = false - + source = "./fabric/modules/project" + name = module.create-project.project_id + prefix = var.prefix + # default behavior, uses a data source internally + # project_reuse = {} + # avoid use of a data source when project attributes are available + project_reuse = { + use_data_source = false + project_attributes = { + name = module.create-project.name + number = module.create-project.number + } + } iam_by_principals = { "group:${var.group_email}" = [ "roles/cloudasset.owner", @@ -1577,7 +1588,6 @@ alerts: foo: bar ``` - ## Files @@ -1609,7 +1619,7 @@ alerts: | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L110) | Project name and id suffix. | string | ✓ | | +| [name](variables.tf#L109) | Project name and id suffix. | string | ✓ | | | [alerts](variables-observability.tf#L17) | Monitoring alerts. | map(object({…})) | | {} | | [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | bool | | false | | [billing_account](variables.tf#L23) | Billing account id. | string | | null | @@ -1617,16 +1627,16 @@ alerts: | [contacts](variables.tf#L36) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} | | [custom_roles](variables.tf#L43) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | | [default_service_account](variables.tf#L50) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string | | "keep" | -| [deletion_policy](variables.tf#L64) | Deletion policy setting for this project. | string | | "DELETE" | -| [descriptive_name](variables.tf#L75) | Name of the project name. Used for project name instead of `name` variable. | string | | null | -| [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | +| [deletion_policy](variables.tf#L63) | Deletion policy setting for this project. | string | | "DELETE" | +| [descriptive_name](variables.tf#L74) | Name of the project name. Used for project name instead of `name` variable. | string | | null | +| [factories_config](variables.tf#L80) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} | | [iam](variables-iam.tf#L17) | Authoritative IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | | [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} | | [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} | | [iam_by_principals](variables-iam.tf#L61) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam` variable. | map(list(string)) | | {} | | [iam_by_principals_additive](variables-iam.tf#L54) | Additive IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam_bindings_additive` variable. | map(list(string)) | | {} | -| [labels](variables.tf#L97) | Resource labels. | map(string) | | {} | -| [lien_reason](variables.tf#L104) | If non-empty, creates a project lien with this description. | string | | null | +| [labels](variables.tf#L96) | Resource labels. | map(string) | | {} | +| [lien_reason](variables.tf#L103) | If non-empty, creates a project lien with this description. | string | | null | | [log_scopes](variables-observability.tf#L117) | Log scopes under this project. | map(object({…})) | | {} | | [logging_data_access](variables-observability.tf#L127) | Control activation of data access logs. The special 'allServices' key denotes configuration for all services. | map(object({…})) | | {} | | [logging_exclusions](variables-observability.tf#L138) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string) | | {} | @@ -1635,22 +1645,22 @@ alerts: | [metric_scopes](variables-observability.tf#L216) | List of projects that will act as metric scopes for this project. | list(string) | | [] | | [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | | [notification_channels](variables-observability.tf#L223) | Monitoring notification channels. | map(object({…})) | | {} | -| [org_policies](variables.tf#L115) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} | -| [parent](variables.tf#L143) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null | -| [prefix](variables.tf#L153) | Optional prefix used to generate project id and name. | string | | null | -| [project_create](variables.tf#L163) | Create project. When set to false, uses a data source to reference existing project. | bool | | true | +| [org_policies](variables.tf#L114) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} | +| [parent](variables.tf#L142) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null | +| [prefix](variables.tf#L152) | Optional prefix used to generate project id and name. | string | | null | +| [project_reuse](variables.tf#L162) | Reuse existing project if not null. If name and number are not passed in, a data source is used. | object({…}) | | null | | [quotas](variables-quotas.tf#L17) | Service quota configuration. | map(object({…})) | | {} | -| [service_agents_config](variables.tf#L169) | Automatic service agent configuration options. | object({…}) | | {} | -| [service_config](variables.tf#L180) | Configure service API activation. | object({…}) | | {…} | -| [service_encryption_key_ids](variables.tf#L192) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string)) | | {} | -| [services](variables.tf#L199) | Service APIs to enable. | list(string) | | [] | -| [shared_vpc_host_config](variables.tf#L205) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null | -| [shared_vpc_service_config](variables.tf#L214) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | {…} | -| [skip_delete](variables.tf#L242) | Deprecated. Use deletion_policy. | bool | | null | +| [service_agents_config](variables.tf#L181) | Automatic service agent configuration options. | object({…}) | | {} | +| [service_config](variables.tf#L192) | Configure service API activation. | object({…}) | | {…} | +| [service_encryption_key_ids](variables.tf#L204) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string)) | | {} | +| [services](variables.tf#L211) | Service APIs to enable. | list(string) | | [] | +| [shared_vpc_host_config](variables.tf#L217) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null | +| [shared_vpc_service_config](variables.tf#L226) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | {…} | +| [skip_delete](variables.tf#L254) | Deprecated. Use deletion_policy. | bool | | null | | [tag_bindings](variables-tags.tf#L81) | Tag bindings for this project, in key => tag value id format. | map(string) | | null | | [tags](variables-tags.tf#L88) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | -| [universe](variables.tf#L254) | GCP universe where to deploy the project. The prefix will be prepended to the project id. | object({…}) | | null | -| [vpc_sc](variables.tf#L263) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…}) | | null | +| [universe](variables.tf#L266) | GCP universe where to deploy the project. The prefix will be prepended to the project id. | object({…}) | | null | +| [vpc_sc](variables.tf#L275) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…}) | | null | ## Outputs diff --git a/modules/project/main.tf b/modules/project/main.tf index 8cf3106e9..c789c11a4 100644 --- a/modules/project/main.tf +++ b/modules/project/main.tf @@ -26,31 +26,39 @@ locals { parent_type = var.parent == null ? null : split("/", var.parent)[0] parent_id = var.parent == null ? null : split("/", var.parent)[1] prefix = var.prefix == null ? "" : "${var.prefix}-" - project_id = "${local.universe_prefix}${local.prefix}${var.name}" project = ( - var.project_create ? - { + var.project_reuse == null + ? { project_id = try(google_project.project[0].project_id, null) number = try(google_project.project[0].number, null) name = try(google_project.project[0].name, null) } - : { - project_id = local.project_id - number = try(data.google_project.project[0].number, null) - name = try(data.google_project.project[0].name, null) - } + : ( + try(var.project_reuse.use_data_source, null) == false + ? { + project_id = local.project_id + number = try(var.project_reuse.project_attributes.number, null) + name = try(var.project_reuse.project_attributes.name, null) + } + : { + project_id = local.project_id + number = try(data.google_project.project[0].number, null) + name = try(data.google_project.project[0].name, null) + } + ) ) + project_id = "${local.universe_prefix}${local.prefix}${var.name}" universe_prefix = var.universe == null ? "" : "${var.universe.prefix}:" available_services = tolist(setsubtract(var.services, try(var.universe.unavailable_services, []))) } data "google_project" "project" { - count = var.project_create ? 0 : 1 + count = try(var.project_reuse.use_data_source, null) == true ? 1 : 0 project_id = local.project_id } resource "google_project" "project" { - count = var.project_create ? 1 : 0 + count = var.project_reuse == null ? 1 : 0 org_id = local.parent_type == "organizations" ? local.parent_id : null folder_id = local.parent_type == "folders" ? local.parent_id : null project_id = local.project_id diff --git a/modules/project/variables.tf b/modules/project/variables.tf index b0e27c928..dd9340907 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -60,7 +60,6 @@ variable "default_service_account" { } } - variable "deletion_policy" { description = "Deletion policy setting for this project." default = "DELETE" @@ -160,10 +159,23 @@ variable "prefix" { } } -variable "project_create" { - description = "Create project. When set to false, uses a data source to reference existing project." - type = bool - default = true +variable "project_reuse" { + description = "Reuse existing project if not null. If name and number are not passed in, a data source is used." + type = object({ + use_data_source = optional(bool, true) + project_attributes = optional(object({ + name = string + number = number + })) + }) + default = null + validation { + condition = ( + try(var.project_reuse.use_data_source, null) != false || + try(var.project_reuse.project_attributes, null) != null + ) + error_message = "Reuse datasource can be disabled only if project attributes are set." + } } variable "service_agents_config" { diff --git a/tests/fast/addons/a1_resman_tenants/simple.yaml b/tests/fast/addons/a1_resman_tenants/simple.yaml index ce130cbb6..46cb95a94 100644 --- a/tests/fast/addons/a1_resman_tenants/simple.yaml +++ b/tests/fast/addons/a1_resman_tenants/simple.yaml @@ -25,7 +25,7 @@ counts: google_logging_project_bucket_config: 4 google_org_policy_policy: 6 google_organization_iam_member: 6 - google_project: 6 + google_project: 4 google_project_iam_audit_config: 2 google_project_iam_binding: 32 google_project_iam_member: 34 @@ -43,4 +43,4 @@ counts: google_tags_tag_key: 1 google_tags_tag_value: 4 modules: 50 - resources: 291 + resources: 289 diff --git a/tests/modules/project/examples/data.yaml b/tests/modules/project/examples/data.yaml index bae69bb7c..14f4e0fd8 100644 --- a/tests/modules/project/examples/data.yaml +++ b/tests/modules/project/examples/data.yaml @@ -26,11 +26,16 @@ values: auto_create_network: false billing_account: 123456-123456-123456 deletion_policy: DELETE + effective_labels: + goog-terraform-provisioned: 'true' folder_id: '1122334455' labels: null name: test-project org_id: null project_id: test-project + tags: null + terraform_labels: + goog-terraform-provisioned: 'true' timeouts: null module.dataset.google_bigquery_dataset.default: dataset_id: bq_sink @@ -39,6 +44,8 @@ values: default_table_expiration_ms: null delete_contents_on_destroy: true description: Terraform managed. + effective_labels: + goog-terraform-provisioned: 'true' external_dataset_reference: [] friendly_name: null labels: null @@ -46,15 +53,20 @@ values: max_time_travel_hours: '168' project: project-id resource_tags: null + terraform_labels: + goog-terraform-provisioned: 'true' timeouts: null module.gcs.google_storage_bucket.bucket[0]: autoclass: [] cors: [] custom_placement_config: [] default_event_based_hold: null + effective_labels: + goog-terraform-provisioned: 'true' enable_object_retention: null encryption: [] force_destroy: true + hierarchical_namespace: [] labels: null lifecycle_rule: [] location: EU @@ -64,6 +76,8 @@ values: requester_pays: null retention_policy: [] storage_class: STANDARD + terraform_labels: + goog-terraform-provisioned: 'true' timeouts: null uniform_bucket_level_access: true module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]: @@ -73,18 +87,27 @@ values: auto_create_network: false billing_account: 123456-123456-123456 deletion_policy: DELETE + effective_labels: + goog-terraform-provisioned: 'true' folder_id: '1122334455' labels: null name: test-host org_id: null project_id: test-host + tags: null + terraform_labels: + goog-terraform-provisioned: 'true' timeouts: null module.kms.google_kms_crypto_key.default["key-global"]: + effective_labels: + goog-terraform-provisioned: 'true' labels: null name: key-global purpose: ENCRYPT_DECRYPT rotation_period: null skip_initial_version_creation: false + terraform_labels: + goog-terraform-provisioned: 'true' timeouts: null module.kms.google_kms_key_ring.default[0]: location: global @@ -95,11 +118,9 @@ values: condition: [] role: roles/cloudkms.cryptoKeyEncrypterDecrypter module.project.data.google_bigquery_default_service_account.bq_sa[0]: - project: test-project - module.project.data.google_project.project[0]: - project_id: test-project + project: test-test-project module.project.data.google_storage_project_service_account.gcs_sa[0]: - project: test-project + project: test-test-project user_project: null module.project.google_bigquery_dataset_iam_member.bq-sinks-binding["info"]: condition: [] @@ -107,7 +128,7 @@ values: module.project.google_compute_shared_vpc_service_project.shared_vpc_service[0]: deletion_policy: null host_project: test-host - service_project: test-project + service_project: test-test-project timeouts: null module.project.google_kms_crypto_key_iam_member.service_agent_cmek["key-0.compute-system"]: condition: [] @@ -120,7 +141,7 @@ values: disabled: null filter: resource.type=gce_instance name: no-gce-instances - project: test-project + project: test-test-project module.project.google_logging_project_sink.sink["debug"]: custom_writer_identity: null description: debug (Terraform-managed). @@ -132,7 +153,7 @@ values: name: no-compute filter: severity=DEBUG name: debug - project: test-project + project: test-test-project unique_writer_identity: true module.project.google_logging_project_sink.sink["info"]: bigquery_options: @@ -143,7 +164,7 @@ values: exclusions: [] filter: severity=INFO name: info - project: test-project + project: test-test-project unique_writer_identity: true module.project.google_logging_project_sink.sink["notice"]: custom_writer_identity: null @@ -153,7 +174,7 @@ values: exclusions: [] filter: severity=NOTICE name: notice - project: test-project + project: test-test-project unique_writer_identity: true module.project.google_logging_project_sink.sink["warnings"]: custom_writer_identity: null @@ -163,12 +184,12 @@ values: exclusions: [] filter: severity=WARNING name: warnings - project: test-project + project: test-test-project unique_writer_identity: true module.project.google_org_policy_policy.default["compute.disableGuestAttributesAccess"]: dry_run_spec: [] - name: projects/test-project/policies/compute.disableGuestAttributesAccess - parent: projects/test-project + name: projects/test-test-project/policies/compute.disableGuestAttributesAccess + parent: projects/test-test-project spec: - inherit_from_parent: null reset: null @@ -177,12 +198,13 @@ values: condition: [] deny_all: null enforce: 'TRUE' + parameters: null values: [] timeouts: null module.project.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]: dry_run_spec: [] - name: projects/test-project/policies/compute.skipDefaultNetworkCreation - parent: projects/test-project + name: projects/test-test-project/policies/compute.skipDefaultNetworkCreation + parent: projects/test-test-project spec: - inherit_from_parent: null reset: null @@ -191,12 +213,13 @@ values: condition: [] deny_all: null enforce: 'TRUE' + parameters: null values: [] timeouts: null module.project.google_org_policy_policy.default["compute.trustedImageProjects"]: dry_run_spec: [] - name: projects/test-project/policies/compute.trustedImageProjects - parent: projects/test-project + name: projects/test-test-project/policies/compute.trustedImageProjects + parent: projects/test-test-project spec: - inherit_from_parent: null reset: null @@ -205,6 +228,7 @@ values: condition: [] deny_all: null enforce: null + parameters: null values: - allowed_values: - projects/my-project @@ -212,8 +236,8 @@ values: timeouts: null module.project.google_org_policy_policy.default["compute.vmExternalIpAccess"]: dry_run_spec: [] - name: projects/test-project/policies/compute.vmExternalIpAccess - parent: projects/test-project + name: projects/test-test-project/policies/compute.vmExternalIpAccess + parent: projects/test-test-project spec: - inherit_from_parent: null reset: null @@ -222,12 +246,13 @@ values: condition: [] deny_all: 'TRUE' enforce: null + parameters: null values: [] timeouts: null module.project.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]: dry_run_spec: [] - name: projects/test-project/policies/iam.allowedPolicyMemberDomains - parent: projects/test-project + name: projects/test-test-project/policies/iam.allowedPolicyMemberDomains + parent: projects/test-test-project spec: - inherit_from_parent: null reset: null @@ -236,6 +261,7 @@ values: condition: [] deny_all: null enforce: null + parameters: null values: - allowed_values: - C0xxxxxxx @@ -244,8 +270,8 @@ values: timeouts: null module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]: dry_run_spec: [] - name: projects/test-project/policies/iam.disableServiceAccountKeyCreation - parent: projects/test-project + name: projects/test-test-project/policies/iam.disableServiceAccountKeyCreation + parent: projects/test-test-project spec: - inherit_from_parent: null reset: null @@ -254,12 +280,13 @@ values: condition: [] deny_all: null enforce: 'TRUE' + parameters: null values: [] timeouts: null module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyUpload"]: dry_run_spec: [] - name: projects/test-project/policies/iam.disableServiceAccountKeyUpload - parent: projects/test-project + name: projects/test-test-project/policies/iam.disableServiceAccountKeyUpload + parent: projects/test-test-project spec: - inherit_from_parent: null reset: null @@ -272,11 +299,13 @@ values: title: condition deny_all: null enforce: 'TRUE' + parameters: null values: [] - allow_all: null condition: [] deny_all: null enforce: 'FALSE' + parameters: null values: [] timeouts: null module.project.google_project_iam_audit_config.default["allServices"]: @@ -284,7 +313,7 @@ values: - exempted_members: - group:organization-admins@example.org log_type: ADMIN_READ - project: test-project + project: test-test-project service: allServices module.project.google_project_iam_audit_config.default["storage.googleapis.com"]: audit_log_config: @@ -292,39 +321,39 @@ values: log_type: DATA_READ - exempted_members: [] log_type: DATA_WRITE - project: test-project + project: test-test-project service: storage.googleapis.com module.project.google_project_iam_binding.authoritative["roles/apigee.serviceAgent"]: condition: [] - project: test-project + project: test-test-project role: roles/apigee.serviceAgent module.project.google_project_iam_binding.authoritative["roles/cloudasset.owner"]: condition: [] members: - group:organization-admins@example.org - project: test-project + project: test-test-project role: roles/cloudasset.owner module.project.google_project_iam_binding.authoritative["roles/cloudsupport.techSupportEditor"]: condition: [] members: - group:organization-admins@example.org - project: test-project + project: test-test-project role: roles/cloudsupport.techSupportEditor module.project.google_project_iam_binding.authoritative["roles/editor"]: condition: [] - project: test-project + project: test-test-project role: roles/editor module.project.google_project_iam_binding.authoritative["roles/iam.securityReviewer"]: condition: [] members: - group:organization-admins@example.org - project: test-project + project: test-test-project role: roles/iam.securityReviewer module.project.google_project_iam_binding.authoritative["roles/logging.admin"]: condition: [] members: - group:organization-admins@example.org - project: test-project + project: test-test-project role: roles/logging.admin module.project.google_project_iam_binding.bindings["iam_admin_conditional"]: condition: @@ -334,12 +363,12 @@ values: title: delegated_network_user_one members: - group:organization-admins@example.org - project: test-project + project: test-test-project role: roles/resourcemanager.projectIamAdmin module.project.google_project_iam_member.bindings["group-owner"]: condition: [] member: group:organization-admins@example.org - project: test-project + project: test-test-project role: roles/owner module.project.google_project_iam_member.bucket-sinks-binding["debug"]: condition: @@ -347,23 +376,23 @@ values: role: roles/logging.bucketWriter module.project.google_project_iam_member.service_agents["apigee"]: condition: [] - project: test-project + project: test-test-project role: roles/apigee.serviceAgent module.project.google_project_iam_member.service_agents["compute-system"]: condition: [] - project: test-project + project: test-test-project role: roles/compute.serviceAgent module.project.google_project_iam_member.service_agents["container-engine-robot"]: condition: [] - project: test-project + project: test-test-project role: roles/container.serviceAgent module.project.google_project_iam_member.service_agents["gkenode"]: condition: [] - project: test-project + project: test-test-project role: roles/container.defaultNodeServiceAgent module.project.google_project_iam_member.service_agents["serverless-robot-prod"]: condition: [] - project: test-project + project: test-test-project role: roles/run.serviceAgent module.project.google_project_iam_member.shared_vpc_host_robots["roles/cloudasset.owner:cloudservices"]: condition: [] @@ -396,55 +425,55 @@ values: module.project.google_project_service.project_services["apigee.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-project + project: test-test-project service: apigee.googleapis.com timeouts: null module.project.google_project_service.project_services["bigquery.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-project + project: test-test-project service: bigquery.googleapis.com timeouts: null module.project.google_project_service.project_services["compute.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-project + project: test-test-project service: compute.googleapis.com timeouts: null module.project.google_project_service.project_services["container.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-project + project: test-test-project service: container.googleapis.com timeouts: null module.project.google_project_service.project_services["logging.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-project + project: test-test-project service: logging.googleapis.com timeouts: null module.project.google_project_service.project_services["run.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-project + project: test-test-project service: run.googleapis.com timeouts: null module.project.google_project_service.project_services["storage.googleapis.com"]: disable_dependent_services: false disable_on_destroy: false - project: test-project + project: test-test-project service: storage.googleapis.com timeouts: null module.project.google_project_service_identity.default["apigee.googleapis.com"]: - project: test-project + project: test-test-project service: apigee.googleapis.com timeouts: null module.project.google_project_service_identity.default["container.googleapis.com"]: - project: test-project + project: test-test-project service: container.googleapis.com timeouts: null module.project.google_project_service_identity.default["run.googleapis.com"]: - project: test-project + project: test-test-project service: run.googleapis.com timeouts: null module.project.google_pubsub_topic_iam_member.pubsub-sinks-binding["notice"]: @@ -457,12 +486,17 @@ values: condition: [] role: roles/storage.objectCreator module.pubsub.google_pubsub_topic.default: + effective_labels: + goog-terraform-provisioned: 'true' ingestion_data_source_settings: [] kms_key_name: null labels: null message_retention_duration: null name: pubsub_sink project: project-id + schema_settings: [] + terraform_labels: + goog-terraform-provisioned: 'true' timeouts: null counts: @@ -479,7 +513,7 @@ counts: google_logging_project_exclusion: 1 google_logging_project_sink: 4 google_org_policy_policy: 7 - google_project: 3 + google_project: 2 google_project_iam_audit_config: 2 google_project_iam_binding: 7 google_project_iam_member: 14 @@ -491,7 +525,7 @@ counts: google_storage_bucket_iam_member: 1 google_storage_project_service_account: 1 modules: 8 - resources: 64 + resources: 63 outputs: {} diff --git a/tests/modules/project_factory/examples/example.yaml b/tests/modules/project_factory/examples/example.yaml index 1ddb659de..1eabc1f54 100644 --- a/tests/modules/project_factory/examples/example.yaml +++ b/tests/modules/project_factory/examples/example.yaml @@ -12,15 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +values: values: module.project-factory.module.automation-buckets["dev-tb-app0-0/state"].google_storage_bucket.bucket[0]: autoclass: [] cors: [] custom_placement_config: [] default_event_based_hold: null + effective_labels: + goog-terraform-provisioned: 'true' enable_object_retention: null encryption: [] force_destroy: false + hierarchical_namespace: [] labels: null lifecycle_rule: [] location: EU @@ -30,8 +34,12 @@ values: requester_pays: null retention_policy: [] storage_class: STANDARD + terraform_labels: + goog-terraform-provisioned: 'true' timeouts: null uniform_bucket_level_access: true + versioning: + - enabled: false ? module.project-factory.module.automation-buckets["dev-tb-app0-0/state"].google_storage_bucket_iam_binding.authoritative["roles/storage.objectCreator"] : bucket: test-pf-dev-tb-app0-0-state condition: [] @@ -53,6 +61,8 @@ values: description: Team B app 0 read-only automation sa. disabled: false display_name: Service account ro for dev-tb-app0-0. + email: test-pf-dev-tb-app0-0-ro@test-pf-teams-iac-0.iam.gserviceaccount.com + member: serviceAccount:test-pf-dev-tb-app0-0-ro@test-pf-teams-iac-0.iam.gserviceaccount.com project: test-pf-teams-iac-0 timeouts: null module.project-factory.module.automation-service-accounts["dev-tb-app0-0/rw"].google_service_account.service_account[0]: @@ -61,6 +71,8 @@ values: description: Team B app 0 read/write automation sa. disabled: false display_name: Service account rw for dev-tb-app0-0. + email: test-pf-dev-tb-app0-0-rw@test-pf-teams-iac-0.iam.gserviceaccount.com + member: serviceAccount:test-pf-dev-tb-app0-0-rw@test-pf-teams-iac-0.iam.gserviceaccount.com project: test-pf-teams-iac-0 timeouts: null module.project-factory.module.billing-account[0].google_billing_budget.default["test-100"]: @@ -102,8 +114,10 @@ values: type: email user_labels: null module.project-factory.module.hierarchy-folder-lvl-1["team-a"].google_folder.folder[0]: + deletion_protection: false display_name: Team A parent: folders/5678901234 + tags: null timeouts: null module.project-factory.module.hierarchy-folder-lvl-1["team-a"].google_folder_iam_binding.authoritative["roles/viewer"]: condition: [] @@ -112,22 +126,42 @@ values: - group:team-a-admins@example.org role: roles/viewer module.project-factory.module.hierarchy-folder-lvl-1["team-b"].google_folder.folder[0]: + deletion_protection: false display_name: Team B parent: folders/5678901234 + tags: null timeouts: null module.project-factory.module.hierarchy-folder-lvl-1["team-c"].google_folder.folder[0]: + deletion_protection: false display_name: Team C parent: folders/5678901234 + tags: null timeouts: null module.project-factory.module.hierarchy-folder-lvl-2["team-a/app-0"].google_folder.folder[0]: + deletion_protection: false display_name: App 0 + tags: null timeouts: null module.project-factory.module.hierarchy-folder-lvl-2["team-b/app-0"].google_folder.folder[0]: + deletion_protection: false display_name: App 0 + tags: null timeouts: null module.project-factory.module.hierarchy-folder-lvl-2["team-b/app-0"].google_tags_tag_binding.binding["drs-allow-all"]: tag_value: tagValues/123456 timeouts: null + module.project-factory.module.projects-iam["dev-tb-app0-0"].google_project_iam_binding.authoritative["roles/owner"]: + condition: [] + members: + - serviceAccount:test-pf-dev-tb-app0-0-rw@test-pf-teams-iac-0.iam.gserviceaccount.com + project: test-pf-dev-tb-app0-0 + role: roles/owner + module.project-factory.module.projects-iam["dev-tb-app0-0"].google_project_iam_binding.authoritative["roles/viewer"]: + condition: [] + members: + - serviceAccount:test-pf-dev-tb-app0-0-ro@test-pf-teams-iac-0.iam.gserviceaccount.com + project: test-pf-dev-tb-app0-0 + role: roles/viewer module.project-factory.module.projects["dev-ta-app0-be"].data.google_storage_project_service_account.gcs_sa[0]: project: test-pf-dev-ta-app0-be user_project: null @@ -154,6 +188,7 @@ values: effective_labels: app: app-0 environment: test + goog-terraform-provisioned: 'true' team: team-a labels: app: app-0 @@ -161,9 +196,11 @@ values: team: team-a name: test-pf-dev-ta-app0-be project_id: test-pf-dev-ta-app0-be + tags: null terraform_labels: app: app-0 environment: test + goog-terraform-provisioned: 'true' team: team-a timeouts: null ? module.project-factory.module.projects["dev-ta-app0-be"].google_project_iam_member.service_agents["container-engine-robot"] @@ -228,25 +265,16 @@ values: deletion_policy: DELETE effective_labels: environment: test + goog-terraform-provisioned: 'true' labels: environment: test name: test-pf-dev-tb-app0-0 project_id: test-pf-dev-tb-app0-0 + tags: null terraform_labels: environment: test + goog-terraform-provisioned: 'true' timeouts: null - module.project-factory.module.projects["dev-tb-app0-0"].google_project_iam_binding.authoritative["roles/owner"]: - condition: [] - members: - - serviceAccount:test-pf-dev-tb-app0-0-rw@test-pf-teams-iac-0.iam.gserviceaccount.com - project: test-pf-dev-tb-app0-0 - role: roles/owner - module.project-factory.module.projects["dev-tb-app0-0"].google_project_iam_binding.authoritative["roles/viewer"]: - condition: [] - members: - - serviceAccount:test-pf-dev-tb-app0-0-ro@test-pf-teams-iac-0.iam.gserviceaccount.com - project: test-pf-dev-tb-app0-0 - role: roles/viewer module.project-factory.module.projects["dev-tb-app0-0"].google_project_iam_member.service_agents["serverless-robot-prod"]: condition: [] project: test-pf-dev-tb-app0-0 @@ -289,14 +317,17 @@ values: deletion_policy: DELETE effective_labels: environment: test + goog-terraform-provisioned: 'true' folder_id: '5678901234' labels: environment: test name: test-pf-teams-iac-0 org_id: null project_id: test-pf-teams-iac-0 + tags: null terraform_labels: environment: test + goog-terraform-provisioned: 'true' timeouts: null module.project-factory.module.projects["teams-iac-0"].google_project_iam_member.service_agents["container-engine-robot"]: condition: [] @@ -346,6 +377,8 @@ values: description: null disabled: false display_name: Backend instances. + email: app-0-be@test-pf-dev-ta-app0-be.iam.gserviceaccount.com + member: serviceAccount:app-0-be@test-pf-dev-ta-app0-be.iam.gserviceaccount.com project: test-pf-dev-ta-app0-be timeouts: null ? module.project-factory.module.service-accounts["dev-ta-app0-be/app-0-fe"].google_project_iam_member.project-roles["test-pf-dev-net-spoke-0-roles/compute.networkUser"] @@ -366,6 +399,8 @@ values: description: null disabled: false display_name: Frontend instances. + email: app-0-fe@test-pf-dev-ta-app0-be.iam.gserviceaccount.com + member: serviceAccount:app-0-fe@test-pf-dev-ta-app0-be.iam.gserviceaccount.com project: test-pf-dev-ta-app0-be timeouts: null @@ -388,5 +423,5 @@ counts: google_storage_bucket_iam_binding: 2 google_storage_project_service_account: 3 google_tags_tag_binding: 1 - modules: 15 + modules: 16 resources: 56 diff --git a/tools/tfdoc.py b/tools/tfdoc.py index 04e7db91d..9cbd17d74 100755 --- a/tools/tfdoc.py +++ b/tools/tfdoc.py @@ -169,16 +169,19 @@ def _parse(body, enum=VAR_ENUM, re=VAR_RE, template=VAR_TEMPLATE): item[context].append(data) -def create_toc(readme): +def create_toc(readme, skip=['contents']): 'Create a Markdown table of contents a for README.' doc = marko.parse(readme) lines = [] headings = [x for x in doc.children if x.get_type() == 'Heading'] + skip = skip or [] for h in headings[1:]: title = h.children[0].children slug = title.lower().strip() slug = re.sub(r'[^\w\s-]', '', slug) slug = re.sub(r'[-\s]+', '-', slug) + if slug in skip: + continue link = f'- [{title}](#{slug})' indent = ' ' * (h.level - 2) lines.append(f'{indent}{link}') @@ -512,8 +515,9 @@ def render_toc(readme, toc): @click.option('--replace/--no-replace', default=True) @click.option('--show-extra/--no-show-extra', default=False) @click.option('--toc-only', is_flag=True, default=False) +@click.option('--toc-skip', multiple=True, default=['contents']) def main(module_path=None, exclude_file=None, files=False, replace=True, - show_extra=True, toc_only=False): + show_extra=True, toc_only=False, toc_skip=['contents']): 'Program entry point.' if toc_only and module_path.endswith('.md'): readme_path = module_path @@ -523,7 +527,7 @@ def main(module_path=None, exclude_file=None, files=False, replace=True, if not toc_only: doc = create_tfref(module_path, files, show_extra, exclude_file, readme) readme = render_tfref(readme, doc.content) - toc = create_toc(readme) + toc = create_toc(readme, toc_skip) readme = render_toc(readme, toc) if replace: try: