Repository: chanzuckerberg/fogg
Pull request #873 (2023-06-02 13:16:07)

feat: Fogg template for k8s
To generate a k8s template, configure `kubernetes` provider like this (you need to specify the `cluster_name`):

```yaml
providers:
  kubernetes:
    enabled: true
    cluster_name: eks-v2
    version: 2.19.0
```


Patch:
diff --git a/config/v2/config.go b/config/v2/config.go
index e7047bef..7de59601 100644
--- a/config/v2/config.go
+++ b/config/v2/config.go
@@ -253,7 +253,8 @@ type TfeProvider struct {
 }
 
 type KubernetesProvider struct {
-	CommonProvider `yaml:",inline"`
+	CommonProvider       `yaml:",inline"`
+	ClusterComponentName *string `yaml:"cluster_component_name,omitempty"`
 }
 
 type HelmProvider struct {
diff --git a/config/v2/resolvers.go b/config/v2/resolvers.go
index 9fd238dc..e754c960 100644
--- a/config/v2/resolvers.go
+++ b/config/v2/resolvers.go
@@ -586,6 +586,7 @@ func ResolveKubernetesProvider(commons ...Common) *KubernetesProvider {
 			p.CustomProvider = defaultEnabled(false)
 		}
 	}
+	clusterComponentName := lastNonNil(KubernetesProviderClusterComponentNameGetter, commons...)
 	var version *string
 	var enabled *bool
 
@@ -605,6 +606,7 @@ func ResolveKubernetesProvider(commons ...Common) *KubernetesProvider {
 
 	if version != nil {
 		return &KubernetesProvider{
+			ClusterComponentName: clusterComponentName,
 			CommonProvider: CommonProvider{
 				CustomProvider: lastNonNilBool(KubernetesProviderCustomProviderGetter, commons...),
 				Enabled:        enabled,
@@ -1238,3 +1240,10 @@ func DependsOnComponentsGetter(comm Common) []string {
 	}
 	return comm.DependsOn.Components
 }
+
+func KubernetesProviderClusterComponentNameGetter(comm Common) *string {
+	if comm.Providers == nil || comm.Providers.Kubernetes == nil {
+		return nil
+	}
+	return comm.Providers.Kubernetes.ClusterComponentName
+}
diff --git a/plan/plan.go b/plan/plan.go
index 35f537b7..c914bbec 100644
--- a/plan/plan.go
+++ b/plan/plan.go
@@ -272,7 +272,8 @@ type TfeProvider struct {
 }
 
 type KubernetesProvider struct {
-	CommonProvider `yaml:",inline"`
+	CommonProvider       `yaml:",inline"`
+	ClusterComponentName *string `yaml:"cluster_component_name,omitempty"`
 }
 
 type HelmProvider struct {
@@ -1078,6 +1079,7 @@ func resolveComponentCommon(commons ...v2.Common) ComponentCommon {
 			version = *k8sConfig.Version
 		}
 		k8sPlan = &KubernetesProvider{
+			ClusterComponentName: k8sConfig.ClusterComponentName,
 			CommonProvider: CommonProvider{
 				Version:        version,
 				Enabled:        k8sConfig.Enabled == nil || (k8sConfig.Enabled != nil && *k8sConfig.Enabled),
diff --git a/templates/templates/common/kubernetes_provider.tmpl b/templates/templates/common/kubernetes_provider.tmpl
new file mode 100644
index 00000000..ddd27f0e
--- /dev/null
+++ b/templates/templates/common/kubernetes_provider.tmpl
@@ -0,0 +1,16 @@
+{{ define "kubernetes_provider" -}}
+{{ if .ClusterComponentName -}}
+  data "aws_eks_cluster" "cluster" {
+    name = data.terraform_remote_state.{{ .ClusterComponentName }}.outputs.cluster_id
+  }
+
+  data "aws_eks_cluster_auth" "cluster" {
+    name = data.terraform_remote_state.{{ .ClusterComponentName }}.outputs.cluster_id
+  }
+
+provider "kubernetes" {
+  host                   = data.aws_eks_cluster.cluster.endpoint
+  cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
+  token                  = data.aws_eks_cluster_auth.cluster.token
+}
+{{ end }}{{ end }}
diff --git a/templates/templates/component/terraform/fogg.tf.tmpl b/templates/templates/component/terraform/fogg.tf.tmpl
index 40dac9e5..520343f5 100644
--- a/templates/templates/component/terraform/fogg.tf.tmpl
+++ b/templates/templates/component/terraform/fogg.tf.tmpl
@@ -50,6 +50,10 @@
   {{ template "auth0_provider" .ProviderConfiguration.Auth0 }}
 {{ end }}{{ end }}
 
+{{- if .ProviderConfiguration.Kubernetes -}}{{- if not .ProviderConfiguration.Kubernetes.CustomProvider -}}
+  {{- template "kubernetes_provider" .ProviderConfiguration.Kubernetes -}}
+{{- end -}}{{- end -}}
+
 terraform {
   required_version = "={{ .TerraformVersion }}"
 


Test patch:
diff --git a/plan/plan_test.go b/plan/plan_test.go
index 8b5b2375..038d14ea 100644
--- a/plan/plan_test.go
+++ b/plan/plan_test.go
@@ -84,10 +84,14 @@ func TestPlanBasicV2Yaml(t *testing.T) {
 	r.NotNil(plan.Envs["staging"])
 
 	r.NotNil(plan.Envs["staging"].Components)
-	r.Len(plan.Envs["staging"].Components, 3)
+	r.Len(plan.Envs["staging"].Components, 4)
 
 	r.NotNil(plan.Envs["staging"])
 	r.NotNil(plan.Envs["staging"].Components["vpc"])
+	r.NotNil(plan.Envs["staging"].Components["k8s-comp"])
+	r.NotNil(plan.Envs["staging"].Components["k8s-comp"].ProviderConfiguration.Kubernetes)
+	r.NotNil(plan.Envs["staging"].Components["k8s-comp"].ProviderConfiguration.Kubernetes.ClusterComponentName)
+
 	logrus.Debugf("%#v\n", plan.Envs["staging"].Components["vpc"].ModuleSource)
 	r.NotNil(*plan.Envs["staging"].Components["vpc"].ModuleSource)
 	r.Equal("github.com/terraform-aws-modules/terraform-aws-vpc?ref=v1.30.0", *plan.Envs["staging"].Components["vpc"].ModuleSource)
diff --git a/testdata/v2_full_yaml/fogg.yml b/testdata/v2_full_yaml/fogg.yml
index 13ef28fb..811f00e4 100644
--- a/testdata/v2_full_yaml/fogg.yml
+++ b/testdata/v2_full_yaml/fogg.yml
@@ -115,6 +115,12 @@ envs:
         extra_vars:
           foo: bar3
         module_source: github.com/terraform-aws-modules/terraform-aws-vpc?ref=v1.30.0
+      k8s-comp:
+        providers:
+          kubernetes:
+            enabled: true
+            cluster_component_name: comp1
+            version: 2.19.0
     extra_vars:
       foo: bar2
 modules:
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/Makefile b/testdata/v2_full_yaml/terraform/envs/staging/Makefile
index 9fb1403e..0d933078 100644
--- a/testdata/v2_full_yaml/terraform/envs/staging/Makefile
+++ b/testdata/v2_full_yaml/terraform/envs/staging/Makefile
@@ -1,7 +1,7 @@
 # Auto-generated by fogg. Do not edit
 # Make improvements in fogg, so that everyone can benefit.
 
-COMPONENTS=comp1 comp2 vpc
+COMPONENTS=comp1 comp2 k8s-comp vpc
 
 all:
 .PHONY: all
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/comp1/fogg.tf b/testdata/v2_full_yaml/terraform/envs/staging/comp1/fogg.tf
index 4b7cfdad..7a6e287d 100644
--- a/testdata/v2_full_yaml/terraform/envs/staging/comp1/fogg.tf
+++ b/testdata/v2_full_yaml/terraform/envs/staging/comp1/fogg.tf
@@ -157,6 +157,19 @@ data "terraform_remote_state" "comp2" {
 
   }
 }
+data "terraform_remote_state" "k8s-comp" {
+  backend = "remote"
+  config = {
+
+
+    hostname     = "example.com"
+    organization = "foo"
+    workspaces = {
+      name = "staging-k8s-comp"
+    }
+
+  }
+}
 data "terraform_remote_state" "vpc" {
   backend = "remote"
   config = {
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/comp1/terragrunt.hcl b/testdata/v2_full_yaml/terraform/envs/staging/comp1/terragrunt.hcl
index 0f9b6c69..97a8d0c1 100644
--- a/testdata/v2_full_yaml/terraform/envs/staging/comp1/terragrunt.hcl
+++ b/testdata/v2_full_yaml/terraform/envs/staging/comp1/terragrunt.hcl
@@ -1,6 +1,7 @@
 dependencies {
   paths = [
     "../comp2",
+    "../k8s-comp",
     "../vpc",
     "../../../accounts/bar",
     "../../../accounts/foo",
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/comp2/fogg.tf b/testdata/v2_full_yaml/terraform/envs/staging/comp2/fogg.tf
index 1e997ad8..40bdc0c7 100644
--- a/testdata/v2_full_yaml/terraform/envs/staging/comp2/fogg.tf
+++ b/testdata/v2_full_yaml/terraform/envs/staging/comp2/fogg.tf
@@ -157,6 +157,19 @@ data "terraform_remote_state" "comp1" {
 
   }
 }
+data "terraform_remote_state" "k8s-comp" {
+  backend = "remote"
+  config = {
+
+
+    hostname     = "example.com"
+    organization = "foo"
+    workspaces = {
+      name = "staging-k8s-comp"
+    }
+
+  }
+}
 data "terraform_remote_state" "vpc" {
   backend = "remote"
   config = {
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/comp2/terragrunt.hcl b/testdata/v2_full_yaml/terraform/envs/staging/comp2/terragrunt.hcl
index c81d46bf..ff1e6d1e 100644
--- a/testdata/v2_full_yaml/terraform/envs/staging/comp2/terragrunt.hcl
+++ b/testdata/v2_full_yaml/terraform/envs/staging/comp2/terragrunt.hcl
@@ -1,6 +1,7 @@
 dependencies {
   paths = [
     "../comp1",
+    "../k8s-comp",
     "../vpc",
     "../../../accounts/bar",
     "../../../accounts/foo",
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/Makefile b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/Makefile
new file mode 100644
index 00000000..f56d5ab2
--- /dev/null
+++ b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/Makefile
@@ -0,0 +1,16 @@
+# Auto-generated by fogg. Do not edit
+# Make improvements in fogg, so that everyone can benefit.
+
+
+export TERRAFORM_VERSION := 0.100.0
+export TFLINT_ENABLED := 0
+export TF_PLUGIN_CACHE_DIR := ../../../..//.terraform.d/plugin-cache
+export TF_BACKEND_KIND := remote
+
+include ../../../..//scripts/component.mk
+
+
+help: ## display help for this makefile
+	@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+.PHONY: help
+
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/README.md b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/README.md
new file mode 100644
index 00000000..e69de29b
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/fogg.tf b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/fogg.tf
new file mode 100644
index 00000000..1a1f5b7e
--- /dev/null
+++ b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/fogg.tf
@@ -0,0 +1,242 @@
+# Auto-generated by fogg. Do not edit
+# Make improvements in fogg, so that everyone can benefit.
+provider "aws" {
+
+  region  = "us-west-2"
+  profile = "profile"
+
+  allowed_account_ids = ["00456"]
+}
+# Aliased Providers (for doing things in every region).
+
+
+provider "assert" {}
+data "aws_eks_cluster" "cluster" {
+  name = data.terraform_remote_state.comp1.outputs.cluster_id
+}
+data "aws_eks_cluster_auth" "cluster" {
+  name = data.terraform_remote_state.comp1.outputs.cluster_id
+}
+provider "kubernetes" {
+  host                   = data.aws_eks_cluster.cluster.endpoint
+  cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
+  token                  = data.aws_eks_cluster_auth.cluster.token
+}
+terraform {
+  required_version = "=0.100.0"
+
+  backend "remote" {
+
+    hostname     = "example.com"
+    organization = "foo"
+    workspaces {
+      name = "staging-k8s-comp"
+    }
+
+  }
+  required_providers {
+
+    archive = {
+      source = "hashicorp/archive"
+
+      version = "~> 2.0"
+
+    }
+
+    assert = {
+      source = "bwoznicki/assert"
+
+      version = "0.0.1"
+
+    }
+
+    aws = {
+      source = "hashicorp/aws"
+
+      version = "0.12.0"
+
+    }
+
+    kubernetes = {
+      source = "hashicorp/kubernetes"
+
+      version = "2.19.0"
+
+    }
+
+    local = {
+      source = "hashicorp/local"
+
+      version = "~> 2.0"
+
+    }
+
+    null = {
+      source = "hashicorp/null"
+
+      version = "3.1.1"
+
+    }
+
+    okta-head = {
+      source = "okta/okta"
+
+      version = "~> 3.30"
+
+    }
+
+    random = {
+      source = "hashicorp/random"
+
+      version = "~> 3.4"
+
+    }
+
+    tls = {
+      source = "hashicorp/tls"
+
+      version = "~> 3.0"
+
+    }
+
+  }
+}
+# tflint-ignore: terraform_unused_declarations
+variable "env" {
+  type    = string
+  default = "staging"
+}
+# tflint-ignore: terraform_unused_declarations
+variable "project" {
+  type    = string
+  default = "proj"
+}
+# tflint-ignore: terraform_unused_declarations
+variable "region" {
+  type    = string
+  default = "us-west-2"
+}
+# tflint-ignore: terraform_unused_declarations
+variable "component" {
+  type    = string
+  default = "k8s-comp"
+}
+# tflint-ignore: terraform_unused_declarations
+variable "aws_profile" {
+  type    = string
+  default = "profile"
+}
+# tflint-ignore: terraform_unused_declarations
+variable "owner" {
+  type    = string
+  default = "foo@example.com"
+}
+# tflint-ignore: terraform_unused_declarations
+variable "tags" {
+  type = object({ project : string, env : string, service : string, owner : string, managedBy : string })
+  default = {
+    project   = "proj"
+    env       = "staging"
+    service   = "k8s-comp"
+    owner     = "foo@example.com"
+    managedBy = "terraform"
+  }
+}
+# tflint-ignore: terraform_unused_declarations
+variable "foo" {
+  type    = string
+  default = "bar2"
+}
+# tflint-ignore: terraform_unused_declarations
+data "terraform_remote_state" "global" {
+  backend = "s3"
+  config = {
+
+
+    bucket = "buck"
+
+    key     = "terraform/proj/global.tfstate"
+    region  = "us-west-2"
+    profile = "profile"
+
+
+  }
+}
+data "terraform_remote_state" "comp1" {
+  backend = "remote"
+  config = {
+
+
+    hostname     = "example.com"
+    organization = "foo"
+    workspaces = {
+      name = "staging-comp1"
+    }
+
+  }
+}
+data "terraform_remote_state" "comp2" {
+  backend = "remote"
+  config = {
+
+
+    hostname     = "example.com"
+    organization = "foo"
+    workspaces = {
+      name = "staging-comp2"
+    }
+
+  }
+}
+data "terraform_remote_state" "vpc" {
+  backend = "remote"
+  config = {
+
+
+    hostname     = "example.com"
+    organization = "foo"
+    workspaces = {
+      name = "staging-vpc"
+    }
+
+  }
+}
+data "terraform_remote_state" "bar" {
+  backend = "s3"
+  config = {
+
+
+    bucket = "buck"
+
+    key     = "terraform/proj/accounts/bar.tfstate"
+    region  = "us-west-2"
+    profile = "profile"
+
+
+  }
+}
+data "terraform_remote_state" "foo" {
+  backend = "s3"
+  config = {
+
+
+    bucket = "buck"
+
+    key     = "terraform/proj/accounts/foo.tfstate"
+    region  = "us-west-2"
+    profile = "profile"
+
+
+  }
+}
+# tflint-ignore: terraform_unused_declarations
+variable "aws_accounts" {
+  type = map(string)
+  default = {
+
+    bar = "00456"
+
+    foo = "123"
+
+  }
+}
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/main.tf b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/main.tf
new file mode 100644
index 00000000..e69de29b
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/outputs.tf b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/outputs.tf
new file mode 100644
index 00000000..e69de29b
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/terraform.d b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/terraform.d
new file mode 120000
index 00000000..b482d75b
--- /dev/null
+++ b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/terraform.d
@@ -0,0 +1,1 @@
+../../../../terraform.d
\ No newline at end of file
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/terragrunt.hcl b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/terragrunt.hcl
new file mode 100644
index 00000000..686d07e5
--- /dev/null
+++ b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/terragrunt.hcl
@@ -0,0 +1,9 @@
+dependencies {
+  paths = [
+    "../comp1",
+    "../comp2",
+    "../vpc",
+    "../../../accounts/bar",
+    "../../../accounts/foo",
+  ]
+}
\ No newline at end of file
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/variables.tf b/testdata/v2_full_yaml/terraform/envs/staging/k8s-comp/variables.tf
new file mode 100644
index 00000000..e69de29b
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/vpc/fogg.tf b/testdata/v2_full_yaml/terraform/envs/staging/vpc/fogg.tf
index 30d5ad0f..bdf1c6ee 100644
--- a/testdata/v2_full_yaml/terraform/envs/staging/vpc/fogg.tf
+++ b/testdata/v2_full_yaml/terraform/envs/staging/vpc/fogg.tf
@@ -170,6 +170,19 @@ data "terraform_remote_state" "comp2" {
 
   }
 }
+data "terraform_remote_state" "k8s-comp" {
+  backend = "remote"
+  config = {
+
+
+    hostname     = "example.com"
+    organization = "foo"
+    workspaces = {
+      name = "staging-k8s-comp"
+    }
+
+  }
+}
 data "terraform_remote_state" "bar" {
   backend = "s3"
   config = {
diff --git a/testdata/v2_full_yaml/terraform/envs/staging/vpc/terragrunt.hcl b/testdata/v2_full_yaml/terraform/envs/staging/vpc/terragrunt.hcl
index 34d2fa2a..9227cf86 100644
--- a/testdata/v2_full_yaml/terraform/envs/staging/vpc/terragrunt.hcl
+++ b/testdata/v2_full_yaml/terraform/envs/staging/vpc/terragrunt.hcl
@@ -2,6 +2,7 @@ dependencies {
   paths = [
     "../comp1",
     "../comp2",
+    "../k8s-comp",
     "../../../accounts/bar",
     "../../../accounts/foo",
   ]