diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index 6998eafe..080422e7 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -62,3 +62,8 @@ jobs: id: documentation-links-fabric run: | python3 tools/check_links.py . + + - name: Check name length (fast) + id: name-length-fast + run: | + python3 tools/check_names.py --prefix-length=10 fast/stages diff --git a/fast/stages/00-bootstrap/README.md b/fast/stages/00-bootstrap/README.md index 52a2e107..0add953b 100644 --- a/fast/stages/00-bootstrap/README.md +++ b/fast/stages/00-bootstrap/README.md @@ -66,7 +66,7 @@ We are intentionally not supporting random prefix/suffixes for names, as that is What is implemented here is a fairly common convention, composed of tokens ordered by relative importance: -- a static prefix (e.g. `myco` or `myco-gcp`) +- a static prefix less or equal to 9 characters (e.g. `myco` or `myco-gcp`) - an environment identifier (e.g. `prod`) - a team/owner identifier (e.g. `sec` for Security) - a context identifier (e.g. `core` or `kms`) @@ -169,7 +169,7 @@ Then make sure you have configured the correct values for the following variable - `organization.id`, `organization.domain`, `organization.customer_id` the id, domain and customer id of your organization, derived from the Cloud Console UI or by running `gcloud organizations list` - `prefix` - the fixed prefix used in your naming convention + the fixed prefix used in your naming, maximum 9 characters long You can also adapt the example that follows to your needs: @@ -337,7 +337,7 @@ Names used in internal references (e.g. `module.foo-prod.id`) are only used by T |---|---|:---:|:---:|:---:|:---:| | [billing_account](variables.tf#L17) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | | | [organization](variables.tf#L96) | Organization details. | object({…}) | ✓ | | | -| [prefix](variables.tf#L111) | Prefix used for resources that need unique names. | string | ✓ | | | +| [prefix](variables.tf#L111) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | | | [bootstrap_user](variables.tf#L25) | Email of the nominal user running this stage for the first time. | string | | null | | | [custom_role_names](variables.tf#L31) | Names of custom roles defined at the org level. | object({…}) | | {…} | | | [groups](variables.tf#L43) | Group names to grant organization-level permissions. | map(string) | | {…} | | diff --git a/fast/stages/00-bootstrap/billing.tf b/fast/stages/00-bootstrap/billing.tf index e8227041..70053c71 100644 --- a/fast/stages/00-bootstrap/billing.tf +++ b/fast/stages/00-bootstrap/billing.tf @@ -31,7 +31,7 @@ module "billing-export-project" { source = "../../../modules/project" count = local.billing_org ? 1 : 0 billing_account = var.billing_account.id - name = "billing-export-0" + name = "billing-exp-0" parent = "organizations/${var.organization.id}" prefix = local.prefix iam = { diff --git a/fast/stages/00-bootstrap/variables.tf b/fast/stages/00-bootstrap/variables.tf index 33709703..68d54650 100644 --- a/fast/stages/00-bootstrap/variables.tf +++ b/fast/stages/00-bootstrap/variables.tf @@ -109,6 +109,11 @@ variable "outputs_location" { } variable "prefix" { - description = "Prefix used for resources that need unique names." + description = "Prefix used for resources that need unique names. Use 9 characters or less." type = string + + validation { + condition = try(length(var.prefix), 0) < 10 + error_message = "Use a maximum of 9 characters for prefix." + } } diff --git a/fast/stages/01-resman/README.md b/fast/stages/01-resman/README.md index e39cf3d2..8ff41f7d 100644 --- a/fast/stages/01-resman/README.md +++ b/fast/stages/01-resman/README.md @@ -166,12 +166,12 @@ Due to its simplicity, this stage lends itself easily to customizations: adding | [automation_project_id](variables.tf#L29) | Project id for the automation project created by the bootstrap stage. | string | ✓ | | 00-bootstrap | | [billing_account](variables.tf#L20) | Billing account id and organization id ('nnnnnnnn' or null). | object({…}) | ✓ | | 00-bootstrap | | [organization](variables.tf#L57) | Organization details. | object({…}) | ✓ | | 00-bootstrap | -| [prefix](variables.tf#L81) | Prefix used for resources that need unique names. | string | ✓ | | 00-bootstrap | +| [prefix](variables.tf#L81) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | | [custom_roles](variables.tf#L35) | Custom roles defined at the org level, in key => id format. | map(string) | | {} | 00-bootstrap | | [groups](variables.tf#L42) | Group names to grant organization-level permissions. | map(string) | | {…} | 00-bootstrap | | [organization_policy_configs](variables.tf#L67) | Organization policies customization. | object({…}) | | null | | | [outputs_location](variables.tf#L75) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | -| [team_folders](variables.tf#L87) | Team folders to be created. Format is described in a code comment. | map(object({…})) | | null | | +| [team_folders](variables.tf#L92) | Team folders to be created. Format is described in a code comment. | map(object({…})) | | null | | ## Outputs diff --git a/fast/stages/01-resman/branch-networking.tf b/fast/stages/01-resman/branch-networking.tf index bf712c4f..153aecb1 100644 --- a/fast/stages/01-resman/branch-networking.tf +++ b/fast/stages/01-resman/branch-networking.tf @@ -43,16 +43,16 @@ module "branch-network-folder" { module "branch-network-sa" { source = "../../../modules/iam-service-account" project_id = var.automation_project_id - name = "resman-networking-0" + name = "prod-resman-net-0" description = "Terraform resman networking service account." - prefix = local.prefixes.prod + prefix = var.prefix } module "branch-network-gcs" { source = "../../../modules/gcs" project_id = var.automation_project_id - name = "resman-networking-0" - prefix = local.prefixes.prod + name = "prod-resman-net-0" + prefix = var.prefix versioning = true iam = { "roles/storage.objectAdmin" = [module.branch-network-sa.iam_email] diff --git a/fast/stages/01-resman/branch-sandbox.tf b/fast/stages/01-resman/branch-sandbox.tf index e40aa3fe..0e145b6b 100644 --- a/fast/stages/01-resman/branch-sandbox.tf +++ b/fast/stages/01-resman/branch-sandbox.tf @@ -42,8 +42,8 @@ module "branch-sandbox-folder" { module "branch-sandbox-gcs" { source = "../../../modules/gcs" project_id = var.automation_project_id - name = "resman-sandbox-0" - prefix = local.prefixes.dev + name = "dev-resman-sbox-0" + prefix = var.prefix versioning = true iam = { "roles/storage.objectAdmin" = [module.branch-sandbox-sa.iam_email] @@ -53,7 +53,7 @@ module "branch-sandbox-gcs" { module "branch-sandbox-sa" { source = "../../../modules/iam-service-account" project_id = var.automation_project_id - name = "resman-sandbox-0" + name = "dev-resman-sbox-0" description = "Terraform resman sandbox service account." - prefix = local.prefixes.dev + prefix = var.prefix } diff --git a/fast/stages/01-resman/branch-security.tf b/fast/stages/01-resman/branch-security.tf index 94f68ecd..33bd5de0 100644 --- a/fast/stages/01-resman/branch-security.tf +++ b/fast/stages/01-resman/branch-security.tf @@ -44,16 +44,16 @@ module "branch-security-folder" { module "branch-security-sa" { source = "../../../modules/iam-service-account" project_id = var.automation_project_id - name = "resman-security-0" + name = "prod-resman-sec-0" description = "Terraform resman security service account." - prefix = local.prefixes.prod + prefix = var.prefix } module "branch-security-gcs" { source = "../../../modules/gcs" project_id = var.automation_project_id - name = "resman-security-0" - prefix = local.prefixes.prod + name = "prod-resman-sec-0" + prefix = var.prefix versioning = true iam = { "roles/storage.objectAdmin" = [module.branch-security-sa.iam_email] diff --git a/fast/stages/01-resman/branch-teams.tf b/fast/stages/01-resman/branch-teams.tf index 408a34ce..41caeadc 100644 --- a/fast/stages/01-resman/branch-teams.tf +++ b/fast/stages/01-resman/branch-teams.tf @@ -27,9 +27,9 @@ module "branch-teams-folder" { module "branch-teams-prod-sa" { source = "../../../modules/iam-service-account" project_id = var.automation_project_id - name = "resman-teams-0" + name = "prod-resman-teams-0" description = "Terraform resman production service account." - prefix = local.prefixes.prod + prefix = var.prefix } # Team-level folders, service accounts and buckets for each individual team @@ -46,9 +46,9 @@ module "branch-teams-team-sa" { source = "../../../modules/iam-service-account" for_each = coalesce(var.team_folders, {}) project_id = var.automation_project_id - name = "teams-${each.key}-0" + name = "prod-teams-${each.key}-0" description = "Terraform team ${each.key} service account." - prefix = local.prefixes.prod + prefix = var.prefix iam = { "roles/iam.serviceAccountTokenCreator" = ( each.value.impersonation_groups == null @@ -62,8 +62,8 @@ module "branch-teams-team-gcs" { source = "../../../modules/gcs" for_each = coalesce(var.team_folders, {}) project_id = var.automation_project_id - name = "teams-${each.key}-0" - prefix = local.prefixes.prod + name = "prod-teams-${each.key}-0" + prefix = var.prefix versioning = true iam = { "roles/storage.objectAdmin" = [module.branch-teams-team-sa[each.key].iam_email] @@ -103,17 +103,17 @@ module "branch-teams-team-dev-folder" { module "branch-teams-dev-projectfactory-sa" { source = "../../../modules/iam-service-account" project_id = var.automation_project_id - name = "resman-pf-0" + name = "dev-resman-pf-0" # naming: environment in description description = "Terraform project factory development service account." - prefix = local.prefixes.dev + prefix = var.prefix } module "branch-teams-dev-projectfactory-gcs" { source = "../../../modules/gcs" project_id = var.automation_project_id - name = "resman-pf-0" - prefix = local.prefixes.dev + name = "dev-resman-pf-0" + prefix = var.prefix versioning = true iam = { "roles/storage.objectAdmin" = [module.branch-teams-dev-projectfactory-sa.iam_email] @@ -153,17 +153,17 @@ module "branch-teams-team-prod-folder" { module "branch-teams-prod-projectfactory-sa" { source = "../../../modules/iam-service-account" project_id = var.automation_project_id - name = "resman-pf-0" + name = "prod-resman-pf-0" # naming: environment in description description = "Terraform project factory production service account." - prefix = local.prefixes.prod + prefix = var.prefix } module "branch-teams-prod-projectfactory-gcs" { source = "../../../modules/gcs" project_id = var.automation_project_id - name = "resman-pf-0" - prefix = local.prefixes.prod + name = "prod-resman-pf-0" + prefix = var.prefix versioning = true iam = { "roles/storage.objectAdmin" = [module.branch-teams-prod-projectfactory-sa.iam_email] diff --git a/fast/stages/01-resman/main.tf b/fast/stages/01-resman/main.tf index 2aedb7ce..9d12239e 100644 --- a/fast/stages/01-resman/main.tf +++ b/fast/stages/01-resman/main.tf @@ -27,9 +27,4 @@ locals { for k, v in local.groups : k => "group:${v}" } - # naming: environment names - prefixes = { - dev = "${var.prefix}-dev" - prod = "${var.prefix}-prod" - } } diff --git a/fast/stages/01-resman/variables.tf b/fast/stages/01-resman/variables.tf index 3570441e..93398a2e 100644 --- a/fast/stages/01-resman/variables.tf +++ b/fast/stages/01-resman/variables.tf @@ -80,8 +80,13 @@ variable "outputs_location" { variable "prefix" { # tfdoc:variable:source 00-bootstrap - description = "Prefix used for resources that need unique names." + description = "Prefix used for resources that need unique names. Use 9 characters or less." type = string + + validation { + condition = try(length(var.prefix), 0) < 10 + error_message = "Use a maximum of 9 characters for prefix." + } } variable "team_folders" { diff --git a/fast/stages/02-networking-nva/README.md b/fast/stages/02-networking-nva/README.md index 2ff9056f..014a0736 100644 --- a/fast/stages/02-networking-nva/README.md +++ b/fast/stages/02-networking-nva/README.md @@ -366,17 +366,17 @@ Don't forget to add a peering zone in the landing project and point it to the ne | [billing_account_id](variables.tf#L17) | Billing account id. | string | ✓ | | 00-bootstrap | | [folder_ids](variables.tf#L59) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | map(string) | ✓ | | 01-resman | | [organization](variables.tf#L91) | Organization details. | object({…}) | ✓ | | 00-bootstrap | -| [prefix](variables.tf#L107) | Prefix used for resources that need unique names. | string | ✓ | | 00-bootstrap | +| [prefix](variables.tf#L107) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | | [custom_adv](variables.tf#L23) | Custom advertisement definitions in name => range format. | map(string) | | {…} | | | [data_dir](variables.tf#L45) | Relative path for the folder storing configuration data for network resources. | string | | "data" | | | [dns](variables.tf#L51) | Onprem DNS resolvers | map(list(string)) | | {…} | | | [l7ilb_subnets](variables.tf#L65) | Subnets used for L7 ILBs. | map(list(object({…}))) | | {…} | | | [onprem_cidr](variables.tf#L83) | Onprem addresses in name => range format. | map(string) | | {…} | | | [outputs_location](variables.tf#L101) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | -| [project_factory_sa](variables.tf#L113) | IAM emails for project factory service accounts | map(string) | | {} | 01-resman | -| [psa_ranges](variables.tf#L120) | IP ranges used for Private Service Access (e.g. CloudSQL). | map(map(string)) | | {…} | | -| [router_configs](variables.tf#L139) | Configurations for CRs and onprem routers. | map(object({…})) | | {…} | | -| [vpn_onprem_configs](variables.tf#L162) | VPN gateway configuration for onprem interconnection. | map(object({…})) | | {…} | | +| [project_factory_sa](variables.tf#L118) | IAM emails for project factory service accounts | map(string) | | {} | 01-resman | +| [psa_ranges](variables.tf#L125) | IP ranges used for Private Service Access (e.g. CloudSQL). | map(map(string)) | | {…} | | +| [router_configs](variables.tf#L144) | Configurations for CRs and onprem routers. | map(object({…})) | | {…} | | +| [vpn_onprem_configs](variables.tf#L167) | VPN gateway configuration for onprem interconnection. | map(object({…})) | | {…} | | ## Outputs diff --git a/fast/stages/02-networking-nva/variables.tf b/fast/stages/02-networking-nva/variables.tf index 0659628d..8fca0ba7 100644 --- a/fast/stages/02-networking-nva/variables.tf +++ b/fast/stages/02-networking-nva/variables.tf @@ -106,8 +106,13 @@ variable "outputs_location" { variable "prefix" { # tfdoc:variable:source 00-bootstrap - description = "Prefix used for resources that need unique names." + description = "Prefix used for resources that need unique names. Use 9 characters or less." type = string + + validation { + condition = try(length(var.prefix), 0) < 10 + error_message = "Use a maximum of 9 characters for prefix." + } } variable "project_factory_sa" { diff --git a/fast/stages/02-networking-vpn/README.md b/fast/stages/02-networking-vpn/README.md index afab994a..4b96eba8 100644 --- a/fast/stages/02-networking-vpn/README.md +++ b/fast/stages/02-networking-vpn/README.md @@ -311,18 +311,18 @@ DNS configurations are centralised in the `dns.tf` file. Spokes delegate DNS res | [billing_account_id](variables.tf#L17) | Billing account id. | string | ✓ | | 00-bootstrap | | [folder_ids](variables.tf#L61) | Folders to be used for the networking resources in folders/nnnnnnnnnnn format. If null, folder will be created. | map(string) | ✓ | | 01-resman | | [organization](variables.tf#L85) | Organization details. | object({…}) | ✓ | | 00-bootstrap | -| [prefix](variables.tf#L101) | Prefix used for resources that need unique names. | string | ✓ | | 00-bootstrap | +| [prefix](variables.tf#L101) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | | [custom_adv](variables.tf#L23) | Custom advertisement definitions in name => range format. | map(string) | | {…} | | | [custom_roles](variables.tf#L40) | Custom roles defined at the org level, in key => id format. | map(string) | | {} | 00-bootstrap | | [data_dir](variables.tf#L47) | Relative path for the folder storing configuration data for network resources. | string | | "data" | | | [dns](variables.tf#L53) | Onprem DNS resolvers. | map(list(string)) | | {…} | | | [l7ilb_subnets](variables.tf#L67) | Subnets used for L7 ILBs. | map(list(object({…}))) | | {…} | | | [outputs_location](variables.tf#L95) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | string | | null | | -| [project_factory_sa](variables.tf#L107) | IAM emails for project factory service accounts. | map(string) | | {} | 01-resman | -| [psa_ranges](variables.tf#L114) | IP ranges used for Private Service Access (e.g. CloudSQL). | map(map(string)) | | {…} | | -| [router_configs](variables.tf#L129) | Configurations for CRs and onprem routers. | map(object({…})) | | {…} | | -| [vpn_onprem_configs](variables.tf#L153) | VPN gateway configuration for onprem interconnection. | map(object({…})) | | {…} | | -| [vpn_spoke_configs](variables.tf#L209) | VPN gateway configuration for spokes. | map(object({…})) | | {…} | | +| [project_factory_sa](variables.tf#L112) | IAM emails for project factory service accounts. | map(string) | | {} | 01-resman | +| [psa_ranges](variables.tf#L119) | IP ranges used for Private Service Access (e.g. CloudSQL). | map(map(string)) | | {…} | | +| [router_configs](variables.tf#L134) | Configurations for CRs and onprem routers. | map(object({…})) | | {…} | | +| [vpn_onprem_configs](variables.tf#L158) | VPN gateway configuration for onprem interconnection. | map(object({…})) | | {…} | | +| [vpn_spoke_configs](variables.tf#L214) | VPN gateway configuration for spokes. | map(object({…})) | | {…} | | ## Outputs diff --git a/fast/stages/02-networking-vpn/variables.tf b/fast/stages/02-networking-vpn/variables.tf index 3eb141e7..92c264fc 100644 --- a/fast/stages/02-networking-vpn/variables.tf +++ b/fast/stages/02-networking-vpn/variables.tf @@ -100,8 +100,13 @@ variable "outputs_location" { variable "prefix" { # tfdoc:variable:source 00-bootstrap - description = "Prefix used for resources that need unique names." + description = "Prefix used for resources that need unique names. Use 9 characters or less." type = string + + validation { + condition = try(length(var.prefix), 0) < 10 + error_message = "Use a maximum of 9 characters for prefix." + } } variable "project_factory_sa" { diff --git a/fast/stages/02-security/README.md b/fast/stages/02-security/README.md index 621db3e9..613b1c49 100644 --- a/fast/stages/02-security/README.md +++ b/fast/stages/02-security/README.md @@ -288,19 +288,19 @@ Some references that might be useful in setting up this stage: | [billing_account_id](variables.tf#L17) | Billing account id. | string | ✓ | | bootstrap | | [folder_id](variables.tf#L23) | Folder to be used for the networking resources in folders/nnnn format. | string | ✓ | | resman | | [organization](variables.tf#L73) | Organization details. | object({…}) | ✓ | | bootstrap | -| [prefix](variables.tf#L89) | Prefix used for resources that need unique names. | string | ✓ | | | +| [prefix](variables.tf#L89) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | | [groups](variables.tf#L29) | Group names to grant organization-level permissions. | map(string) | | {…} | bootstrap | | [kms_defaults](variables.tf#L44) | Defaults used for KMS keys. | object({…}) | | {…} | | | [kms_keys](variables.tf#L56) | KMS keys to create, keyed by name. Null attributes will be interpolated with defaults. | map(object({…})) | | {} | | | [kms_restricted_admins](variables.tf#L67) | Map of environment => [identities] who can assign the encrypt/decrypt roles on keys. | map(list(string)) | | {} | | | [outputs_location](variables.tf#L83) | Path where providers, tfvars files, and lists for the following stages are written. Leave empty to disable. | string | | null | | -| [vpc_sc_access_levels](variables.tf#L94) | VPC SC access level definitions. | map(object({…})) | | {} | | -| [vpc_sc_egress_policies](variables.tf#L109) | VPC SC egress policy defnitions. | map(object({…})) | | {} | | -| [vpc_sc_ingress_policies](variables.tf#L127) | VPC SC ingress policy defnitions. | map(object({…})) | | {} | | -| [vpc_sc_perimeter_access_levels](variables.tf#L147) | VPC SC perimeter access_levels. | object({…}) | | null | | -| [vpc_sc_perimeter_egress_policies](variables.tf#L157) | VPC SC egress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | -| [vpc_sc_perimeter_ingress_policies](variables.tf#L167) | VPC SC ingress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | -| [vpc_sc_perimeter_projects](variables.tf#L177) | VPC SC perimeter resources. | object({…}) | | null | | +| [vpc_sc_access_levels](variables.tf#L100) | VPC SC access level definitions. | map(object({…})) | | {} | | +| [vpc_sc_egress_policies](variables.tf#L115) | VPC SC egress policy defnitions. | map(object({…})) | | {} | | +| [vpc_sc_ingress_policies](variables.tf#L133) | VPC SC ingress policy defnitions. | map(object({…})) | | {} | | +| [vpc_sc_perimeter_access_levels](variables.tf#L153) | VPC SC perimeter access_levels. | object({…}) | | null | | +| [vpc_sc_perimeter_egress_policies](variables.tf#L163) | VPC SC egress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | +| [vpc_sc_perimeter_ingress_policies](variables.tf#L173) | VPC SC ingress policies per perimeter, values reference keys defined in the `vpc_sc_ingress_policies` variable. | object({…}) | | null | | +| [vpc_sc_perimeter_projects](variables.tf#L183) | VPC SC perimeter resources. | object({…}) | | null | | ## Outputs diff --git a/fast/stages/02-security/variables.tf b/fast/stages/02-security/variables.tf index 0829f098..00cbe4dc 100644 --- a/fast/stages/02-security/variables.tf +++ b/fast/stages/02-security/variables.tf @@ -87,8 +87,14 @@ variable "outputs_location" { } variable "prefix" { - description = "Prefix used for resources that need unique names." + # tfdoc:variable:source 00-bootstrap + description = "Prefix used for resources that need unique names. Use 9 characters or less." type = string + + validation { + condition = try(length(var.prefix), 0) < 10 + error_message = "Use a maximum of 9 characters for prefix." + } } variable "vpc_sc_access_levels" { diff --git a/fast/stages/03-project-factory/prod/README.md b/fast/stages/03-project-factory/prod/README.md index 7c2d3d68..c784342c 100644 --- a/fast/stages/03-project-factory/prod/README.md +++ b/fast/stages/03-project-factory/prod/README.md @@ -108,12 +108,12 @@ terraform apply | name | description | type | required | default | producer | |---|---|:---:|:---:|:---:|:---:| | [billing_account_id](variables.tf#L19) | Billing account id. | string | ✓ | | 00-bootstrap | -| [prefix](variables.tf#L44) | Prefix used for resources that need unique names. | string | ✓ | | 00-bootstrap | +| [prefix](variables.tf#L44) | Prefix used for resources that need unique names. Use 9 characters or less. | string | ✓ | | 00-bootstrap | | [data_dir](variables.tf#L25) | Relative path for the folder storing configuration data. | string | | "data/projects" | | | [defaults_file](variables.tf#L38) | Relative path for the file storing the project factory configuration. | string | | "data/defaults.yaml" | | | [environment_dns_zone](variables.tf#L31) | DNS zone suffix for environment. | string | | null | 02-networking | -| [shared_vpc_self_link](variables.tf#L50) | Self link for the shared VPC. | string | | null | 02-networking | -| [vpc_host_project](variables.tf#L57) | Host project for the shared VPC. | string | | null | 02-networking | +| [shared_vpc_self_link](variables.tf#L55) | Self link for the shared VPC. | string | | null | 02-networking | +| [vpc_host_project](variables.tf#L62) | Host project for the shared VPC. | string | | null | 02-networking | ## Outputs diff --git a/fast/stages/03-project-factory/prod/variables.tf b/fast/stages/03-project-factory/prod/variables.tf index 2e2b2c95..a580260c 100644 --- a/fast/stages/03-project-factory/prod/variables.tf +++ b/fast/stages/03-project-factory/prod/variables.tf @@ -43,8 +43,13 @@ variable "defaults_file" { variable "prefix" { # tfdoc:variable:source 00-bootstrap - description = "Prefix used for resources that need unique names." + description = "Prefix used for resources that need unique names. Use 9 characters or less." type = string + + validation { + condition = try(length(var.prefix), 0) < 10 + error_message = "Use a maximum of 9 characters for prefix." + } } variable "shared_vpc_self_link" { diff --git a/tools/check_names.py b/tools/check_names.py new file mode 100755 index 00000000..c487d693 --- /dev/null +++ b/tools/check_names.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +'Parse names from specific Terraform resources and optionally check length.' + +import collections +import enum +import logging +import pathlib +import re + +import click + + +BASEDIR = pathlib.Path(__file__).resolve().parents[1] +LOGGER = logging.getLogger() +MOD_TOKENS = [ + ('NAME', r'\s*module\s*"([^"]+)"\s*\{\s*'), + ('SOURCE', r'\s*source\s*=\s*"([^"]+)"\s*'), + ('VALUE', r'\s*name\s*=\s*"([^"]+)"\s*'), + ('REST', r'(.*)') +] +MOD = enum.Enum('MOD', ' '.join(name for name, _ in MOD_TOKENS)) +MOD_RE = re.compile('|'.join(f'(?:{pattern})' for _, pattern in MOD_TOKENS)) +MOD_LIMITS = { + 'project': 30, 'iam-service-account': 30, 'gcs': 63 +} + +Name = collections.namedtuple('Name', 'source name value length') + + +def get_names(dir_name): + dir_path = BASEDIR / dir_name + for tf_path in sorted(dir_path.glob('**/*.tf')): + if '.terraform' in str(tf_path): + continue + LOGGER.debug(f'file {tf_path}') + doc = tf_path.read_text() + name = source = None + for m in MOD_RE.finditer(doc): + token_type = MOD(m.lastindex) + if token_type == MOD.REST: + continue + value = m.group(m.lastindex).strip() + LOGGER.debug(f'{token_type}: {value}') + if token_type == MOD.NAME: + if name: + LOGGER.debug(f'module {name} already open ({value})') + name = value + source = None + elif token_type == MOD.SOURCE: + source = value.split('/')[-1] + LOGGER.debug(f'{name} {source}') + elif token_type == MOD.VALUE: + if name is None or source not in MOD_LIMITS: + continue + if '$' in value: + LOGGER.debug(f'interpolation in {name} ({value}), skipping') + else: + yield Name(source, name, value, len(value)) + name = source = None + + +@click.command() +@click.argument('dirs', type=str, nargs=-1) +@click.option('--prefix-length', default=7, type=int) +def main(dirs, prefix_length=None): + 'Parse names in dirs.' + import json + logging.basicConfig(level=logging.INFO) + names = [] + for dir_name in dirs: + for name in get_names(dir_name): + names.append(name) + names.sort() + source_just = max(len(k) for k in MOD_LIMITS) + name_just = max(len(n.name) for n in names) + value_just = max(len(n.value) for n in names) + for name in names: + name_length = name.length + prefix_length + flag = '✗' if name_length >= MOD_LIMITS[name.source] else '✓' + print(( + f'[{flag}] {name.source.ljust(source_just)} ' + f'{name.name.ljust(name_just)} ' + f'{name.value.ljust(value_just)} ' + f'({name_length})' + )) + + +if __name__ == '__main__': + main()