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()