Skip to main content

Terraform Infrastructure

Terraform lives in orphaned-wells-ui-server/deployment/terraform.

It manages the current GKE deployment infrastructure, upload buckets, DNS, and deployment target outputs. Legacy VM definitions remain in Terraform for future re-enablement, but Terraform manages legacy VM modules only for names listed in enabled_legacy_backend_vms.

What Terraform manages

  • Shared GKE Autopilot cluster.
  • One Cloud Storage upload bucket per unique GKE backend bucket name.
  • One global static IP per backend collaborator for Kubernetes Ingress.
  • Optional <collaborator>-k8s-server.uow-carbon.org test DNS records.
  • Primary backend DNS records, such as staging-server.uow-carbon.org, pointing to the GKE static IP.
  • kubernetes_deploy_targets, the output consumed by backend GitHub Actions.
  • Legacy Compute Engine VM resources only for names listed in enabled_legacy_backend_vms.
caution

Add a collaborator to gke_backends or gke_backend_overrides for GKE-only infrastructure. Add a collaborator to legacy_backend_vms only when you need to preserve a reusable VM definition, and add it to enabled_legacy_backend_vms only when Terraform should actively manage that VM.

Prerequisites

  • Terraform 1.x.
  • Google Cloud SDK.
  • jq for output export and state verification commands.
  • GitHub CLI gh for updating GitHub Actions secrets from the command line.
  • Access to the target GCP project.
  • Access to the shared Terraform state bucket: gs://tidy-outlet-412020-ogrre-terraform-state.
  • A local terraform.tfvars file only when you need uncommitted local overrides.

Shared non-secret defaults live in variables.tf. Add long-lived public collaborators to the gke_backends map there so the repo remains the source of truth.

Example terraform.tfvars override for local testing:

gke_backend_overrides = {
"boots" = {}
}

*.tfvars and .env files are local operational files and should not be committed. Terraform state is stored remotely in GCS; do not commit local state backups or state migration files.

Authenticate

cd orphaned-wells-ui-server/deployment/terraform

gcloud auth login
gcloud config set project <PROJECT_ID>
gcloud auth application-default login

Plan and apply

terraform init
terraform workspace select ogrre
terraform workspace show
terraform plan
terraform apply

To exclude GKE resources from a plan:

terraform plan -var='enable_gke=false'

Export GKE deployment targets

After apply, export the Kubernetes deployment target map and store it as the backend repository secret. The gh command requires a GitHub account with permission to edit repository Actions secrets:

terraform workspace select ogrre
gh auth login
gh secret set K8S_DEPLOY_TARGETS \
--repo CATALOG-Historic-Records/orphaned-wells-ui-server \
--body "$(terraform output -json kubernetes_deploy_targets | jq -c .)"

Re-export it any time Terraform changes hostnames, static IP names, namespaces, upload bucket names, resource requests, or cluster metadata.

Upload buckets

Each GKE backend gets a Cloud Storage upload bucket. The default bucket name is <collaborator>_uploads; use upload_bucket_name only for existing exceptions or explicit custom names. Staging uses uploaded_documents_v0.

Terraform keys bucket resources by bucket name, so collaborators can intentionally share a bucket without creating duplicate resources. Buckets use force_destroy=false and prevent_destroy=true to protect uploaded files.

Legacy Compute Engine VMs

Legacy VM definitions are kept in legacy_backend_vms so they can be re-enabled later without reconstructing their machine, disk, image, or zone settings. They are disabled by default because enabled_legacy_backend_vms defaults to an empty set.

To re-enable a legacy VM, add its name to enabled_legacy_backend_vms:

enabled_legacy_backend_vms = ["isgs"]

To disable it again without deleting the definition, remove the name from enabled_legacy_backend_vms. If Terraform state still contains old module resources and you want Terraform to stop managing them rather than destroy them, remove only those bindings from state with terraform state rm.

Workspaces and state

This Terraform setup uses a shared GCS backend configured in backend.tf:

gs://tidy-outlet-412020-ogrre-terraform-state/orphaned-wells-ui-server

The backend bucket is bootstrap infrastructure. It is configured by backend.tf and created or updated out-of-band with scripts/bootstrap_terraform_state_bucket.sh; it is not itself a Terraform-managed resource in this root module. The bucket should have uniform bucket-level access, public access prevention, and object versioning enabled.

Use the shared ogrre workspace for normal infrastructure work:

terraform init
terraform workspace select ogrre
terraform workspace show
terraform plan

If this is your first time using the backend, confirm the remote workspace is visible:

terraform workspace list

You can also verify that Terraform is reading remote state:

terraform state pull > /private/tmp/ogrre-remote.tfstate
jq -r '.resources | length' /private/tmp/ogrre-remote.tfstate
gcloud storage ls -r gs://tidy-outlet-412020-ogrre-terraform-state/orphaned-wells-ui-server
caution

Treat the shared remote state as production infrastructure metadata. Do not run terraform state push, terraform state rm, terraform state mv, terraform import, terraform workspace new, or terraform workspace delete against the shared backend unless you are intentionally doing state maintenance.

warning

If terraform init asks whether to migrate all local workspaces to gcs, do not answer yes unless you intentionally want to overwrite or copy every local workspace into the shared backend. For selective migration, back up the local state and push only the known-good state file.

Workspaces are still available with the GCS backend, but use a separate workspace only when you intentionally want an isolated remote state:

terraform workspace new <workspace_name>
terraform workspace select <workspace_name>

Do not use ad hoc workspaces for shared collaborator infrastructure. A plan from an empty or incorrect workspace may propose recreating existing cloud resources.

State recovery and imports

Imports are normally unnecessary now that the shared ogrre state is remote. If you are recovering or bootstrapping a state file, use the backend repository import scripts and review the summary before applying:

bash scripts/import_existing_infrastructure.sh --target-workspace ogrre --dry-run
bash scripts/import_existing_infrastructure.sh --target-workspace ogrre

The comprehensive importer reads this repo's Terraform naming conventions and attempts to import the configured firewalls, GKE resources, upload buckets, DNS records, static IPs, and enabled legacy VM resources. Missing resources are reported and do not stop the script unless --strict is passed.

Primary DNS ownership

Primary backend DNS records are managed by root-level GKE resources:

google_dns_record_set.gke_backend_primary["<collaborator>"]

Legacy VM modules can still manage VMs and VM IPs, but they do not create the primary backend DNS record for a collaborator whose GKE backend has create_primary_dns_record=true. Existing DNS records were moved into the GKE resource addresses with Terraform moved blocks, so a normal plan should not propose duplicate DNS records for existing <collaborator>-server.uow-carbon.org names.

Targeted plans

Use -target only for isolated Terraform work:

terraform plan -target='module.backend_vms["staging"]'
terraform apply -target='module.backend_vms["staging"]'

Targeting bypasses part of Terraform's normal dependency planning, so use a full plan afterward when possible.