From 16af8bccda2e4e0a0db95a1fb60ab762aa93acb1 Mon Sep 17 00:00:00 2001
From: Jessica Yuen <im.jessicayuen@gmail.com>
Date: Tue, 24 Oct 2017 12:24:11 -0700
Subject: [PATCH] Generate environment param file

This commit will generate the `environments/<env>/params.libsonnet` file
on `env add <env>`.

The purpose of this file is to allow users to define custom parameters
on an environment-to-environment basis. It is meant to allow for
"overrides" to component params.
---
 metadata/environment.go      | 96 ++++++++++++++++++++++--------------
 metadata/environment_test.go | 21 ++++++++
 2 files changed, 80 insertions(+), 37 deletions(-)

diff --git a/metadata/environment.go b/metadata/environment.go
index 38f9f91b..2bf4b6fd 100644
--- a/metadata/environment.go
+++ b/metadata/environment.go
@@ -38,6 +38,7 @@ const (
 	schemaFilename        = "swagger.json"
 	extensionsLibFilename = "k.libsonnet"
 	k8sLibFilename        = "k8s.libsonnet"
+	paramsFileName        = "params.libsonnet"
 	specFilename          = "spec.json"
 )
 
@@ -100,51 +101,58 @@ func (m *manager) createEnvironment(name, server, namespace string, extensionsLi
 
 	log.Infof("Generating environment metadata at path '%s'", envPath)
 
-	// Generate the schema file.
-	log.Debugf("Generating '%s', length: %d", schemaFilename, len(specData))
-	schemaPath := appendToAbsPath(metadataPath, schemaFilename)
-	err = afero.WriteFile(m.appFS, string(schemaPath), specData, defaultFilePermissions)
-	if err != nil {
-		log.Debugf("Failed to write '%s'", schemaFilename)
-		return err
-	}
-
-	log.Debugf("Generating '%s', length: %d", k8sLibFilename, len(k8sLibData))
-	k8sLibPath := appendToAbsPath(metadataPath, k8sLibFilename)
-	err = afero.WriteFile(m.appFS, string(k8sLibPath), k8sLibData, defaultFilePermissions)
-	if err != nil {
-		log.Debugf("Failed to write '%s'", k8sLibFilename)
-		return err
-	}
-
-	log.Debugf("Generating '%s', length: %d", extensionsLibFilename, len(extensionsLibData))
-	extensionsLibPath := appendToAbsPath(metadataPath, extensionsLibFilename)
-	err = afero.WriteFile(m.appFS, string(extensionsLibPath), extensionsLibData, defaultFilePermissions)
+	// Generate the environment spec file.
+	envSpecData, err := generateSpecData(server, namespace)
 	if err != nil {
-		log.Debugf("Failed to write '%s'", extensionsLibFilename)
 		return err
 	}
 
-	// Generate the environment .jsonnet file
-	overrideFileName := path.Base(name) + ".jsonnet"
-	overrideData := m.generateOverrideData()
-	log.Debugf("Generating '%s', length: %d", overrideFileName, len(overrideData))
-	overrideLibPath := appendToAbsPath(envPath, overrideFileName)
-	err = afero.WriteFile(m.appFS, string(overrideLibPath), overrideData, defaultFilePermissions)
-	if err != nil {
-		log.Debugf("Failed to write '%s'", overrideFileName)
-		return err
+	metadata := []struct {
+		path AbsPath
+		data []byte
+	}{
+		{
+			// schema file
+			appendToAbsPath(metadataPath, schemaFilename),
+			specData,
+		},
+		{
+			// k8s file
+			appendToAbsPath(metadataPath, k8sLibFilename),
+			k8sLibData,
+		},
+		{
+			// extensions file
+			appendToAbsPath(metadataPath, extensionsLibFilename),
+			extensionsLibData,
+		},
+		{
+			// environment base override file
+			appendToAbsPath(envPath, path.Base(name)+".jsonnet"),
+			m.generateOverrideData(),
+		},
+		{
+			// params file
+			appendToAbsPath(envPath, paramsFileName),
+			m.generateParamsData(),
+		},
+		{
+			// spec file
+			appendToAbsPath(envPath, specFilename),
+			envSpecData,
+		},
 	}
 
-	// Generate the environment spec file.
-	envSpecData, err := generateSpecData(server, namespace)
-	if err != nil {
-		return err
+	for _, a := range metadata {
+		fileName := path.Base(string(a.path))
+		log.Debugf("Generating '%s', length: %d", fileName, len(a.data))
+		if err = afero.WriteFile(m.appFS, string(a.path), a.data, defaultFilePermissions); err != nil {
+			log.Debugf("Failed to write '%s'", fileName)
+			return err
+		}
 	}
 
-	log.Debugf("Generating '%s', length: %d", specFilename, len(envSpecData))
-	envSpecPath := appendToAbsPath(envPath, specFilename)
-	return afero.WriteFile(m.appFS, string(envSpecPath), envSpecData, defaultFilePermissions)
+	return nil
 }
 
 func (m *manager) DeleteEnvironment(name string) error {
@@ -369,6 +377,20 @@ func (m *manager) generateOverrideData() []byte {
 	return buf.Bytes()
 }
 
+func (m *manager) generateParamsData() []byte {
+	return []byte(`local params = import "` + m.componentParamsPath + `";
+params + {
+  components +: {
+    // Insert component parameter overrides here. Ex:
+    // guestbook +: {
+    //   name: "guestbook-dev",
+    //   replicas: params.global.replicas,
+    // },
+  },
+}
+`)
+}
+
 func generateSpecData(server, namespace string) ([]byte, error) {
 	// Format the spec json and return; preface keys with 2 space idents.
 	return json.MarshalIndent(EnvironmentSpec{Server: server, Namespace: namespace}, "", "  ")
diff --git a/metadata/environment_test.go b/metadata/environment_test.go
index 788a8351..1ea73ed2 100644
--- a/metadata/environment_test.go
+++ b/metadata/environment_test.go
@@ -203,3 +203,24 @@ base + {
 		t.Fatalf("Expected to generate override file with data:\n%s\n,got:\n%s", expected, result)
 	}
 }
+
+func TestGenerateParamsData(t *testing.T) {
+	m := mockEnvironments(t, "test-gen-params-data")
+
+	expected := `local params = import "test-gen-params-data/components/params.libsonnet";
+params + {
+  components +: {
+    // Insert component parameter overrides here. Ex:
+    // guestbook +: {
+    //   name: "guestbook-dev",
+    //   replicas: params.global.replicas,
+    // },
+  },
+}
+`
+	result := string(m.generateParamsData())
+
+	if result != expected {
+		t.Fatalf("Expected to generate params file with data:\n%s\n, got:\n%s", expected, result)
+	}
+}
-- 
GitLab