Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into pr-16
Browse files Browse the repository at this point in the history
# Conflicts:
#	locals.tf
#	main.tf
#	templates/common-variables.hcl.tf.tpl
#	templates/default-versions.hcl.tf.tpl
  • Loading branch information
Dave Arnold committed Apr 21, 2026
2 parents 6d39cfa + dcf8501 commit 809e9b7
Show file tree
Hide file tree
Showing 27 changed files with 1,964 additions and 21 deletions.
6 changes: 3 additions & 3 deletions clusters/csvd-dev-mcm/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ module "eks_deployment" {
vpc_domain_name = "dev.inf.csp1.census.gov"
vpc_name = "vpc3-inf-dev"
tags = {
Owner = "matthew.c.morgan@census.gov"
Environment = "development"
CostAllocation = "census:ocio:csvd"
Owner = "matthew.c.morgan@census.gov"
Environment = "development"
CostAllocation = "census:ocio:csvd"
}
organization = "census:ocio:csvd"
}
Expand Down
7 changes: 4 additions & 3 deletions defaults.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ locals {
# Dynamic AWS profile generation
aws_profile = "${var.cluster_config.account_name}-${var.cluster_config.environment_abbr}"

# Static template values (hidden from users)
# template_repo is null — all generated-repo content is managed via managed_extra_files.
# template-eks-cluster is a human reference only; it has no automation role.
repository_defaults = {
template = "template-eks-cluster"
template_owner = "SCT-Engineering"
template = null
template_owner = null
}

# Static EKS configuration for Karpenter bootstrap node group
Expand Down
134 changes: 134 additions & 0 deletions docs/adr/0001-generated-file-source-of-truth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# ADR 0001: All Generated Cluster Repository Files Must Be Versioned in terraform-eks-deployment

**Date:** 2026-04-20
**Status:** Proposed
**Deciders:** arnol377, morga471

---

## Context

The EKS Cluster Automation (ECA) system generates new EKS cluster repositories by running
`terraform apply` inside a CodeBuild project (`eks-terragrunt-repo-creator`). The build
checks out a pinned commit of `terraform-eks-deployment` (via `REPO_BRANCH` in `buildspec.yml`)
and applies it, which calls `CSVD/terraform-github-repo` to create the GitHub repo and
commit all generated files via `managed_extra_files`.

The files written into a generated cluster repo fall into two categories:

1. **Rendered config files**`_envcommon/default-versions.hcl`, `_envcommon/common-variables.hcl`,
`account.hcl`, `region.hcl`, `vpc.hcl`, `cluster.hcl` — rendered from Go templates
(`*.tf.tpl`) committed inside `terraform-eks-deployment/templates/`.

2. **Terragrunt module entrypoints**`eks/terragrunt.hcl`, `eks-config/terragrunt.hcl`,
`eks-dns/terragrunt.hcl`, and all other `eks-*/terragrunt.hcl` files — one per
Terragrunt module in the cluster's run-all graph.

Historically, the second category was provided by cloning `template-eks-cluster` as a
GitHub repo template. The template contained placeholder directory paths
(`environment/region/vpc/cluster/eks-*/`) that were supposed to be renamed to real computed
paths after clone. That renaming was never implemented, producing broken repos with literal
`environment/region/vpc/cluster` in all paths.

PR #16 (`test_cluster``main`) correctly eliminates the GitHub template feature
(`template_repo = null`) but proposes reading the `eks-*/terragrunt.hcl` files live from
`template-eks-cluster:main` at Terraform plan time via `data.github_repository_file`.

This ADR records the decision about where those files should live and why.

---

## Decision

We will commit all `eks-*/terragrunt.hcl` template files directly into
`terraform-eks-deployment/templates/eks-modules/` and write them into generated repos
via `managed_extra_files`, alongside the existing rendered config files.

The `template-eks-cluster` GitHub repo will no longer be used as a source of file content
in the automation path. The GitHub template feature (`template_repo`) will remain `null`.

---

## Alternatives Considered

### Option A: Read eks-module files live from `template-eks-cluster` at plan time (PR #16 approach)

`data.github_repository_file` datasources fetch each `eks-*/terragrunt.hcl` from
`template-eks-cluster:main` during `terraform plan`. They are passed into
`managed_extra_files` alongside the rendered config files.

**Rejected because:**

- **Internal consistency cannot be guaranteed.** The rendered config files
(`_envcommon/default-versions.hcl`, `_envcommon/common-variables.hcl`) are generated
from templates in `terraform-eks-deployment`. The eks-module files are fetched live from
a separate repo at a different, independently-advancing ref. A change to
`eks-karpenter/terragrunt.hcl` in `template-eks-cluster` that references a new variable
not yet present in `default-versions.hcl` will flow into new repos silently, producing
files that are internally inconsistent and will fail when terragrunt is run.

- **Partial updates are possible.** PR #16's drift-detection update mode only re-commits
files whose content changed. A template update that touches `eks-karpenter/terragrunt.hcl`
but not `default-versions.hcl` could produce a cluster repo where those two files are
at different effective versions.

- **Plan-time API coupling increases fragility.** Every `terraform plan` makes one GitHub
API call per eks-module file (currently 14 calls). If the GHE endpoint is slow or the
token lacks access, the plan fails regardless of whether the user intends to touch those
files.

- **`REPO_BRANCH` pinning is undermined.** CodeBuild pins `terraform-eks-deployment` to a
tested commit via `REPO_BRANCH`. This guarantees a known, reproducible set of Terraform
logic and defaults. Pulling supporting files from a separately-versioned repo at runtime
breaks that reproducibility guarantee — the effective artifact being applied is no longer
fully described by a single commit.

### Option B: Keep `template-eks-cluster` as a GitHub repo template (previous approach)

Use the GitHub template feature to seed new repos with `eks-*/terragrunt.hcl` files and
then rename the placeholder paths via a post-apply script.

**Rejected because:**

- Placeholder paths (`environment/region/vpc/cluster/`) land in the generated repo and
cannot be easily renamed after the fact via standard Terraform resources.
- Requires an out-of-band post-apply step (script or `null_resource`) that runs outside
Terraform's state model.
- The template repo still diverges from `terraform-eks-deployment` over time (same
consistency problem as Option A).

---

## Consequences

**Positive:**

- A single commit of `terraform-eks-deployment` fully describes all files that will be
written into a generated cluster repo. Pinning `REPO_BRANCH` in `buildspec.yml` is
sufficient to produce a fully reproducible, internally consistent artifact.
- When a new eks-module version or a new variable is added, a single PR to
`terraform-eks-deployment` updates both the `eks-*/terragrunt.hcl` template and the
corresponding `default-versions.hcl` template atomically. They cannot diverge.
- No live API calls at plan time for file content. Plan performance and reliability are
not affected by the availability of `template-eks-cluster`.
- The GitHub template feature (`template_repo`) is not used, removing a dependency on a
separately-maintained repo and on GitHub's template clone behavior.

**Negative:**

- `template-eks-cluster` and `terraform-eks-deployment/templates/eks-modules/` must be
kept manually in sync if humans use the template repo as a reference. Mitigation: add a
README to `template-eks-cluster` noting that it is no longer the automation source of
truth and pointing to `terraform-eks-deployment`.
- Adding a new eks-module requires a PR to `terraform-eks-deployment` rather than just
adding a directory to `template-eks-cluster`. This is the desired behavior — changes
go through review — but is a minor workflow difference.

**Neutral:**

- `template-eks-cluster` can be archived or retained as a human-readable reference. It
is not deleted because it may still be useful for onboarding documentation.
- The `data.github_repository_file` approach in PR #16 remains valid for a future
*update* workflow (deliberately syncing template changes into existing cluster repos),
as long as that workflow operates on the `templates/eks-modules/` copy in
`terraform-eks-deployment` rather than `template-eks-cluster:main`.
48 changes: 48 additions & 0 deletions examples/adsd-tools-dev/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
provider "aws" {
}

data "aws_secretsmanager_secret_version" "github_token" {
secret_id = "/eks-cluster-deployment/github_token"
}

provider "github" {
token = data.aws_secretsmanager_secret_version.github_token.secret_string
}

module "eks_deployment" {
source = "../../"

# Repository and cluster configuration - single name for both
name = "adsd-tools-dev"
environment = "prod"
region = "us-gov-east-1"

# Cluster configuration - simplified interface
cluster_config = {
account_name = "adsd-tools-nonprod-gov"
aws_account_id = "533109815932"
cluster_mailing_list = "adsd.enterprise.tools.support.branch.list@census.gov"
environment_abbr = "prod"
finops_project_name = "adsd_etdsb_tools_migration"
finops_project_number = "fs0000000069"
finops_project_role = "adsd_tools_mgrn_eks"
vpc_domain_name = "dev.adsd.csp1.census.gov"
vpc_name = "vpc3-inf-dev"
tags = {
Owner = "adsd.enterprise.tools.support.branch.list@census.gov"
Environment = "development"
CostCenter = "census:ocio:adsd"
}
organization = "census:ocio:adsd"
}
}

output "repository_url" {
description = "URL of the created GitHub repository"
value = module.eks_deployment.repository_url
}

output "ssh_clone_url" {
description = "SSH clone URL of the repository"
value = module.eks_deployment.ssh_clone_url
}
48 changes: 48 additions & 0 deletions examples/csvd-mcm-common/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
provider "aws" {
}

data "aws_secretsmanager_secret_version" "github_token" {
secret_id = "/eks-cluster-deployment/github_token"
}

provider "github" {
token = data.aws_secretsmanager_secret_version.github_token.secret_string
}

module "eks_deployment" {
source = "../../"

# Repository and cluster configuration - single name for both
name = "csvd-mcm-common"
environment = "prod"
region = "us-gov-east-1"

# Cluster configuration - simplified interface
cluster_config = {
account_name = "csvd-mcm-common"
aws_account_id = "220615867784"
cluster_mailing_list = "matthew.c.morgan@census.gov"
environment_abbr = "prod"
finops_project_name = "csvd_platformbaseline",
finops_project_number = "fs0000000078",
finops_project_role = "csvd_platformbaseline_app",
vpc_domain_name = "shared.inf.csp1.census.gov"
vpc_name = "vpc2-inf-shared"
tags = {
Owner = "matthew.c.morgan@census.gov"
Environment = "development"
CostCenter = "census:ocio:csvd"
}
organization = "census:ocio:csvd"
}
}

output "repository_url" {
description = "URL of the created GitHub repository"
value = module.eks_deployment.repository_url
}

output "ssh_clone_url" {
description = "SSH clone URL of the repository"
value = module.eks_deployment.ssh_clone_url
}
27 changes: 21 additions & 6 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ locals {
) : file.path => file.content
}

existing_managed_file_paths = !local.create_repository && local.update_source_branch != null ? toset([
existing_managed_file_paths = ! local.create_repository && local.update_source_branch != null ? toset([
for entry in data.github_tree.update_source_branch_tree[0].entries : entry.path
if entry.type == "blob"
]) : toset([])

managed_files_requiring_update = local.create_repository ? local.desired_managed_files_by_path : {
for path, content in local.desired_managed_files_by_path : path => content
if !contains(local.existing_managed_file_paths, path) || data.github_repository_file.existing_managed_files[path].content != content
if ! contains(local.existing_managed_file_paths, path) || data.github_repository_file.existing_managed_files[path].content != content
}

has_update_changes = length(local.managed_files_requiring_update) > 0
Expand All @@ -140,7 +140,7 @@ locals {
}

data "github_repository" "existing_repo" {
count = !local.create_repository ? 1 : 0
count = ! local.create_repository ? 1 : 0
full_name = "${var.organization}/${var.name}"
}

Expand All @@ -162,7 +162,7 @@ resource "terraform_data" "create_mode_guard" {

lifecycle {
precondition {
condition = !local.create_mode_repo_exists
condition = ! local.create_mode_repo_exists
error_message = "repository_mode=\"create\" is set but repository \"${var.name}\" already exists in ${var.organization}. Switch to repository_mode=\"update\"."
}
}
Expand All @@ -177,7 +177,7 @@ data "github_repository_file" "template_cluster_files" {
}

data "github_tree" "update_source_branch_tree" {
count = !local.create_repository && local.update_source_branch != null ? 1 : 0
count = ! local.create_repository && local.update_source_branch != null ? 1 : 0

repository = var.name
tree_sha = local.update_source_branch
Expand All @@ -189,7 +189,7 @@ data "github_tree" "update_source_branch_tree" {
}

data "github_repository_file" "existing_managed_files" {
for_each = !local.create_repository ? {
for_each = ! local.create_repository ? {
for path, content in local.desired_managed_files_by_path : path => content
if contains(local.existing_managed_file_paths, path)
} : {}
Expand All @@ -199,6 +199,21 @@ data "github_repository_file" "existing_managed_files" {
file = each.key
}

locals {
# Base path prefix for all eks-module files in the generated repo
eks_module_cluster_prefix = "${var.environment}/${var.region}/${var.cluster_config.vpc_name}/${var.name}"

# Auto-discover all files in templates/eks-modules/ and map them to their
# target paths in the generated repo. The naming convention converts
# "eks-karpenter.terragrunt.hcl" → "eks-karpenter/terragrunt.hcl" by
# splitting on the first dot.
eks_module_files = {
for fname in fileset("${path.module}/templates/eks-modules", "*") :
"${local.eks_module_cluster_prefix}/${join("/", regex("^([^.]+)\\.(.+)$", fname))}" =>
file("${path.module}/templates/eks-modules/${fname}")
}
}

module "github_repo" {
source = "../terraform-github-repo"

Expand Down
Loading

0 comments on commit 809e9b7

Please sign in to comment.