|
|
@ -43,6 +43,36 @@ func concatPrefix(a, b string) string {
|
|
|
|
// - 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 map[string]interface{}) (Values, error) {
|
|
|
|
func CoalesceValues(chrt *chart.Chart, vals map[string]interface{}) (Values, error) {
|
|
|
|
|
|
|
|
valsCopy, err := copyValues(vals)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return vals, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return coalesce(log.Printf, chrt, valsCopy, "", false)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// MergeValues is used to merge the values in a chart and its subcharts. This
|
|
|
|
|
|
|
|
// is different from Coalescing as nil/null values are preserved.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Values are coalesced together using the following rules:
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// - Values in a higher level chart always override values in a lower-level
|
|
|
|
|
|
|
|
// dependency chart
|
|
|
|
|
|
|
|
// - 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.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Retaining Nils is useful when processes early in a Helm action or business
|
|
|
|
|
|
|
|
// logic need to retain them for when Coalescing will happen again later in the
|
|
|
|
|
|
|
|
// business logic.
|
|
|
|
|
|
|
|
func MergeValues(chrt *chart.Chart, vals map[string]interface{}) (Values, error) {
|
|
|
|
|
|
|
|
valsCopy, err := copyValues(vals)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return vals, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return coalesce(log.Printf, chrt, valsCopy, "", true)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func copyValues(vals map[string]interface{}) (Values, error) {
|
|
|
|
v, err := copystructure.Copy(vals)
|
|
|
|
v, err := copystructure.Copy(vals)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return vals, err
|
|
|
|
return vals, err
|
|
|
@ -53,21 +83,26 @@ func CoalesceValues(chrt *chart.Chart, vals map[string]interface{}) (Values, err
|
|
|
|
if valsCopy == nil {
|
|
|
|
if valsCopy == nil {
|
|
|
|
valsCopy = make(map[string]interface{})
|
|
|
|
valsCopy = make(map[string]interface{})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return coalesce(log.Printf, chrt, valsCopy, "")
|
|
|
|
|
|
|
|
|
|
|
|
return valsCopy, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type printFn func(format string, v ...interface{})
|
|
|
|
type printFn func(format string, v ...interface{})
|
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// This is a helper function for CoalesceValues.
|
|
|
|
// This is a helper function for CoalesceValues and MergeValues.
|
|
|
|
func coalesce(printf printFn, ch *chart.Chart, dest map[string]interface{}, prefix string) (map[string]interface{}, error) {
|
|
|
|
//
|
|
|
|
coalesceValues(printf, ch, dest, prefix)
|
|
|
|
// Note, the merge argument specifies whether this is being used by MergeValues
|
|
|
|
return coalesceDeps(printf, ch, dest, prefix)
|
|
|
|
// or CoalesceValues. Coalescing removes null values and their keys in some
|
|
|
|
|
|
|
|
// situations while merging keeps the null values.
|
|
|
|
|
|
|
|
func coalesce(printf printFn, ch *chart.Chart, dest map[string]interface{}, prefix string, merge bool) (map[string]interface{}, error) {
|
|
|
|
|
|
|
|
coalesceValues(printf, ch, dest, prefix, merge)
|
|
|
|
|
|
|
|
return coalesceDeps(printf, ch, dest, prefix, merge)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// coalesceDeps coalesces the dependencies of the given chart.
|
|
|
|
// coalesceDeps coalesces the dependencies of the given chart.
|
|
|
|
func coalesceDeps(printf printFn, chrt *chart.Chart, dest map[string]interface{}, prefix string) (map[string]interface{}, error) {
|
|
|
|
func coalesceDeps(printf printFn, chrt *chart.Chart, dest map[string]interface{}, prefix string, merge bool) (map[string]interface{}, error) {
|
|
|
|
for _, subchart := range chrt.Dependencies() {
|
|
|
|
for _, subchart := range chrt.Dependencies() {
|
|
|
|
if c, ok := dest[subchart.Name()]; !ok {
|
|
|
|
if c, ok := dest[subchart.Name()]; !ok {
|
|
|
|
// If dest doesn't already have the key, create it.
|
|
|
|
// If dest doesn't already have the key, create it.
|
|
|
@ -78,13 +113,11 @@ func coalesceDeps(printf printFn, chrt *chart.Chart, dest map[string]interface{}
|
|
|
|
if dv, ok := dest[subchart.Name()]; ok {
|
|
|
|
if dv, ok := dest[subchart.Name()]; ok {
|
|
|
|
dvmap := dv.(map[string]interface{})
|
|
|
|
dvmap := dv.(map[string]interface{})
|
|
|
|
subPrefix := concatPrefix(prefix, chrt.Metadata.Name)
|
|
|
|
subPrefix := concatPrefix(prefix, chrt.Metadata.Name)
|
|
|
|
|
|
|
|
|
|
|
|
// Get globals out of dest and merge them into dvmap.
|
|
|
|
// Get globals out of dest and merge them into dvmap.
|
|
|
|
coalesceGlobals(printf, dvmap, dest, subPrefix)
|
|
|
|
coalesceGlobals(printf, dvmap, dest, subPrefix, merge)
|
|
|
|
|
|
|
|
|
|
|
|
// Now coalesce the rest of the values.
|
|
|
|
// Now coalesce the rest of the values.
|
|
|
|
var err error
|
|
|
|
var err error
|
|
|
|
dest[subchart.Name()], err = coalesce(printf, subchart, dvmap, subPrefix)
|
|
|
|
dest[subchart.Name()], err = coalesce(printf, subchart, dvmap, subPrefix, merge)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return dest, err
|
|
|
|
return dest, err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -96,7 +129,7 @@ func coalesceDeps(printf printFn, chrt *chart.Chart, dest map[string]interface{}
|
|
|
|
// coalesceGlobals copies the globals out of src and merges them into dest.
|
|
|
|
// coalesceGlobals copies the globals out of src and merges them into dest.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// For convenience, returns dest.
|
|
|
|
// For convenience, returns dest.
|
|
|
|
func coalesceGlobals(printf printFn, dest, src map[string]interface{}, prefix string) {
|
|
|
|
func coalesceGlobals(printf printFn, dest, src map[string]interface{}, prefix string, merge bool) {
|
|
|
|
var dg, sg map[string]interface{}
|
|
|
|
var dg, sg map[string]interface{}
|
|
|
|
|
|
|
|
|
|
|
|
if destglob, ok := dest[GlobalKey]; !ok {
|
|
|
|
if destglob, ok := dest[GlobalKey]; !ok {
|
|
|
@ -130,7 +163,10 @@ func coalesceGlobals(printf printFn, dest, src map[string]interface{}, prefix st
|
|
|
|
// Basically, we reverse order of coalesce here to merge
|
|
|
|
// Basically, we reverse order of coalesce here to merge
|
|
|
|
// top-down.
|
|
|
|
// top-down.
|
|
|
|
subPrefix := concatPrefix(prefix, key)
|
|
|
|
subPrefix := concatPrefix(prefix, key)
|
|
|
|
coalesceTablesFullKey(printf, vv, destvmap, subPrefix)
|
|
|
|
// In this location coalesceTablesFullKey should always have
|
|
|
|
|
|
|
|
// merge set to true. The output of coalesceGlobals is run
|
|
|
|
|
|
|
|
// through coalesce where any nils will be removed.
|
|
|
|
|
|
|
|
coalesceTablesFullKey(printf, vv, destvmap, subPrefix, true)
|
|
|
|
dg[key] = vv
|
|
|
|
dg[key] = vv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -156,12 +192,38 @@ func copyMap(src map[string]interface{}) map[string]interface{} {
|
|
|
|
// coalesceValues builds up a values map for a particular chart.
|
|
|
|
// coalesceValues builds up a values map for a particular chart.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Values in v will override the values in the chart.
|
|
|
|
// Values in v will override the values in the chart.
|
|
|
|
func coalesceValues(printf printFn, c *chart.Chart, v map[string]interface{}, prefix string) {
|
|
|
|
func coalesceValues(printf printFn, c *chart.Chart, v map[string]interface{}, prefix string, merge bool) {
|
|
|
|
subPrefix := concatPrefix(prefix, c.Metadata.Name)
|
|
|
|
subPrefix := concatPrefix(prefix, c.Metadata.Name)
|
|
|
|
for key, val := range c.Values {
|
|
|
|
|
|
|
|
|
|
|
|
// Using c.Values directly when coalescing a table can cause problems where
|
|
|
|
|
|
|
|
// the original c.Values is altered. Creating a deep copy stops the problem.
|
|
|
|
|
|
|
|
// This section is fault-tolerant as there is no ability to return an error.
|
|
|
|
|
|
|
|
valuesCopy, err := copystructure.Copy(c.Values)
|
|
|
|
|
|
|
|
var vc map[string]interface{}
|
|
|
|
|
|
|
|
var ok bool
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
// If there is an error something is wrong with copying c.Values it
|
|
|
|
|
|
|
|
// means there is a problem in the deep copying package or something
|
|
|
|
|
|
|
|
// wrong with c.Values. In this case we will use c.Values and report
|
|
|
|
|
|
|
|
// an error.
|
|
|
|
|
|
|
|
printf("warning: unable to copy values, err: %s", err)
|
|
|
|
|
|
|
|
vc = c.Values
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
vc, ok = valuesCopy.(map[string]interface{})
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
|
|
// c.Values has a map[string]interface{} structure. If the copy of
|
|
|
|
|
|
|
|
// it cannot be treated as map[string]interface{} there is something
|
|
|
|
|
|
|
|
// strangely wrong. Log it and use c.Values
|
|
|
|
|
|
|
|
printf("warning: unable to convert values copy to values type")
|
|
|
|
|
|
|
|
vc = c.Values
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for key, val := range vc {
|
|
|
|
if value, ok := v[key]; ok {
|
|
|
|
if value, ok := v[key]; ok {
|
|
|
|
if value == nil {
|
|
|
|
if value == nil && !merge {
|
|
|
|
// When the YAML value is null, we remove the value's key.
|
|
|
|
// When the YAML value is null and we are coalescing instead of
|
|
|
|
|
|
|
|
// merging, we remove the value's key.
|
|
|
|
// This allows Helm's various sources of values (value files or --set) to
|
|
|
|
// This allows Helm's various sources of values (value files or --set) to
|
|
|
|
// remove incompatible keys from any previous chart, file, or set values.
|
|
|
|
// remove incompatible keys from any previous chart, file, or set values.
|
|
|
|
delete(v, key)
|
|
|
|
delete(v, key)
|
|
|
@ -177,7 +239,7 @@ func coalesceValues(printf printFn, c *chart.Chart, v map[string]interface{}, pr
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// Because v has higher precedence than nv, dest values override src
|
|
|
|
// Because v has higher precedence than nv, dest values override src
|
|
|
|
// values.
|
|
|
|
// values.
|
|
|
|
coalesceTablesFullKey(printf, dest, src, concatPrefix(subPrefix, key))
|
|
|
|
coalesceTablesFullKey(printf, dest, src, concatPrefix(subPrefix, key), merge)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -191,13 +253,17 @@ func coalesceValues(printf printFn, c *chart.Chart, v map[string]interface{}, pr
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// 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{} {
|
|
|
|
return coalesceTablesFullKey(log.Printf, dst, src, "")
|
|
|
|
return coalesceTablesFullKey(log.Printf, dst, src, "", false)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func MergeTables(dst, src map[string]interface{}) map[string]interface{} {
|
|
|
|
|
|
|
|
return coalesceTablesFullKey(log.Printf, dst, src, "", true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// coalesceTablesFullKey merges a source map into a destination map.
|
|
|
|
// coalesceTablesFullKey merges a source map into a destination map.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// dest is considered authoritative.
|
|
|
|
// dest is considered authoritative.
|
|
|
|
func coalesceTablesFullKey(printf printFn, dst, src map[string]interface{}, prefix string) map[string]interface{} {
|
|
|
|
func coalesceTablesFullKey(printf printFn, dst, src map[string]interface{}, prefix string, merge bool) map[string]interface{} {
|
|
|
|
// When --reuse-values is set but there are no modifications yet, return new values
|
|
|
|
// When --reuse-values is set but there are no modifications yet, return new values
|
|
|
|
if src == nil {
|
|
|
|
if src == nil {
|
|
|
|
return dst
|
|
|
|
return dst
|
|
|
@ -209,13 +275,13 @@ func coalesceTablesFullKey(printf printFn, dst, src map[string]interface{}, pref
|
|
|
|
// values.
|
|
|
|
// values.
|
|
|
|
for key, val := range src {
|
|
|
|
for key, val := range src {
|
|
|
|
fullkey := concatPrefix(prefix, key)
|
|
|
|
fullkey := concatPrefix(prefix, key)
|
|
|
|
if dv, ok := dst[key]; ok && dv == nil {
|
|
|
|
if dv, ok := dst[key]; ok && !merge && dv == nil {
|
|
|
|
delete(dst, key)
|
|
|
|
delete(dst, key)
|
|
|
|
} else if !ok {
|
|
|
|
} else if !ok {
|
|
|
|
dst[key] = val
|
|
|
|
dst[key] = val
|
|
|
|
} else if istable(val) {
|
|
|
|
} else if istable(val) {
|
|
|
|
if istable(dv) {
|
|
|
|
if istable(dv) {
|
|
|
|
coalesceTablesFullKey(printf, dv.(map[string]interface{}), val.(map[string]interface{}), fullkey)
|
|
|
|
coalesceTablesFullKey(printf, dv.(map[string]interface{}), val.(map[string]interface{}), fullkey, merge)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
printf("warning: cannot overwrite table with non table for %s (%v)", fullkey, val)
|
|
|
|
printf("warning: cannot overwrite table with non table for %s (%v)", fullkey, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|