@ -172,9 +172,7 @@ func CoalesceValues(chrt *chart.Chart, vals *chart.Config) (Values, error) {
}
}
}
}
var err error
return coalesceDeps ( chrt , cvals )
cvals , err = coalesceDeps ( chrt , cvals )
return cvals , err
}
}
// 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.
@ -186,8 +184,7 @@ func coalesce(ch *chart.Chart, dest map[string]interface{}) (map[string]interfac
if err != nil {
if err != nil {
return dest , err
return dest , err
}
}
coalesceDeps ( ch , dest )
return coalesceDeps ( ch , dest )
return dest , nil
}
}
// coalesceDeps coalesces the dependencies of the given chart.
// coalesceDeps coalesces the dependencies of the given chart.
@ -203,7 +200,7 @@ func coalesceDeps(chrt *chart.Chart, dest map[string]interface{}) (map[string]in
dvmap := dv . ( map [ string ] interface { } )
dvmap := dv . ( map [ string ] interface { } )
// Get globals out of dest and merge them into dvmap.
// Get globals out of dest and merge them into dvmap.
coalesceGlobals ( dvmap , dest , chrt . Metadata . Name )
dvmap = coalesceGlobals ( dvmap , dest , chrt . Metadata . Name )
var err error
var err error
// Now coalesce the rest of the values.
// Now coalesce the rest of the values.
@ -236,45 +233,20 @@ func coalesceGlobals(dest, src map[string]interface{}, chartName string) map[str
return dg
return dg
}
}
rv := make ( map [ string ] interface { } )
for k , v := range dest {
rv [ k ] = v
}
// EXPERIMENTAL: In the past, we have disallowed globals to test tables. This
// EXPERIMENTAL: In the past, we have disallowed globals to test tables. This
// reverses that decision. It may somehow be possible to introduce a loop
// reverses that decision. It may somehow be possible to introduce a loop
// here, but I haven't found a way. So for the time being, let's allow
// here, but I haven't found a way. So for the time being, let's allow
// tables in globals.
// tables in globals.
for key , val := range sg {
if istable ( val ) {
vv := copyMap ( val . ( map [ string ] interface { } ) )
if destv , ok := dg [ key ] ; ok {
if destvmap , ok := destv . ( map [ string ] interface { } ) ; ok {
// 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 , chartName )
rv [ GlobalKey ] = coalesceTables ( sg , dg , chartName )
dg [ key ] = vv
return rv
continue
} else {
log . Printf ( "Warning: For chart '%s', cannot merge map onto non-map for key '%q'. Skipping." , chartName , key )
}
} else {
// Here there is no merge. We're just adding.
dg [ key ] = vv
}
} else if dv , ok := dg [ key ] ; ok && istable ( dv ) {
// It's not clear if this condition can actually ever trigger.
log . Printf ( "Warning: For chart '%s', key '%s' is a table. Skipping." , chartName , key )
continue
}
// TODO: Do we need to do any additional checking on the value?
dg [ key ] = val
}
dest [ GlobalKey ] = dg
return dest
}
func copyMap ( src map [ string ] interface { } ) map [ string ] interface { } {
dest := make ( map [ string ] interface { } , len ( src ) )
for k , v := range src {
dest [ k ] = v
}
return dest
}
}
// coalesceValues builds up a values map for a particular chart.
// coalesceValues builds up a values map for a particular chart.
@ -294,30 +266,7 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf
return v , fmt . Errorf ( "Error: Reading chart '%s' default values (%s): %s" , c . Metadata . Name , c . Values . Raw , err )
return v , fmt . Errorf ( "Error: Reading chart '%s' default values (%s): %s" , c . Metadata . Name , c . Values . Raw , err )
}
}
for key , val := range nv {
return coalesceTables ( v , nv . AsMap ( ) , c . Metadata . Name ) , nil
if value , ok := v [ key ] ; ok {
if value == nil {
// When the YAML value is null, we remove the value's key.
// This allows Helm's various sources of values (value files or --set) to
// remove incompatible keys from any previous chart, file, or set values.
delete ( v , key )
} else if dest , ok := value . ( map [ string ] interface { } ) ; ok {
// if v[key] is a table, merge nv's val table into v[key].
src , ok := val . ( map [ string ] interface { } )
if ! ok {
log . Printf ( "Warning: Building values map for chart '%s'. Skipped value (%+v) for '%s', as it is not a table." , c . Metadata . Name , src , key )
continue
}
// Because v has higher precedence than nv, dest values override src
// values.
coalesceTables ( dest , src , c . Metadata . Name )
}
} else {
// If the key is not in v, copy it from nv.
v [ key ] = val
}
}
return v , nil
}
}
// coalesceTables merges a source map into a destination map.
// coalesceTables merges a source map into a destination map.
@ -326,36 +275,50 @@ func coalesceValues(c *chart.Chart, v map[string]interface{}) (map[string]interf
func coalesceTables ( dst , src map [ string ] interface { } , chartName string ) map [ string ] interface { } {
func coalesceTables ( dst , src map [ string ] interface { } , chartName string ) map [ string ] interface { } {
// Because dest has higher precedence than src, dest values override src
// Because dest has higher precedence than src, dest values override src
// values.
// values.
rv := make ( map [ string ] interface { } )
for key , val := range src {
for key , val := range src {
dv , ok := dst [ key ]
dv , ok := dst [ key ]
if ok && dv == nil {
if ! ok { // if not in dst, then copy from src
// skip here, we delete at end
rv [ key ] = val
continue
continue
}
}
if istable ( val ) {
if dv == nil { // if set to nil in dst, then ignore
if ! ok {
// When the YAML value is null, we skip the value's key.
dst [ key ] = val
// This allows Helm's various sources of values (value files or --set) to
} else if istable ( dv ) {
// remove incompatible keys from any previous chart, file, or set values.
coalesceTables ( dv . ( map [ string ] interface { } ) , val . ( map [ string ] interface { } ) , chartName )
} else {
log . Printf ( "Warning: Merging destination map for chart '%s'. Cannot overwrite table item '%s', with non table value: %v" , chartName , key , val )
}
continue
continue
} else if ok && istable ( dv ) {
}
srcTable , srcIsTable := val . ( map [ string ] interface { } )
dstTable , dstIsTable := dv . ( map [ string ] interface { } )
switch {
case srcIsTable && dstIsTable : // both tables, we coalesce
rv [ key ] = coalesceTables ( dstTable , srcTable , chartName )
case srcIsTable && ! dstIsTable :
log . Printf ( "Warning: Merging destination map for chart '%s'. Cannot overwrite table item '%s', with non table value: %v" , chartName , key , val )
// despite message in warning, we appear to do exactly that, and do take the dst value
rv [ key ] = dv
case ! srcIsTable && dstIsTable :
log . Printf ( "Warning: Merging destination map for chart '%s'. The destination item '%s' is a table and ignoring the source '%s' as it has a non-table value of: %v" , chartName , key , key , val )
log . Printf ( "Warning: Merging destination map for chart '%s'. The destination item '%s' is a table and ignoring the source '%s' as it has a non-table value of: %v" , chartName , key , key , val )
continue
rv [ key ] = dv
} else if ! ok { // <- ok is still in scope from preceding conditional.
default : // neither are tables, simply take the dst value
dst [ key ] = val
rv [ key ] = dv
continue
}
}
}
}
// never return a nil value, rather delete the key
for k , v := range dst {
// do we have anything in dst that wasn't processed already that we need to copy across?
if v == nil {
for key , val := range dst {
delete ( dst , k )
if val == nil {
continue
}
}
_ , ok := rv [ key ]
if ! ok {
rv [ key ] = val
}
}
return dst
}
return rv
}
}
// ReleaseOptions represents the additional release options needed
// ReleaseOptions represents the additional release options needed