# HG changeset patch # User Florent Aide <florent.aide@gmail.com> # Date 1652645549 -7200 # Sun May 15 22:12:29 2022 +0200 # Node ID c4f0f586a2f15ddc7871939a2ac2d89eb1cfd76e # Parent dba164c9d6498ce1b1bd459627bcf78616383f68 move hydration code to CmdConfig and add variable merging diff --git a/runner/cmd.go b/runner/cmd.go --- a/runner/cmd.go +++ b/runner/cmd.go @@ -1,11 +1,15 @@ package runner import ( + "bytes" + "fmt" "os" "path/filepath" + "text/template" "github.com/go-cmd/cmd" "github.com/rs/zerolog" + "gopkg.in/yaml.v2" ) func RunCMD(name string, args ...string) (err error, stdout, stderr []string) { @@ -71,3 +75,65 @@ Files []string Values []Value } + +// hydrate expands templated variables in our config with concrete values +func (c *CmdConfig) hydrate() error { + if err := c.hydrateHelmCharts(); err != nil { + return err + } + if err := c.hydrateYttCharts(); err != nil { + return err + } + return nil +} + +func (c *CmdConfig) prepareVariables(v []Variable) map[string]string { + variables := make(map[string]string) + for _, variable := range v { + variables[variable.Name] = variable.Value + } + variables["namespace"] = c.Namespace + return variables +} + +func (c *CmdConfig) hydrateYttCharts() error { + for entryFileName, entry := range c.Spec.Charts.Ytt { + for valIndex, val := range entry.Values { + valueTmpl, err := template.New("ytt entry value").Parse(val.Value) + if err != nil { + return fmt.Errorf("failed to parse ytt entry value as template: %q, %w", val.Value, err) + } + buf := new(bytes.Buffer) + if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil { + return fmt.Errorf("failed to hydrate ytt entry: %q, %w", val.Value, err) + } + // replace original content with hydrated version + c.Spec.Charts.Ytt[entryFileName].Values[valIndex].Value = buf.String() + } + } + return nil +} + +func (c *CmdConfig) hydrateHelmCharts() error { + for name, chart := range c.Spec.Charts.Helm { + var newVals []string + for _, value := range chart.Values { + rawChartValue, err := yaml.Marshal(value) + if err != nil { + return fmt.Errorf("failed to get chart values as string: %w", err) + } + valueTmpl, err := template.New("chart").Parse(string(rawChartValue)) + if err != nil { + return fmt.Errorf("failed to parse chart values as template: %q, %w", chart.Values, err) + } + buf := new(bytes.Buffer) + if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil { + return fmt.Errorf("failed to hydrate chart values entry: %q, %w", chart.Values, err) + } + newVals = append(newVals, buf.String()) + } + chart.Values = newVals + c.Spec.Charts.Helm[name] = chart + } + return nil +} diff --git a/runner/config.go b/runner/config.go --- a/runner/config.go +++ b/runner/config.go @@ -1,14 +1,7 @@ package runner import ( - "bytes" - "errors" - "fmt" - "os" - "text/template" - "github.com/spf13/viper" - yaml "gopkg.in/yaml.v2" ) // Variable ... @@ -70,67 +63,25 @@ return cfg, nil } -func checkExists(path string) bool { - _, err := os.Stat(path) - return !errors.Is(err, os.ErrNotExist) -} - -// hydrate expands templated variables in our config with concrete values -func (c *Config) hydrate() error { - if err := c.hydrateHelmCharts(); err != nil { - return err +// MergeVariables takes another config and will import those variables into +// the current config by replacing old ones and adding the new ones +func (c *Config) MergeVariables(other *Config) { + for _, variable := range other.Spec.Variables { + c.overlayVariable(variable) } - if err := c.hydrateYttCharts(); err != nil { - return err - } - return nil -} - -func (c *Config) prepareVariables(v []Variable) map[string]string { - variables := make(map[string]string) - for _, variable := range v { - variables[variable.Name] = variable.Value - } - variables["namespace"] = c.Namespace - return variables } -func (c *Config) hydrateYttCharts() error { - for entryFileName, entry := range c.Spec.Charts.Ytt { - for valIndex, val := range entry.Values { - valueTmpl, err := template.New("ytt entry value").Parse(val.Value) - if err != nil { - return fmt.Errorf("failed to parse ytt entry value as template: %q, %w", val.Value, err) - } - buf := new(bytes.Buffer) - if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil { - return fmt.Errorf("failed to hydrate ytt entry: %q, %w", val.Value, err) - } - // replace original content with hydrated version - c.Spec.Charts.Ytt[entryFileName].Values[valIndex].Value = buf.String() +// overlayVariable takes a variable in and either replaces an existing variable +// of the same name or create a new variable in the config if no matching name +// is found +func (c *Config) overlayVariable(v Variable) { + // find same variable by name and replace is value + // if not found then create the variable + for index, originalVariable := range c.Spec.Variables { + if originalVariable.Name == v.Name { + c.Spec.Variables[index].Value = v.Value + return } } - return nil + c.Spec.Variables = append(c.Spec.Variables, v) } - -func (c *Config) hydrateHelmCharts() error { - for name, chart := range c.Spec.Charts.Helm { - rawChartValues, err := yaml.Marshal(chart.Values) - if err != nil { - return fmt.Errorf("failed to get chart values as string: %w", err) - } - valueTmpl, err := template.New("chart").Parse(string(rawChartValues)) - if err != nil { - return fmt.Errorf("failed to parse chart values as template: %q, %w", chart.Values, err) - } - buf := new(bytes.Buffer) - if err := valueTmpl.Execute(buf, c.prepareVariables(c.Spec.Variables)); err != nil { - return fmt.Errorf("failed to hydrate chart values entry: %q, %w", chart.Values, err) - } - // replace original content with hydrated version - hydratedChart := chart - hydratedChart.Values = buf.String() - c.Spec.Charts.Helm[name] = hydratedChart - } - return nil -} diff --git a/runner/config_test.go b/runner/config_test.go --- a/runner/config_test.go +++ b/runner/config_test.go @@ -37,3 +37,4 @@ // verify variables overwrite assert.Equal(t, "admin", config.Spec.Charts.Ytt["odoo"].Values[2].Value) +}