about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@gmail.com>2017-07-13T13·57+0200
committerVincent Ambo <tazjin@gmail.com>2017-07-13T14·07+0200
commit7607f6dc0fff076cc69ca2d6f50eb04b728e3a44 (patch)
tree7deafdc7ad291249d773eaec1b47113e843b22a3
parent9d26c17f13240479ef3e12e9182aca3ac2e61901 (diff)
feat context: Allow overriding resource set paths
Instead of always inferring the path at which files in a resource set
are located, let users override the path by specifying a `path` field.

This makes it possible to add the same resource set multiple times
with different values while still keeping distinct names for
addressability (for example when using include/exclude).

This fixes #70
-rw-r--r--context/context.go23
-rw-r--r--context/context_test.go68
-rw-r--r--context/testdata/explicit-path.yaml11
-rw-r--r--context/testdata/explicit-subresource-path.yaml8
4 files changed, 105 insertions, 5 deletions
diff --git a/context/context.go b/context/context.go
index c812af8b26f7..66a45390e0f0 100644
--- a/context/context.go
+++ b/context/context.go
@@ -9,6 +9,7 @@ import (
 
 type ResourceSet struct {
 	Name   string                 `json:"name"`
+	Path   string                 `json:"path"`
 	Values map[string]interface{} `json:"values"`
 
 	// Fields for resource set collections
@@ -41,7 +42,7 @@ func LoadContextFromFile(filename string) (*Context, error) {
 		)
 	}
 
-	c.ResourceSets = flattenResourceSetCollections(&c.ResourceSets)
+	c.ResourceSets = flattenPrepareResourceSetPaths(&c.ResourceSets)
 	c.BaseDir = path.Dir(filename)
 	c.ResourceSets = loadAllDefaultValues(&c)
 
@@ -73,19 +74,31 @@ func (ctx *Context) loadImportedVariables() error {
 	return nil
 }
 
-// Flattens resource set collections, i.e. resource sets that themselves have an additional 'include' field set.
+// Correctly prepares the file paths for resource sets by inferring implicit paths and flattening resource set
+// collections, i.e. resource sets that themselves have an additional 'include' field set.
 // Those will be regarded as a short-hand for including multiple resource sets from a subfolder.
 // See https://github.com/tazjin/kontemplate/issues/9 for more information.
-func flattenResourceSetCollections(rs *[]ResourceSet) []ResourceSet {
+func flattenPrepareResourceSetPaths(rs *[]ResourceSet) []ResourceSet {
 	flattened := make([]ResourceSet, 0)
 
 	for _, r := range *rs {
+		// If a path is not explicitly specified it should default to the resource set name.
+		// This is also the classic behaviour prior to kontemplate 1.2
+		if r.Path == "" {
+			r.Path = r.Name
+		}
+
 		if len(r.Include) == 0 {
 			flattened = append(flattened, r)
 		} else {
 			for _, subResourceSet := range r.Include {
+				if subResourceSet.Path == "" {
+					subResourceSet.Path = subResourceSet.Name
+				}
+
 				subResourceSet.Parent = r.Name
 				subResourceSet.Name = path.Join(r.Name, subResourceSet.Name)
+				subResourceSet.Path = path.Join(r.Path, subResourceSet.Path)
 				subResourceSet.Values = *util.Merge(&r.Values, &subResourceSet.Values)
 				flattened = append(flattened, subResourceSet)
 			}
@@ -114,13 +127,13 @@ func loadDefaultValues(rs *ResourceSet, c *Context) *map[string]interface{} {
 	var defaultVars map[string]interface{}
 
 	// Attempt to load YAML values
-	err := util.LoadJsonOrYaml(path.Join(c.BaseDir, rs.Name, "default.yaml"), &defaultVars)
+	err := util.LoadJsonOrYaml(path.Join(c.BaseDir, rs.Path, "default.yaml"), &defaultVars)
 	if err == nil {
 		return util.Merge(&defaultVars, &rs.Values)
 	}
 
 	// Attempt to load JSON values
-	err = util.LoadJsonOrYaml(path.Join(c.BaseDir, rs.Name, "default.json"), &defaultVars)
+	err = util.LoadJsonOrYaml(path.Join(c.BaseDir, rs.Path, "default.json"), &defaultVars)
 	if err == nil {
 		return util.Merge(&defaultVars, &rs.Values)
 	}
diff --git a/context/context_test.go b/context/context_test.go
index b6acf416e6cc..350b2b66a9cf 100644
--- a/context/context_test.go
+++ b/context/context_test.go
@@ -21,6 +21,7 @@ func TestLoadFlatContextFromFile(t *testing.T) {
 		ResourceSets: []ResourceSet{
 			{
 				Name: "some-api",
+				Path: "some-api",
 				Values: map[string]interface{}{
 					"apiPort":          float64(4567), // yep!
 					"importantFeature": true,
@@ -55,6 +56,7 @@ func TestLoadContextWithResourceSetCollections(t *testing.T) {
 		ResourceSets: []ResourceSet{
 			{
 				Name: "some-api",
+				Path: "some-api",
 				Values: map[string]interface{}{
 					"apiPort":          float64(4567), // yep!
 					"importantFeature": true,
@@ -65,6 +67,7 @@ func TestLoadContextWithResourceSetCollections(t *testing.T) {
 			},
 			{
 				Name: "collection/nested",
+				Path: "collection/nested",
 				Values: map[string]interface{}{
 					"lizards": "good",
 				},
@@ -95,6 +98,7 @@ func TestSubresourceVariableInheritance(t *testing.T) {
 		ResourceSets: []ResourceSet{
 			{
 				Name: "parent/child",
+				Path: "parent/child",
 				Values: map[string]interface{}{
 					"foo": "bar",
 					"bar": "baz",
@@ -125,6 +129,7 @@ func TestSubresourceVariableInheritanceOverride(t *testing.T) {
 		ResourceSets: []ResourceSet{
 			{
 				Name: "parent/child",
+				Path: "parent/child",
 				Values: map[string]interface{}{
 					"foo": "newvalue",
 				},
@@ -203,3 +208,66 @@ func TestImportValuesOverride(t *testing.T) {
 		t.Fail()
 	}
 }
+
+func TestExplicitPathLoading(t *testing.T) {
+	ctx, err := LoadContextFromFile("testdata/explicit-path.yaml")
+	if err != nil {
+		t.Error(err)
+		t.Fail()
+	}
+
+	expected := Context{
+		Name: "k8s.prod.mydomain.com",
+		ResourceSets: []ResourceSet{
+			{
+				Name: "some-api-europe",
+				Path: "some-api",
+				Values: map[string]interface{}{
+					"location": "europe",
+				},
+				Include: nil,
+				Parent:  "",
+			},
+			{
+				Name: "some-api-asia",
+				Path: "some-api",
+				Values: map[string]interface{}{
+					"location": "asia",
+				},
+				Include: nil,
+				Parent:  "",
+			},
+		},
+		BaseDir: "testdata",
+	}
+
+	if !reflect.DeepEqual(*ctx, expected) {
+		t.Error("Loaded context and expected context did not match")
+		t.Fail()
+	}
+}
+
+func TestExplicitSubresourcePathLoading(t *testing.T) {
+	ctx, err := LoadContextFromFile("testdata/explicit-subresource-path.yaml")
+	if err != nil {
+		t.Error(err)
+		t.Fail()
+	}
+
+	expected := Context{
+		Name: "k8s.prod.mydomain.com",
+		ResourceSets: []ResourceSet{
+			{
+				Name:   "parent/child",
+				Path:   "parent-path/child-path",
+				Parent: "parent",
+			},
+		},
+		BaseDir: "testdata",
+	}
+
+	if !reflect.DeepEqual(*ctx, expected) {
+		t.Error("Loaded context and expected context did not match")
+		t.Fail()
+	}
+}
diff --git a/context/testdata/explicit-path.yaml b/context/testdata/explicit-path.yaml
new file mode 100644
index 000000000000..2c81f83c0919
--- /dev/null
+++ b/context/testdata/explicit-path.yaml
@@ -0,0 +1,11 @@
+---
+context: k8s.prod.mydomain.com
+include:
+  - name: some-api-europe
+    path: some-api
+    values:
+      location: europe
+  - name: some-api-asia
+    path: some-api
+    values:
+      location: asia
diff --git a/context/testdata/explicit-subresource-path.yaml b/context/testdata/explicit-subresource-path.yaml
new file mode 100644
index 000000000000..6cf86183229e
--- /dev/null
+++ b/context/testdata/explicit-subresource-path.yaml
@@ -0,0 +1,8 @@
+---
+context: k8s.prod.mydomain.com
+include:
+  - name: parent
+    path: parent-path
+    include:
+      - name: child
+        path: child-path