From 11cfc80020010ff949de767698124cc5719361e0 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Tue, 4 Apr 2017 14:28:22 +0200 Subject: [PATCH] feat context: Support resource set default values This adds functionality to specify default values directly in resource sets. The idea is that users can create a file called `values.yaml` or `values.json` in a resource set's folder and have all variables specified in that file be automatically merged into the resource set variables with the lowest priority. This fixes #25 This fixes #30 (to a degree) --- context/context.go | 46 +++++++++++++++++++++++++-- context/context_test.go | 14 ++++++++ context/testdata/default-loading.yaml | 6 ++++ context/testdata/default/default.yaml | 2 ++ 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 context/testdata/default-loading.yaml create mode 100644 context/testdata/default/default.yaml diff --git a/context/context.go b/context/context.go index 520070d88..ad3d00693 100644 --- a/context/context.go +++ b/context/context.go @@ -64,8 +64,9 @@ func LoadContextFromFile(filename string) (*Context, error) { ) } - c.ResourceSets = *flattenResourceSetCollections(&c.ResourceSets) + c.ResourceSets = flattenResourceSetCollections(&c.ResourceSets) c.BaseDir = path.Dir(filename) + c.ResourceSets = loadAllDefaultValues(&c) return &c, nil } @@ -73,7 +74,7 @@ func LoadContextFromFile(filename string) (*Context, error) { // Flattens 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 flattenResourceSetCollections(rs *[]ResourceSet) []ResourceSet { flattened := make([]ResourceSet, 0) for _, r := range *rs { @@ -89,5 +90,44 @@ func flattenResourceSetCollections(rs *[]ResourceSet) *[]ResourceSet { } } - return &flattened + return flattened +} + +func loadAllDefaultValues(c *Context) []ResourceSet { + updated := make([]ResourceSet, len(c.ResourceSets)) + + for i, rs := range c.ResourceSets { + merged := loadDefaultValues(&rs, c) + rs.Values = *merged + updated[i] = rs + } + + return updated +} + +// Loads and merges default values for a resource set collection from path/to/set/default.{json|yaml}. +// YAML takes precedence over JSON. +// Default values in resource set collections have the lowest priority possible. +func loadDefaultValues(rs *ResourceSet, c *Context) *map[string]interface{} { + var defaultVars map[string]interface{} + + // Attempt to load YAML values + y, err := ioutil.ReadFile(path.Join(c.BaseDir, rs.Name, "default.yaml")) + if err == nil { + yaml.Unmarshal(y, &defaultVars) + return util.Merge(&defaultVars, &rs.Values) + } + + // Attempt to load JSON values + j, err := ioutil.ReadFile(path.Join(c.BaseDir, rs.Name, "default.json")) + if err == nil { + json.Unmarshal(j, &defaultVars) + return util.Merge(&defaultVars, &rs.Values) + } + + // The actual error is not inspected here. The reasoning for this is that in case of serious problems (e.g. + // permission issues with the folder / folder not existing) failure will occur a bit later anyways. + // Otherwise we'd have to differentiate between file-not-found-errors (no default values specified) and other + // errors here. + return &rs.Values } diff --git a/context/context_test.go b/context/context_test.go index 4c95f058c..8da30c9a8 100644 --- a/context/context_test.go +++ b/context/context_test.go @@ -140,3 +140,17 @@ func TestSubresourceVariableInheritanceOverride(t *testing.T) { t.Fail() } } + +func TestDefaultValuesLoading(t *testing.T) { + ctx, err := LoadContextFromFile("testdata/default-loading.yaml") + if err != nil { + t.Error(err) + t.Fail() + } + + rs := ctx.ResourceSets[0] + if rs.Values["defaultValues"] != "loaded" { + t.Errorf("Default values not loaded from YAML file") + t.Fail() + } +} diff --git a/context/testdata/default-loading.yaml b/context/testdata/default-loading.yaml new file mode 100644 index 000000000..d589c99b4 --- /dev/null +++ b/context/testdata/default-loading.yaml @@ -0,0 +1,6 @@ +--- +context: default-loading +include: + - name: default + values: + override: notAtAll \ No newline at end of file diff --git a/context/testdata/default/default.yaml b/context/testdata/default/default.yaml new file mode 100644 index 000000000..0ffa3cd81 --- /dev/null +++ b/context/testdata/default/default.yaml @@ -0,0 +1,2 @@ +defaultValues: loaded +override: noop \ No newline at end of file