ref(*): replace byte array with map for Release config

Signed-off-by: Adam Reese <adam@reese.io>
pull/5013/head
Adam Reese 6 years ago
parent 7fa09e2d1f
commit 2b81eea1e2
No known key found for this signature in database
GPG Key ID: 06F35E60A7A18DD6

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/ghodss/yaml"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require" "k8s.io/helm/cmd/helm/require"
@ -81,6 +82,11 @@ func (o *getValuesOptions) run(out io.Writer) error {
return nil 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 return nil
} }

@ -126,7 +126,7 @@ func (o *lintOptions) run(out io.Writer) error {
return nil 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 var chartPath string
linter := support.Linter{} 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 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{}{} base := map[string]interface{}{}
// User specified a values files via -f/--values // User specified a values files via -f/--values
@ -173,11 +173,11 @@ func (o *lintOptions) vals() ([]byte, error) {
currentMap := map[string]interface{}{} currentMap := map[string]interface{}{}
bytes, err := ioutil.ReadFile(filePath) bytes, err := ioutil.ReadFile(filePath)
if err != nil { if err != nil {
return []byte{}, err return base, err
} }
if err := yaml.Unmarshal(bytes, &currentMap); err != nil { if err := yaml.Unmarshal(bytes, &currentMap); 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 // Merge with the previous map
base = mergeValues(base, currentMap) base = mergeValues(base, currentMap)
@ -186,16 +186,16 @@ func (o *lintOptions) vals() ([]byte, error) {
// User specified a value via --set // User specified a value via --set
for _, value := range o.values { for _, value := range o.values {
if err := strvals.ParseInto(value, base); err != nil { 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 // User specified a value via --set-string
for _, value := range o.stringValues { for _, value := range o.stringValues {
if err := strvals.ParseIntoString(value, base); err != nil { 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
} }

@ -21,7 +21,7 @@ import (
) )
var ( var (
values = []byte{} values = make(map[string]interface{})
namespace = "testNamespace" namespace = "testNamespace"
strict = false strict = false
archivedChartPath = "testdata/testcharts/compressedchart-0.1.0.tgz" archivedChartPath = "testdata/testcharts/compressedchart-0.1.0.tgz"

@ -50,7 +50,7 @@ func (o *valuesOptions) addFlags(fs *pflag.FlagSet) {
// mergeValues merges values from files specified via -f/--values and // mergeValues merges values from files specified via -f/--values and
// directly via --set or --set-string, marshaling them to YAML // 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{}{} base := map[string]interface{}{}
// User specified a values files via -f/--values // User specified a values files via -f/--values
@ -59,11 +59,11 @@ func (o *valuesOptions) mergedValues() ([]byte, error) {
bytes, err := readFile(filePath) bytes, err := readFile(filePath)
if err != nil { if err != nil {
return []byte{}, err return base, err
} }
if err := yaml.Unmarshal(bytes, &currentMap); err != nil { if err := yaml.Unmarshal(bytes, &currentMap); 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 // Merge with the previous map
base = mergeValues(base, currentMap) base = mergeValues(base, currentMap)
@ -72,18 +72,18 @@ func (o *valuesOptions) mergedValues() ([]byte, error) {
// User specified a value via --set // User specified a value via --set
for _, value := range o.values { for _, value := range o.values {
if err := strvals.ParseInto(value, base); err != nil { 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 // User specified a value via --set-string
for _, value := range o.stringValues { for _, value := range o.stringValues {
if err := strvals.ParseIntoString(value, base); err != nil { 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. // readFile load a file from stdin, the local directory, or a remote file with a url.

@ -21,6 +21,8 @@ import (
"text/template" "text/template"
"time" "time"
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/chartutil" "k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/hapi/release" "k8s.io/helm/pkg/hapi/release"
) )
@ -51,15 +53,20 @@ func printRelease(out io.Writer, rel *release.Release) error {
if err != nil { if err != nil {
return err return err
} }
cfgStr, err := cfg.YAML() computed, err := cfg.YAML()
if err != nil {
return err
}
config, err := yaml.Marshal(rel.Config)
if err != nil { if err != nil {
return err return err
} }
data := map[string]interface{}{ data := map[string]interface{}{
"Release": rel, "Release": rel,
"Config": string(rel.Config), "Config": string(config),
"ComputedValues": cfgStr, "ComputedValues": computed,
"ReleaseDate": rel.Info.LastDeployed.Format(time.ANSIC), "ReleaseDate": rel.Info.LastDeployed.Format(time.ANSIC),
} }
return tpl(printReleaseTemplate, data, out) return tpl(printReleaseTemplate, data, out)

@ -27,7 +27,6 @@ import (
"time" "time"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/ghodss/yaml"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -167,11 +166,7 @@ func (o *templateOptions) run(out io.Writer) error {
Name: o.releaseName, Name: o.releaseName,
} }
var m map[string]interface{} if err := chartutil.ProcessDependencies(c, config); err != nil {
if err := yaml.Unmarshal(config, &m); err != nil {
return err
}
if err := chartutil.ProcessDependencies(c, m); err != nil {
return err return err
} }

@ -2,7 +2,8 @@ REVISION: 1
RELEASED: Fri Sep 2 22:04:05 1977 RELEASED: Fri Sep 2 22:04:05 1977
CHART: foo-0.1.0-beta.1 CHART: foo-0.1.0-beta.1
USER-SUPPLIED VALUES: USER-SUPPLIED VALUES:
name: "value" name: value
COMPUTED VALUES: COMPUTED VALUES:
name: value name: value

@ -1 +1,2 @@
name: "value" name: value

@ -19,8 +19,6 @@ import (
"log" "log"
"strings" "strings"
"github.com/ghodss/yaml"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/version" "k8s.io/helm/pkg/version"
) )
@ -166,8 +164,7 @@ Loop:
for _, lr := range c.Metadata.Dependencies { for _, lr := range c.Metadata.Dependencies {
lr.Enabled = true lr.Enabled = true
} }
b, _ := yaml.Marshal(v) cvals, err := CoalesceValues(c, v)
cvals, err := CoalesceValues(c, b)
if err != nil { if err != nil {
return err return err
} }
@ -227,7 +224,7 @@ func processImportValues(c *chart.Chart) error {
return nil return nil
} }
// combine chart values and empty config to get Values // combine chart values and empty config to get Values
cvals, err := CoalesceValues(c, []byte{}) cvals, err := CoalesceValues(c, nil)
if err != nil { if err != nil {
return err return err
} }
@ -253,7 +250,7 @@ func processImportValues(c *chart.Chart) error {
continue continue
} }
// create value map from child to be merged into parent // 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: case string:
child := "exports." + iv child := "exports." + iv
outiv = append(outiv, map[string]string{ outiv = append(outiv, map[string]string{
@ -265,7 +262,7 @@ func processImportValues(c *chart.Chart) error {
log.Printf("Warning: ImportValues missing table: %v", err) log.Printf("Warning: ImportValues missing table: %v", err)
continue continue
} }
b = coalesceTables(b, vm.AsMap()) b = CoalesceTables(b, vm.AsMap())
} }
} }
// set our formatted import values // set our formatted import values
@ -273,7 +270,7 @@ func processImportValues(c *chart.Chart) error {
} }
// set the new values // set the new values
c.Values = coalesceTables(b, cvals) c.Values = CoalesceTables(b, cvals)
return nil return nil
} }

@ -142,21 +142,14 @@ func ReadValuesFile(filename string) (Values, error) {
// - Scalar values and arrays are replaced, maps are merged // - 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 // - A chart has access to all of the variables for it, as well as all of
// the values destined for its dependencies. // the values destined for its dependencies.
func CoalesceValues(chrt *chart.Chart, vals []byte) (Values, error) { func CoalesceValues(chrt *chart.Chart, vals map[string]interface{}) (Values, error) {
var err error if vals == nil {
cvals := Values{} vals = make(map[string]interface{})
// 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
}
} }
if _, err := coalesce(chrt, cvals); err != nil { if _, err := coalesce(chrt, vals); err != nil {
return cvals, err 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. // 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 { } else {
// Basically, we reverse order of coalesce here to merge // Basically, we reverse order of coalesce here to merge
// top-down. // top-down.
coalesceTables(vv, destvmap) CoalesceTables(vv, destvmap)
dg[key] = vv dg[key] = vv
continue 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 // Because v has higher precedence than nv, dest values override src
// values. // values.
coalesceTables(dest, src) CoalesceTables(dest, src)
} }
} else { } else {
// If the key is not in v, copy it from nv. // 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. // coalesceTables merges a source map into a destination map.
// //
// dest is considered authoritative. // 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 // Because dest has higher precedence than src, dest values override src
// values. // values.
for key, val := range src { 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 { if innerdst, ok := dst[key]; !ok {
dst[key] = val dst[key] = val
} else if istable(innerdst) { } else if istable(innerdst) {
coalesceTables(innerdst.(map[string]interface{}), val.(map[string]interface{})) CoalesceTables(innerdst.(map[string]interface{}), val.(map[string]interface{}))
} else { } else {
log.Printf("warning: cannot overwrite table with non table for %s (%v)", key, val) log.Printf("warning: cannot overwrite table with non table for %s (%v)", key, val)
} }
continue
} else if dv, ok := dst[key]; ok && istable(dv) { } 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) 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. } else if !ok { // <- ok is still in scope from preceding conditional.
dst[key] = val dst[key] = val
continue
} }
} }
return dst return dst
@ -320,7 +313,7 @@ type ReleaseOptions struct {
// ToRenderValues composes the struct from the data coming from the Releases, Charts and Values files // 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. // 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{}{ top := map[string]interface{}{
"Release": map[string]interface{}{ "Release": map[string]interface{}{

@ -70,7 +70,7 @@ water:
} }
} }
func TestToRenderValuesCaps(t *testing.T) { func TestToRenderValues(t *testing.T) {
chartValues := map[string]interface{}{ chartValues := map[string]interface{}{
"name": "al Rashid", "name": "al Rashid",
@ -80,12 +80,13 @@ func TestToRenderValuesCaps(t *testing.T) {
}, },
} }
overideValues := ` overideValues := map[string]interface{}{
name: Haroun "name": "Haroun",
where: "where": map[string]interface{}{
city: Baghdad "city": "Baghdad",
date: 809 CE "date": "809 CE",
` },
}
c := &chart.Chart{ c := &chart.Chart{
Metadata: &chart.Metadata{Name: "test"}, Metadata: &chart.Metadata{Name: "test"},
@ -98,7 +99,6 @@ where:
c.AddDependency(&chart.Chart{ c.AddDependency(&chart.Chart{
Metadata: &chart.Metadata{Name: "where"}, Metadata: &chart.Metadata{Name: "where"},
}) })
v := []byte(overideValues)
o := ReleaseOptions{ o := ReleaseOptions{
Name: "Seven Voyages", Name: "Seven Voyages",
@ -111,7 +111,7 @@ where:
KubeVersion: &kversion.Info{Major: "1"}, KubeVersion: &kversion.Info{Major: "1"},
} }
res, err := ToRenderValues(c, v, o, caps) res, err := ToRenderValues(c, overideValues, o, caps)
if err != nil { if err != nil {
t.Fatal(err) 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 // ref: http://www.yaml.org/spec/1.2/spec.html#id2803362
var testCoalesceValuesYaml = ` var testCoalesceValuesYaml = []byte(`
top: yup top: yup
bottom: null bottom: null
right: Null right: Null
@ -286,12 +286,17 @@ pequod:
sail: true sail: true
ahab: ahab:
scope: whale scope: whale
` `)
func TestCoalesceValues(t *testing.T) { func TestCoalesceValues(t *testing.T) {
c := loadChart(t, "testdata/moby") 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 { if err != nil {
t.Fatal(err) 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 // What we expect is that anything in dst overrides anything in src, but that
// otherwise the values are coalesced. // otherwise the values are coalesced.
coalesceTables(dst, src) CoalesceTables(dst, src)
if dst["name"] != "Ishmael" { if dst["name"] != "Ishmael" {
t.Errorf("Unexpected name: %s", dst["name"]) t.Errorf("Unexpected name: %s", dst["name"])

@ -100,12 +100,13 @@ func TestRender(t *testing.T) {
Values: map[string]interface{}{"outer": "DEFAULT", "inner": "DEFAULT"}, Values: map[string]interface{}{"outer": "DEFAULT", "inner": "DEFAULT"},
} }
vals := []byte(` vals := map[string]interface{}{
outer: spouter "outer": "spouter",
inner: inn "inner": "inn",
global: "global": map[string]interface{}{
callme: Ishmael "callme": "Ishmael",
`) },
}
e := New() e := New()
v, err := chartutil.CoalesceValues(c, vals) v, err := chartutil.CoalesceValues(c, vals)
@ -302,13 +303,17 @@ func TestRenderNestedValues(t *testing.T) {
} }
outer.AddDependency(inner) outer.AddDependency(inner)
injValues := []byte(` injValues := map[string]interface{}{
what: rosebuds "what": "rosebuds",
herrick: "herrick": map[string]interface{}{
deepest: "deepest": map[string]interface{}{
what: flower "what": "flower",
global: },
when: to-day`) },
"global": map[string]interface{}{
"when": "to-day",
},
}
tmp, err := chartutil.CoalesceValues(outer, injValues) tmp, err := chartutil.CoalesceValues(outer, injValues)
if err != nil { if err != nil {

@ -28,7 +28,7 @@ type Release struct {
Chart *chart.Chart `json:"chart,omitempty"` Chart *chart.Chart `json:"chart,omitempty"`
// Config is the set of extra Values added to the chart. // Config is the set of extra Values added to the chart.
// These values override the default values inside of 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 is the string representation of the rendered template.
Manifest string `json:"manifest,omitempty"` Manifest string `json:"manifest,omitempty"`
// Hooks are all of the hooks declared for this release. // Hooks are all of the hooks declared for this release.

@ -98,7 +98,7 @@ type UpdateReleaseRequest struct {
// Chart is the protobuf representation of a chart. // Chart is the protobuf representation of a chart.
Chart *chart.Chart `json:"chart,omitempty"` Chart *chart.Chart `json:"chart,omitempty"`
// Values is a string containing (unparsed) YAML values. // 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 // dry_run, if true, will run through the release logic, but neither create
DryRun bool `json:"dry_run,omitempty"` DryRun bool `json:"dry_run,omitempty"`
// DisableHooks causes the server to skip running any hooks for the upgrade. // 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 is the protobuf representation of a chart.
Chart *chart.Chart `json:"chart,omitempty"` Chart *chart.Chart `json:"chart,omitempty"`
// Values is a string containing (unparsed) YAML values. // 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 // DryRun, if true, will run through the release logic, but neither create
// a release object nor deploy to Kubernetes. The release object returned // a release object nor deploy to Kubernetes. The release object returned
// in the response will be fake. // in the response will be fake.

@ -17,8 +17,6 @@ limitations under the License.
package helm // import "k8s.io/helm/pkg/helm" package helm // import "k8s.io/helm/pkg/helm"
import ( import (
yaml "gopkg.in/yaml.v2"
"k8s.io/helm/pkg/chart" "k8s.io/helm/pkg/chart"
"k8s.io/helm/pkg/chart/loader" "k8s.io/helm/pkg/chart/loader"
"k8s.io/helm/pkg/chartutil" "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 { if err := reqOpts.runBefore(req); err != nil {
return nil, err return nil, err
} }
var m map[string]interface{} if err := chartutil.ProcessDependencies(req.Chart, req.Values); err != nil {
yaml.Unmarshal(req.Values, &m)
err := chartutil.ProcessDependencies(req.Chart, m)
if err != nil {
return nil, err return nil, err
} }
return c.tiller.InstallRelease(req) 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 { if err := reqOpts.runBefore(req); err != nil {
return nil, err return nil, err
} }
var m map[string]interface{} if err := chartutil.ProcessDependencies(req.Chart, req.Values); err != nil {
if err := yaml.Unmarshal(req.Values, &m); err != nil {
return nil, err
}
if err := chartutil.ProcessDependencies(req.Chart, m); err != nil {
return nil, err return nil, err
} }
return c.tiller.UpdateRelease(req) return c.tiller.UpdateRelease(req)

@ -231,7 +231,7 @@ func ReleaseMock(opts *MockReleaseOptions) *release.Release {
Description: "Release mock", Description: "Release mock",
}, },
Chart: ch, Chart: ch,
Config: []byte(`name: "value"`), Config: map[string]interface{}{"name": "value"},
Version: version, Version: version,
Namespace: namespace, Namespace: namespace,
Hooks: []*release.Hook{ Hooks: []*release.Hook{

@ -101,12 +101,10 @@ func TestInstallRelease_VerifyOptions(t *testing.T) {
var dryRun = true var dryRun = true
var chartName = "alpine" var chartName = "alpine"
var chartPath = filepath.Join(chartsDir, chartName) var chartPath = filepath.Join(chartsDir, chartName)
var overrides = []byte("key1=value1,key2=value2")
// Expected InstallReleaseRequest message // Expected InstallReleaseRequest message
exp := &hapi.InstallReleaseRequest{ exp := &hapi.InstallReleaseRequest{
Chart: loadChart(t, chartName), Chart: loadChart(t, chartName),
Values: overrides,
DryRun: dryRun, DryRun: dryRun,
Name: releaseName, Name: releaseName,
DisableHooks: disableHooks, DisableHooks: disableHooks,
@ -115,7 +113,6 @@ func TestInstallRelease_VerifyOptions(t *testing.T) {
// Options used in InstallRelease // Options used in InstallRelease
ops := []InstallOption{ ops := []InstallOption{
ValueOverrides(overrides),
InstallDryRun(dryRun), InstallDryRun(dryRun),
ReleaseName(releaseName), ReleaseName(releaseName),
InstallReuseName(reuseName), InstallReuseName(reuseName),
@ -191,14 +188,12 @@ func TestUpdateRelease_VerifyOptions(t *testing.T) {
var chartPath = filepath.Join(chartsDir, chartName) var chartPath = filepath.Join(chartsDir, chartName)
var releaseName = "test" var releaseName = "test"
var disableHooks = true var disableHooks = true
var overrides = []byte("key1=value1,key2=value2")
var dryRun = false var dryRun = false
// Expected UpdateReleaseRequest message // Expected UpdateReleaseRequest message
exp := &hapi.UpdateReleaseRequest{ exp := &hapi.UpdateReleaseRequest{
Name: releaseName, Name: releaseName,
Chart: loadChart(t, chartName), Chart: loadChart(t, chartName),
Values: overrides,
DryRun: dryRun, DryRun: dryRun,
DisableHooks: disableHooks, DisableHooks: disableHooks,
} }
@ -206,7 +201,6 @@ func TestUpdateRelease_VerifyOptions(t *testing.T) {
// Options used in UpdateRelease // Options used in UpdateRelease
ops := []UpdateOption{ ops := []UpdateOption{
UpgradeDryRun(dryRun), UpgradeDryRun(dryRun),
UpdateValueOverrides(overrides),
UpgradeDisableHooks(disableHooks), UpgradeDisableHooks(disableHooks),
} }

@ -143,7 +143,7 @@ func ReleaseListStatuses(statuses []release.ReleaseStatus) ReleaseListOption {
type InstallOption func(*options) type InstallOption func(*options)
// ValueOverrides specifies a list of values to include when installing. // 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) { return func(opts *options) {
opts.instReq.Values = raw opts.instReq.Values = raw
} }
@ -220,7 +220,7 @@ func RollbackWait(wait bool) RollbackOption {
} }
// UpdateValueOverrides specifies a list of values to include when upgrading // 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) { return func(opts *options) {
opts.updateReq.Values = raw opts.updateReq.Values = raw
} }

@ -24,7 +24,7 @@ import (
) )
// All runs all of the available linters on the given base directory. // 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 // Using abs path to get directory context
chartDir, _ := filepath.Abs(basedir) chartDir, _ := filepath.Abs(basedir)

@ -24,7 +24,7 @@ import (
"testing" "testing"
) )
var values = []byte{} var values map[string]interface{}
const namespace = "testNamespace" const namespace = "testNamespace"
const strict = false const strict = false

@ -30,7 +30,7 @@ import (
) )
// Templates lints the templates in the Linter. // 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/" path := "templates/"
templatesPath := filepath.Join(linter.ChartDir, path) templatesPath := filepath.Join(linter.ChartDir, path)
@ -56,13 +56,8 @@ func Templates(linter *support.Linter, values []byte, namespace string, strict b
if err != nil { if err != nil {
return return
} }
// convert our values back into config
yvals, err := yaml.Marshal(cvals)
if err != nil {
return
}
caps := chartutil.DefaultCapabilities caps := chartutil.DefaultCapabilities
valuesToRender, err := chartutil.ToRenderValues(chart, yvals, options, caps) valuesToRender, err := chartutil.ToRenderValues(chart, cvals, options, caps)
if err != nil { if err != nil {
// FIXME: This seems to generate a duplicate, but I can't find where the first // FIXME: This seems to generate a duplicate, but I can't find where the first
// error is coming from. // error is coming from.

@ -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 namespace = "testNamespace"
const strict = false const strict = false

@ -33,7 +33,7 @@ var releases = []*rspb.Release{
} }
func tsRelease(name string, vers int, dur time.Duration, status rspb.ReleaseStatus) *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} info := &rspb.Info{Status: status, LastDeployed: tmsp}
return &rspb.Release{ return &rspb.Release{
Name: name, Name: name,

@ -25,7 +25,6 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/discovery" "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") return errors.Wrap(err, "failed to rebuild old values")
} }
// merge new values with current req.Values = chartutil.CoalesceTables(current.Config, req.Values)
b := append(current.Config, '\n')
req.Values = append(b, req.Values...)
req.Chart.Values = oldVals 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 return nil
} }
// If req.Values is empty, but current.Config is not, copy current into the if len(req.Values) == 0 && len(current.Config) > 0 {
// request.
if (len(req.Values) == 0 || bytes.Equal(req.Values, []byte("{}\n"))) &&
len(current.Config) > 0 &&
!bytes.Equal(current.Config, []byte("{}\n")) {
s.Log("copying values from %s (v%d) to new release.", current.Name, current.Version) s.Log("copying values from %s (v%d) to new release.", current.Name, current.Version)
req.Values = current.Config req.Values = current.Config
} }

@ -239,7 +239,7 @@ func namedReleaseStub(name string, status release.ReleaseStatus) *release.Releas
Description: "Named Release Stub", Description: "Named Release Stub",
}, },
Chart: chartStub(), Chart: chartStub(),
Config: []byte(`name: value`), Config: map[string]interface{}{"name": "value"},
Version: 1, Version: 1,
Hooks: []*release.Hook{ Hooks: []*release.Hook{
{ {
@ -379,7 +379,7 @@ func releaseWithKeepStub(rlsName string) *release.Release {
Status: release.StatusDeployed, Status: release.StatusDeployed,
}, },
Chart: ch, Chart: ch,
Config: []byte(`name: value`), Config: map[string]interface{}{"name": "value"},
Version: 1, Version: 1,
Manifest: manifestWithKeep, Manifest: manifestWithKeep,
} }

@ -17,7 +17,6 @@ limitations under the License.
package tiller package tiller
import ( import (
"bytes"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
@ -82,7 +81,7 @@ func TestUpdateRelease(t *testing.T) {
if res.Config == nil { if res.Config == nil {
t.Errorf("Got release without config: %#v", res) 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) 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)}, {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") 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) t.Fatalf("Failed updated: %s", err)
} }
expect := "foo: bar" if rel.Config != nil && rel.Config["foo"] != "bar" {
if rel.Config != nil && !bytes.Equal(rel.Config, []byte(expect)) { t.Errorf("Expected chart value 'foo' = 'bar', got %s", rel.Config)
t.Errorf("Expected chart values to be %q, got %q", expect, string(rel.Config))
} }
req = &hapi.UpdateReleaseRequest{ req = &hapi.UpdateReleaseRequest{
@ -179,7 +177,7 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
}, },
}, },
Values: []byte("foo2: bar2"), Values: map[string]interface{}{"foo2": "bar2"},
ReuseValues: true, ReuseValues: true,
} }
@ -190,9 +188,8 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
} }
// This should have the newly-passed overrides. // This should have the newly-passed overrides.
expect = "foo: bar\nfoo2: bar2\n" if len(rel.Config) != 2 && rel.Config["foo2"] != "bar2" {
if rel.Config != nil && !bytes.Equal(rel.Config, []byte(expect)) { t.Errorf("Expected chart value 'foo2' = 'bar2', got %s", rel.Config)
t.Errorf("Expected request config to be %q, got %q", expect, string(rel.Config))
} }
req = &hapi.UpdateReleaseRequest{ req = &hapi.UpdateReleaseRequest{
@ -204,7 +201,7 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)}, {Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
}, },
}, },
Values: []byte("foo: baz"), Values: map[string]interface{}{"foo": "baz"},
ReuseValues: true, ReuseValues: true,
} }
@ -213,9 +210,8 @@ func TestUpdateRelease_ComplexReuseValues(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed updated: %s", err) t.Fatalf("Failed updated: %s", err)
} }
expect = "foo: baz\nfoo2: bar2\n" if len(rel.Config) != 2 && rel.Config["foo"] != "baz" {
if rel.Config != nil && !bytes.Equal(rel.Config, []byte(expect)) { t.Errorf("Expected chart value 'foo' = 'baz', got %s", rel.Config)
t.Errorf("Expected chart values to be %q, got %q", expect, rel.Config)
} }
} }
@ -235,7 +231,7 @@ func TestUpdateRelease_ReuseValues(t *testing.T) {
// Since reuseValues is set, this should get ignored. // Since reuseValues is set, this should get ignored.
Values: map[string]interface{}{"foo": "bar"}, Values: map[string]interface{}{"foo": "bar"},
}, },
Values: []byte("name2: val2"), Values: map[string]interface{}{"name2": "val2"},
ReuseValues: true, ReuseValues: true,
} }
res, err := rs.UpdateRelease(req) 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() // 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" 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) t.Errorf("Expected request config to be %q, got %q", expect, res.Config)
} }
compareStoredAndReturnedRelease(t, *rs, res) compareStoredAndReturnedRelease(t, *rs, res)

Loading…
Cancel
Save