diff --git a/cmd/helm/get_values.go b/cmd/helm/get_values.go index 837301e88..b13d0ba75 100644 --- a/cmd/helm/get_values.go +++ b/cmd/helm/get_values.go @@ -20,6 +20,7 @@ import ( "fmt" "io" + "github.com/ghodss/yaml" "github.com/spf13/cobra" "k8s.io/helm/cmd/helm/require" @@ -81,6 +82,11 @@ func (o *getValuesOptions) run(out io.Writer) error { return nil } - fmt.Fprintln(out, string(res.Config)) + resConfig, err := yaml.Marshal(res.Config) + if err != nil { + return err + } + + fmt.Fprintln(out, string(resConfig)) return nil } diff --git a/cmd/helm/lint.go b/cmd/helm/lint.go index dd71677b5..756ed4261 100644 --- a/cmd/helm/lint.go +++ b/cmd/helm/lint.go @@ -126,7 +126,7 @@ func (o *lintOptions) run(out io.Writer) error { return nil } -func lintChart(path string, vals []byte, namespace string, strict bool) (support.Linter, error) { +func lintChart(path string, vals map[string]interface{}, namespace string, strict bool) (support.Linter, error) { var chartPath string linter := support.Linter{} @@ -165,7 +165,7 @@ func lintChart(path string, vals []byte, namespace string, strict bool) (support return lint.All(chartPath, vals, namespace, strict), nil } -func (o *lintOptions) vals() ([]byte, error) { +func (o *lintOptions) vals() (map[string]interface{}, error) { base := map[string]interface{}{} // User specified a values files via -f/--values @@ -173,11 +173,11 @@ func (o *lintOptions) vals() ([]byte, error) { currentMap := map[string]interface{}{} bytes, err := ioutil.ReadFile(filePath) if err != nil { - return []byte{}, err + return base, err } if err := yaml.Unmarshal(bytes, ¤tMap); err != nil { - return []byte{}, errors.Wrapf(err, "failed to parse %s", filePath) + return base, errors.Wrapf(err, "failed to parse %s", filePath) } // Merge with the previous map base = mergeValues(base, currentMap) @@ -186,16 +186,16 @@ func (o *lintOptions) vals() ([]byte, error) { // User specified a value via --set for _, value := range o.values { if err := strvals.ParseInto(value, base); err != nil { - return []byte{}, errors.Wrap(err, "failed parsing --set data") + return base, errors.Wrap(err, "failed parsing --set data") } } // User specified a value via --set-string for _, value := range o.stringValues { if err := strvals.ParseIntoString(value, base); err != nil { - return []byte{}, errors.Wrap(err, "failed parsing --set-string data") + return base, errors.Wrap(err, "failed parsing --set-string data") } } - return yaml.Marshal(base) + return base, nil } diff --git a/cmd/helm/lint_test.go b/cmd/helm/lint_test.go index 1609debbe..da7bdb70a 100644 --- a/cmd/helm/lint_test.go +++ b/cmd/helm/lint_test.go @@ -21,7 +21,7 @@ import ( ) var ( - values = []byte{} + values = make(map[string]interface{}) namespace = "testNamespace" strict = false archivedChartPath = "testdata/testcharts/compressedchart-0.1.0.tgz" diff --git a/cmd/helm/options.go b/cmd/helm/options.go index 33dda1a79..8d68cf214 100644 --- a/cmd/helm/options.go +++ b/cmd/helm/options.go @@ -50,7 +50,7 @@ func (o *valuesOptions) addFlags(fs *pflag.FlagSet) { // mergeValues merges values from files specified via -f/--values and // directly via --set or --set-string, marshaling them to YAML -func (o *valuesOptions) mergedValues() ([]byte, error) { +func (o *valuesOptions) mergedValues() (map[string]interface{}, error) { base := map[string]interface{}{} // User specified a values files via -f/--values @@ -59,11 +59,11 @@ func (o *valuesOptions) mergedValues() ([]byte, error) { bytes, err := readFile(filePath) if err != nil { - return []byte{}, err + return base, err } if err := yaml.Unmarshal(bytes, ¤tMap); err != nil { - return []byte{}, errors.Wrapf(err, "failed to parse %s", filePath) + return base, errors.Wrapf(err, "failed to parse %s", filePath) } // Merge with the previous map base = mergeValues(base, currentMap) @@ -72,18 +72,18 @@ func (o *valuesOptions) mergedValues() ([]byte, error) { // User specified a value via --set for _, value := range o.values { if err := strvals.ParseInto(value, base); err != nil { - return []byte{}, errors.Wrap(err, "failed parsing --set data") + return base, errors.Wrap(err, "failed parsing --set data") } } // User specified a value via --set-string for _, value := range o.stringValues { if err := strvals.ParseIntoString(value, base); err != nil { - return []byte{}, errors.Wrap(err, "failed parsing --set-string data") + return base, errors.Wrap(err, "failed parsing --set-string data") } } - return yaml.Marshal(base) + return base, nil } // readFile load a file from stdin, the local directory, or a remote file with a url. diff --git a/cmd/helm/printer.go b/cmd/helm/printer.go index aa20590ca..8cd013075 100644 --- a/cmd/helm/printer.go +++ b/cmd/helm/printer.go @@ -21,6 +21,8 @@ import ( "text/template" "time" + "github.com/ghodss/yaml" + "k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/hapi/release" ) @@ -51,15 +53,20 @@ func printRelease(out io.Writer, rel *release.Release) error { if err != nil { return err } - cfgStr, err := cfg.YAML() + computed, err := cfg.YAML() + if err != nil { + return err + } + + config, err := yaml.Marshal(rel.Config) if err != nil { return err } data := map[string]interface{}{ "Release": rel, - "Config": string(rel.Config), - "ComputedValues": cfgStr, + "Config": string(config), + "ComputedValues": computed, "ReleaseDate": rel.Info.LastDeployed.Format(time.ANSIC), } return tpl(printReleaseTemplate, data, out) diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 04dffa517..44285cb1a 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -27,7 +27,6 @@ import ( "time" "github.com/Masterminds/semver" - "github.com/ghodss/yaml" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -167,11 +166,7 @@ func (o *templateOptions) run(out io.Writer) error { Name: o.releaseName, } - var m map[string]interface{} - if err := yaml.Unmarshal(config, &m); err != nil { - return err - } - if err := chartutil.ProcessDependencies(c, m); err != nil { + if err := chartutil.ProcessDependencies(c, config); err != nil { return err } diff --git a/cmd/helm/testdata/output/get-release.txt b/cmd/helm/testdata/output/get-release.txt index 844712011..2c6127f33 100644 --- a/cmd/helm/testdata/output/get-release.txt +++ b/cmd/helm/testdata/output/get-release.txt @@ -2,7 +2,8 @@ REVISION: 1 RELEASED: Fri Sep 2 22:04:05 1977 CHART: foo-0.1.0-beta.1 USER-SUPPLIED VALUES: -name: "value" +name: value + COMPUTED VALUES: name: value diff --git a/cmd/helm/testdata/output/get-values.txt b/cmd/helm/testdata/output/get-values.txt index e6ad584a9..de601163c 100644 --- a/cmd/helm/testdata/output/get-values.txt +++ b/cmd/helm/testdata/output/get-values.txt @@ -1 +1,2 @@ -name: "value" +name: value + diff --git a/pkg/chartutil/dependencies.go b/pkg/chartutil/dependencies.go index 4c32a6b79..f87983adb 100644 --- a/pkg/chartutil/dependencies.go +++ b/pkg/chartutil/dependencies.go @@ -19,8 +19,6 @@ import ( "log" "strings" - "github.com/ghodss/yaml" - "k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/version" ) @@ -166,8 +164,7 @@ Loop: for _, lr := range c.Metadata.Dependencies { lr.Enabled = true } - b, _ := yaml.Marshal(v) - cvals, err := CoalesceValues(c, b) + cvals, err := CoalesceValues(c, v) if err != nil { return err } @@ -227,7 +224,7 @@ func processImportValues(c *chart.Chart) error { return nil } // combine chart values and empty config to get Values - cvals, err := CoalesceValues(c, []byte{}) + cvals, err := CoalesceValues(c, nil) if err != nil { return err } @@ -253,7 +250,7 @@ func processImportValues(c *chart.Chart) error { continue } // create value map from child to be merged into parent - b = coalesceTables(cvals, pathToMap(parent, vv.AsMap())) + b = CoalesceTables(cvals, pathToMap(parent, vv.AsMap())) case string: child := "exports." + iv outiv = append(outiv, map[string]string{ @@ -265,7 +262,7 @@ func processImportValues(c *chart.Chart) error { log.Printf("Warning: ImportValues missing table: %v", err) continue } - b = coalesceTables(b, vm.AsMap()) + b = CoalesceTables(b, vm.AsMap()) } } // set our formatted import values @@ -273,7 +270,7 @@ func processImportValues(c *chart.Chart) error { } // set the new values - c.Values = coalesceTables(b, cvals) + c.Values = CoalesceTables(b, cvals) return nil } diff --git a/pkg/chartutil/values.go b/pkg/chartutil/values.go index 957fc92a0..e9aad0866 100644 --- a/pkg/chartutil/values.go +++ b/pkg/chartutil/values.go @@ -142,21 +142,14 @@ func ReadValuesFile(filename string) (Values, error) { // - Scalar values and arrays are replaced, maps are merged // - A chart has access to all of the variables for it, as well as all of // the values destined for its dependencies. -func CoalesceValues(chrt *chart.Chart, vals []byte) (Values, error) { - var err error - cvals := Values{} - // Parse values if not nil. We merge these at the top level because - // the passed-in values are in the same namespace as the parent chart. - if vals != nil { - cvals, err = ReadValues(vals) - if err != nil { - return cvals, err - } +func CoalesceValues(chrt *chart.Chart, vals map[string]interface{}) (Values, error) { + if vals == nil { + vals = make(map[string]interface{}) } - if _, err := coalesce(chrt, cvals); err != nil { - return cvals, err + if _, err := coalesce(chrt, vals); err != nil { + return vals, err } - return coalesceDeps(chrt, cvals) + return coalesceDeps(chrt, vals) } // coalesce coalesces the dest values and the chart values, giving priority to the dest values. @@ -229,7 +222,7 @@ func coalesceGlobals(dest, src map[string]interface{}) { } else { // Basically, we reverse order of coalesce here to merge // top-down. - coalesceTables(vv, destvmap) + CoalesceTables(vv, destvmap) dg[key] = vv continue } @@ -273,7 +266,7 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) { } // Because v has higher precedence than nv, dest values override src // values. - coalesceTables(dest, src) + CoalesceTables(dest, src) } } else { // If the key is not in v, copy it from nv. @@ -285,7 +278,10 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) { // coalesceTables merges a source map into a destination map. // // dest is considered authoritative. -func coalesceTables(dst, src map[string]interface{}) map[string]interface{} { +func CoalesceTables(dst, src map[string]interface{}) map[string]interface{} { + if dst == nil || src == nil { + return src + } // Because dest has higher precedence than src, dest values override src // values. for key, val := range src { @@ -293,17 +289,14 @@ func coalesceTables(dst, src map[string]interface{}) map[string]interface{} { if innerdst, ok := dst[key]; !ok { dst[key] = val } else if istable(innerdst) { - coalesceTables(innerdst.(map[string]interface{}), val.(map[string]interface{})) + CoalesceTables(innerdst.(map[string]interface{}), val.(map[string]interface{})) } else { log.Printf("warning: cannot overwrite table with non table for %s (%v)", key, val) } - continue } else if dv, ok := dst[key]; ok && istable(dv) { log.Printf("warning: destination for %s is a table. Ignoring non-table value %v", key, val) - continue } else if !ok { // <- ok is still in scope from preceding conditional. dst[key] = val - continue } } return dst @@ -320,7 +313,7 @@ type ReleaseOptions struct { // ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files // // This takes both ReleaseOptions and Capabilities to merge into the render values. -func ToRenderValues(chrt *chart.Chart, chrtVals []byte, options ReleaseOptions, caps *Capabilities) (Values, error) { +func ToRenderValues(chrt *chart.Chart, chrtVals map[string]interface{}, options ReleaseOptions, caps *Capabilities) (Values, error) { top := map[string]interface{}{ "Release": map[string]interface{}{ diff --git a/pkg/chartutil/values_test.go b/pkg/chartutil/values_test.go index 7e189bbfd..837c5056b 100644 --- a/pkg/chartutil/values_test.go +++ b/pkg/chartutil/values_test.go @@ -70,7 +70,7 @@ water: } } -func TestToRenderValuesCaps(t *testing.T) { +func TestToRenderValues(t *testing.T) { chartValues := map[string]interface{}{ "name": "al Rashid", @@ -80,12 +80,13 @@ func TestToRenderValuesCaps(t *testing.T) { }, } - overideValues := ` -name: Haroun -where: - city: Baghdad - date: 809 CE -` + overideValues := map[string]interface{}{ + "name": "Haroun", + "where": map[string]interface{}{ + "city": "Baghdad", + "date": "809 CE", + }, + } c := &chart.Chart{ Metadata: &chart.Metadata{Name: "test"}, @@ -98,7 +99,6 @@ where: c.AddDependency(&chart.Chart{ Metadata: &chart.Metadata{Name: "where"}, }) - v := []byte(overideValues) o := ReleaseOptions{ Name: "Seven Voyages", @@ -111,7 +111,7 @@ where: KubeVersion: &kversion.Info{Major: "1"}, } - res, err := ToRenderValues(c, v, o, caps) + res, err := ToRenderValues(c, overideValues, o, caps) if err != nil { t.Fatal(err) } @@ -263,7 +263,7 @@ func ttpl(tpl string, v map[string]interface{}) (string, error) { } // ref: http://www.yaml.org/spec/1.2/spec.html#id2803362 -var testCoalesceValuesYaml = ` +var testCoalesceValuesYaml = []byte(` top: yup bottom: null right: Null @@ -286,12 +286,17 @@ pequod: sail: true ahab: scope: whale -` +`) func TestCoalesceValues(t *testing.T) { c := loadChart(t, "testdata/moby") - v, err := CoalesceValues(c, []byte(testCoalesceValuesYaml)) + vals, err := ReadValues(testCoalesceValuesYaml) + if err != nil { + t.Fatal(err) + } + + v, err := CoalesceValues(c, vals) if err != nil { t.Fatal(err) } @@ -366,7 +371,7 @@ func TestCoalesceTables(t *testing.T) { // What we expect is that anything in dst overrides anything in src, but that // otherwise the values are coalesced. - coalesceTables(dst, src) + CoalesceTables(dst, src) if dst["name"] != "Ishmael" { t.Errorf("Unexpected name: %s", dst["name"]) diff --git a/pkg/engine/engine_test.go b/pkg/engine/engine_test.go index de73a8b8e..0c02ef24f 100644 --- a/pkg/engine/engine_test.go +++ b/pkg/engine/engine_test.go @@ -100,12 +100,13 @@ func TestRender(t *testing.T) { Values: map[string]interface{}{"outer": "DEFAULT", "inner": "DEFAULT"}, } - vals := []byte(` -outer: spouter -inner: inn -global: - callme: Ishmael -`) + vals := map[string]interface{}{ + "outer": "spouter", + "inner": "inn", + "global": map[string]interface{}{ + "callme": "Ishmael", + }, + } e := New() v, err := chartutil.CoalesceValues(c, vals) @@ -302,13 +303,17 @@ func TestRenderNestedValues(t *testing.T) { } outer.AddDependency(inner) - injValues := []byte(` -what: rosebuds -herrick: - deepest: - what: flower -global: - when: to-day`) + injValues := map[string]interface{}{ + "what": "rosebuds", + "herrick": map[string]interface{}{ + "deepest": map[string]interface{}{ + "what": "flower", + }, + }, + "global": map[string]interface{}{ + "when": "to-day", + }, + } tmp, err := chartutil.CoalesceValues(outer, injValues) if err != nil { diff --git a/pkg/hapi/release/release.go b/pkg/hapi/release/release.go index 9477369c5..a52e39566 100644 --- a/pkg/hapi/release/release.go +++ b/pkg/hapi/release/release.go @@ -28,7 +28,7 @@ type Release struct { Chart *chart.Chart `json:"chart,omitempty"` // Config is the set of extra Values added to the chart. // These values override the default values inside of the chart. - Config []byte `json:"config,omitempty"` + Config map[string]interface{} `json:"config,omitempty"` // Manifest is the string representation of the rendered template. Manifest string `json:"manifest,omitempty"` // Hooks are all of the hooks declared for this release. diff --git a/pkg/hapi/tiller.go b/pkg/hapi/tiller.go index dbd1580b0..85ea3e64e 100644 --- a/pkg/hapi/tiller.go +++ b/pkg/hapi/tiller.go @@ -98,7 +98,7 @@ type UpdateReleaseRequest struct { // Chart is the protobuf representation of a chart. Chart *chart.Chart `json:"chart,omitempty"` // Values is a string containing (unparsed) YAML values. - Values []byte `json:"values,omitempty"` + Values map[string]interface{} `json:"values,omitempty"` // dry_run, if true, will run through the release logic, but neither create DryRun bool `json:"dry_run,omitempty"` // DisableHooks causes the server to skip running any hooks for the upgrade. @@ -146,7 +146,7 @@ type InstallReleaseRequest struct { // Chart is the protobuf representation of a chart. Chart *chart.Chart `json:"chart,omitempty"` // Values is a string containing (unparsed) YAML values. - Values []byte `json:"values,omitempty"` + Values map[string]interface{} `json:"values,omitempty"` // DryRun, if true, will run through the release logic, but neither create // a release object nor deploy to Kubernetes. The release object returned // in the response will be fake. diff --git a/pkg/helm/client.go b/pkg/helm/client.go index 0dea035a1..aa4e1fab0 100644 --- a/pkg/helm/client.go +++ b/pkg/helm/client.go @@ -17,8 +17,6 @@ limitations under the License. package helm // import "k8s.io/helm/pkg/helm" import ( - yaml "gopkg.in/yaml.v2" - "k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chart/loader" "k8s.io/helm/pkg/chartutil" @@ -95,10 +93,7 @@ func (c *Client) InstallReleaseFromChart(chart *chart.Chart, ns string, opts ... if err := reqOpts.runBefore(req); err != nil { return nil, err } - var m map[string]interface{} - yaml.Unmarshal(req.Values, &m) - err := chartutil.ProcessDependencies(req.Chart, m) - if err != nil { + if err := chartutil.ProcessDependencies(req.Chart, req.Values); err != nil { return nil, err } return c.tiller.InstallRelease(req) @@ -162,11 +157,7 @@ func (c *Client) UpdateReleaseFromChart(rlsName string, chart *chart.Chart, opts if err := reqOpts.runBefore(req); err != nil { return nil, err } - var m map[string]interface{} - if err := yaml.Unmarshal(req.Values, &m); err != nil { - return nil, err - } - if err := chartutil.ProcessDependencies(req.Chart, m); err != nil { + if err := chartutil.ProcessDependencies(req.Chart, req.Values); err != nil { return nil, err } return c.tiller.UpdateRelease(req) diff --git a/pkg/helm/fake.go b/pkg/helm/fake.go index 2228cc485..80b850a6b 100644 --- a/pkg/helm/fake.go +++ b/pkg/helm/fake.go @@ -231,7 +231,7 @@ func ReleaseMock(opts *MockReleaseOptions) *release.Release { Description: "Release mock", }, Chart: ch, - Config: []byte(`name: "value"`), + Config: map[string]interface{}{"name": "value"}, Version: version, Namespace: namespace, Hooks: []*release.Hook{ diff --git a/pkg/helm/helm_test.go b/pkg/helm/helm_test.go index d35ad05b4..50cd821ad 100644 --- a/pkg/helm/helm_test.go +++ b/pkg/helm/helm_test.go @@ -101,12 +101,10 @@ func TestInstallRelease_VerifyOptions(t *testing.T) { var dryRun = true var chartName = "alpine" var chartPath = filepath.Join(chartsDir, chartName) - var overrides = []byte("key1=value1,key2=value2") // Expected InstallReleaseRequest message exp := &hapi.InstallReleaseRequest{ Chart: loadChart(t, chartName), - Values: overrides, DryRun: dryRun, Name: releaseName, DisableHooks: disableHooks, @@ -115,7 +113,6 @@ func TestInstallRelease_VerifyOptions(t *testing.T) { // Options used in InstallRelease ops := []InstallOption{ - ValueOverrides(overrides), InstallDryRun(dryRun), ReleaseName(releaseName), InstallReuseName(reuseName), @@ -191,14 +188,12 @@ func TestUpdateRelease_VerifyOptions(t *testing.T) { var chartPath = filepath.Join(chartsDir, chartName) var releaseName = "test" var disableHooks = true - var overrides = []byte("key1=value1,key2=value2") var dryRun = false // Expected UpdateReleaseRequest message exp := &hapi.UpdateReleaseRequest{ Name: releaseName, Chart: loadChart(t, chartName), - Values: overrides, DryRun: dryRun, DisableHooks: disableHooks, } @@ -206,7 +201,6 @@ func TestUpdateRelease_VerifyOptions(t *testing.T) { // Options used in UpdateRelease ops := []UpdateOption{ UpgradeDryRun(dryRun), - UpdateValueOverrides(overrides), UpgradeDisableHooks(disableHooks), } diff --git a/pkg/helm/option.go b/pkg/helm/option.go index e0d1cda6a..ecc164031 100644 --- a/pkg/helm/option.go +++ b/pkg/helm/option.go @@ -143,7 +143,7 @@ func ReleaseListStatuses(statuses []release.ReleaseStatus) ReleaseListOption { type InstallOption func(*options) // ValueOverrides specifies a list of values to include when installing. -func ValueOverrides(raw []byte) InstallOption { +func ValueOverrides(raw map[string]interface{}) InstallOption { return func(opts *options) { opts.instReq.Values = raw } @@ -220,7 +220,7 @@ func RollbackWait(wait bool) RollbackOption { } // UpdateValueOverrides specifies a list of values to include when upgrading -func UpdateValueOverrides(raw []byte) UpdateOption { +func UpdateValueOverrides(raw map[string]interface{}) UpdateOption { return func(opts *options) { opts.updateReq.Values = raw } diff --git a/pkg/lint/lint.go b/pkg/lint/lint.go index aa8df5814..534085cd1 100644 --- a/pkg/lint/lint.go +++ b/pkg/lint/lint.go @@ -24,7 +24,7 @@ import ( ) // All runs all of the available linters on the given base directory. -func All(basedir string, values []byte, namespace string, strict bool) support.Linter { +func All(basedir string, values map[string]interface{}, namespace string, strict bool) support.Linter { // Using abs path to get directory context chartDir, _ := filepath.Abs(basedir) diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index 2f0b88526..f0747a294 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -24,7 +24,7 @@ import ( "testing" ) -var values = []byte{} +var values map[string]interface{} const namespace = "testNamespace" const strict = false diff --git a/pkg/lint/rules/template.go b/pkg/lint/rules/template.go index 6ee578aff..2acf63168 100644 --- a/pkg/lint/rules/template.go +++ b/pkg/lint/rules/template.go @@ -30,7 +30,7 @@ import ( ) // Templates lints the templates in the Linter. -func Templates(linter *support.Linter, values []byte, namespace string, strict bool) { +func Templates(linter *support.Linter, values map[string]interface{}, namespace string, strict bool) { path := "templates/" templatesPath := filepath.Join(linter.ChartDir, path) @@ -56,13 +56,8 @@ func Templates(linter *support.Linter, values []byte, namespace string, strict b if err != nil { return } - // convert our values back into config - yvals, err := yaml.Marshal(cvals) - if err != nil { - return - } caps := chartutil.DefaultCapabilities - valuesToRender, err := chartutil.ToRenderValues(chart, yvals, options, caps) + valuesToRender, err := chartutil.ToRenderValues(chart, cvals, options, caps) if err != nil { // FIXME: This seems to generate a duplicate, but I can't find where the first // error is coming from. diff --git a/pkg/lint/rules/template_test.go b/pkg/lint/rules/template_test.go index 41a7384e7..8731cf96e 100644 --- a/pkg/lint/rules/template_test.go +++ b/pkg/lint/rules/template_test.go @@ -44,7 +44,7 @@ func TestValidateAllowedExtension(t *testing.T) { } } -var values = []byte("nameOverride: ''\nhttpPort: 80") +var values = map[string]interface{}{"nameOverride": "", "httpPort": 80} const namespace = "testNamespace" const strict = false diff --git a/pkg/releaseutil/sorter_test.go b/pkg/releaseutil/sorter_test.go index 873a0de72..5198ce0a9 100644 --- a/pkg/releaseutil/sorter_test.go +++ b/pkg/releaseutil/sorter_test.go @@ -33,7 +33,7 @@ var releases = []*rspb.Release{ } func tsRelease(name string, vers int, dur time.Duration, status rspb.ReleaseStatus) *rspb.Release { - tmsp := time.Now().Add(time.Duration(dur)) + tmsp := time.Now().Add(dur) info := &rspb.Info{Status: status, LastDeployed: tmsp} return &rspb.Release{ Name: name, diff --git a/pkg/tiller/release_server.go b/pkg/tiller/release_server.go index 65e1c4964..d64803861 100644 --- a/pkg/tiller/release_server.go +++ b/pkg/tiller/release_server.go @@ -25,7 +25,6 @@ import ( "time" "github.com/pkg/errors" - "gopkg.in/yaml.v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/discovery" @@ -126,31 +125,14 @@ func (s *ReleaseServer) reuseValues(req *hapi.UpdateReleaseRequest, current *rel return errors.Wrap(err, "failed to rebuild old values") } - // merge new values with current - b := append(current.Config, '\n') - req.Values = append(b, req.Values...) + req.Values = chartutil.CoalesceTables(current.Config, req.Values) req.Chart.Values = oldVals - // yaml unmarshal and marshal to remove duplicate keys - y := map[string]interface{}{} - if err := yaml.Unmarshal(req.Values, &y); err != nil { - return err - } - data, err := yaml.Marshal(y) - if err != nil { - return err - } - - req.Values = data return nil } - // If req.Values is empty, but current.Config is not, copy current into the - // request. - if (len(req.Values) == 0 || bytes.Equal(req.Values, []byte("{}\n"))) && - len(current.Config) > 0 && - !bytes.Equal(current.Config, []byte("{}\n")) { + if len(req.Values) == 0 && len(current.Config) > 0 { s.Log("copying values from %s (v%d) to new release.", current.Name, current.Version) req.Values = current.Config } diff --git a/pkg/tiller/release_server_test.go b/pkg/tiller/release_server_test.go index cec06a35c..0c8de78b6 100644 --- a/pkg/tiller/release_server_test.go +++ b/pkg/tiller/release_server_test.go @@ -239,7 +239,7 @@ func namedReleaseStub(name string, status release.ReleaseStatus) *release.Releas Description: "Named Release Stub", }, Chart: chartStub(), - Config: []byte(`name: value`), + Config: map[string]interface{}{"name": "value"}, Version: 1, Hooks: []*release.Hook{ { @@ -379,7 +379,7 @@ func releaseWithKeepStub(rlsName string) *release.Release { Status: release.StatusDeployed, }, Chart: ch, - Config: []byte(`name: value`), + Config: map[string]interface{}{"name": "value"}, Version: 1, Manifest: manifestWithKeep, } diff --git a/pkg/tiller/release_update_test.go b/pkg/tiller/release_update_test.go index 178522d08..f0c480096 100644 --- a/pkg/tiller/release_update_test.go +++ b/pkg/tiller/release_update_test.go @@ -17,7 +17,6 @@ limitations under the License. package tiller import ( - "bytes" "reflect" "strings" "testing" @@ -82,7 +81,7 @@ func TestUpdateRelease(t *testing.T) { if res.Config == nil { t.Errorf("Got release without config: %#v", res) - } else if !bytes.Equal(res.Config, rel.Config) { + } else if len(res.Config) != len(rel.Config) { t.Errorf("Expected release values %q, got %q", rel.Config, res.Config) } @@ -139,7 +138,7 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) { {Name: "templates/hooks", Data: []byte(manifestWithHook)}, }, }, - Values: []byte("foo: bar"), + Values: map[string]interface{}{"foo": "bar"}, } t.Log("Running Install release with foo: bar override") @@ -165,9 +164,8 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) { t.Fatalf("Failed updated: %s", err) } - expect := "foo: bar" - if rel.Config != nil && !bytes.Equal(rel.Config, []byte(expect)) { - t.Errorf("Expected chart values to be %q, got %q", expect, string(rel.Config)) + if rel.Config != nil && rel.Config["foo"] != "bar" { + t.Errorf("Expected chart value 'foo' = 'bar', got %s", rel.Config) } req = &hapi.UpdateReleaseRequest{ @@ -179,7 +177,7 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) { {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, }, }, - Values: []byte("foo2: bar2"), + Values: map[string]interface{}{"foo2": "bar2"}, ReuseValues: true, } @@ -190,9 +188,8 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) { } // This should have the newly-passed overrides. - expect = "foo: bar\nfoo2: bar2\n" - if rel.Config != nil && !bytes.Equal(rel.Config, []byte(expect)) { - t.Errorf("Expected request config to be %q, got %q", expect, string(rel.Config)) + if len(rel.Config) != 2 && rel.Config["foo2"] != "bar2" { + t.Errorf("Expected chart value 'foo2' = 'bar2', got %s", rel.Config) } req = &hapi.UpdateReleaseRequest{ @@ -204,7 +201,7 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) { {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, }, }, - Values: []byte("foo: baz"), + Values: map[string]interface{}{"foo": "baz"}, ReuseValues: true, } @@ -213,9 +210,8 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) { if err != nil { t.Fatalf("Failed updated: %s", err) } - expect = "foo: baz\nfoo2: bar2\n" - if rel.Config != nil && !bytes.Equal(rel.Config, []byte(expect)) { - t.Errorf("Expected chart values to be %q, got %q", expect, rel.Config) + if len(rel.Config) != 2 && rel.Config["foo"] != "baz" { + t.Errorf("Expected chart value 'foo' = 'baz', got %s", rel.Config) } } @@ -235,7 +231,7 @@ func TestUpdateRelease_ReuseValues(t *testing.T) { // Since reuseValues is set, this should get ignored. Values: map[string]interface{}{"foo": "bar"}, }, - Values: []byte("name2: val2"), + Values: map[string]interface{}{"name2": "val2"}, ReuseValues: true, } res, err := rs.UpdateRelease(req) @@ -248,7 +244,7 @@ func TestUpdateRelease_ReuseValues(t *testing.T) { } // This should have the newly-passed overrides and any other computed values. `name: value` comes from release Config via releaseStub() expect := "name: value\nname2: val2\n" - if res.Config != nil && !bytes.Equal(res.Config, []byte(expect)) { + if len(res.Config) != 2 || res.Config["name"] != "value" || res.Config["name2"] != "val2" { t.Errorf("Expected request config to be %q, got %q", expect, res.Config) } compareStoredAndReturnedRelease(t, *rs, res)