fix(export-values): broken chaining

Refactor export-values/import-values logic. Now export-values expand from
the top chart to the most nested ones, unlike import-values that have
it reversed (import-values flow didn't change). Now export-values can be
chained and passed through multiple charts, where you define
export-values directive in each chart of the chain. Import-values
already work like that.

Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
pull/10059/head
Ilya Lesikov 3 years ago
parent 23ca433c31
commit 80edf0b04a

@ -217,27 +217,57 @@ func set(path []string, data map[string]interface{}) map[string]interface{} {
return cur return cur
} }
// processImportExportValues merges values between child and parent based on the chart's dependencies' ImportValues // processImportValues merges Values from dependent charts to the current chart based on ImportValues field.
// and ExportValues fields. func processImportValues(c *chart.Chart) error {
func processImportExportValues(c *chart.Chart) error {
if c.Metadata.Dependencies == nil { if c.Metadata.Dependencies == nil {
return nil return nil
} }
// combine chart values and empty config to get Values
cvals, err := CoalesceValues(c, nil) cvals, err := CoalesceValues(c, nil)
if err != nil { if err != nil {
return err return err
} }
b := make(map[string]interface{})
// For each dependency export values from parent or import values from child if export-values or import-values importedValuesMap := make(map[string]interface{})
// specified. for _, r := range c.Metadata.Dependencies {
importedValuesMap = CoalesceTables(importedValuesMap, getImportedValues(r, cvals))
}
c.Values = CoalesceTables(importedValuesMap, cvals)
return nil
}
// processExportValues merges Values from current chart to the child charts based on ExportValues field.
func processExportValues(c *chart.Chart) error {
if c.Metadata.Dependencies == nil {
return nil
}
for _, r := range c.Metadata.Dependencies { for _, r := range c.Metadata.Dependencies {
b = CoalesceTables(b, getExportedValues(c, r, cvals))
b = CoalesceTables(b, getImportedValues(r, cvals)) // combine chart values and empty config to get Values
pvals, err := CoalesceValues(c, nil)
if err != nil {
return err
}
var rc *chart.Chart
for _, dep := range c.Dependencies() {
if dep.Name() == r.Name {
rc = dep
}
}
cvals, err := CoalesceValues(rc, nil)
if err != nil {
return err
} }
// set the new values rc.Values = CoalesceTables(getExportedValues(c.Name(), r, pvals), cvals)
c.Values = CoalesceTables(cvals, b)
return nil
}
return nil return nil
} }
@ -285,13 +315,13 @@ func getImportedValues(r *chart.Dependency, cvals Values) map[string]interface{}
} }
// Generates values map which is exported from parent to specified child via export-values. // Generates values map which is exported from parent to specified child via export-values.
func getExportedValues(c *chart.Chart, r *chart.Dependency, cvals Values) map[string]interface{} { func getExportedValues(parentName string, r *chart.Dependency, pvals Values) map[string]interface{} {
b := make(map[string]interface{}) b := make(map[string]interface{})
var exportValues []interface{} var exportValues []interface{}
for _, rev := range r.ExportValues { for _, rev := range r.ExportValues {
parent, child, err := parseExportValues(rev, r) parent, child, err := parseExportValues(rev)
if err != nil { if err != nil {
log.Printf("Warning: invalid ExportValues defined in chart %q for its dependency %q: %s", c.Name(), r.Name, err) log.Printf("Warning: invalid ExportValues defined in chart %q for its dependency %q: %s", parentName, r.Name, err)
continue continue
} }
@ -302,28 +332,31 @@ func getExportedValues(c *chart.Chart, r *chart.Dependency, cvals Values) map[st
var childValMap map[string]interface{} var childValMap map[string]interface{}
// try to get parent table // try to get parent table
vm, err := cvals.Table(parent) vm, err := pvals.Table(parent)
if err == nil { if err == nil {
if child == "" {
childValMap = vm.AsMap()
} else {
childValMap = pathToMap(child, vm.AsMap()) childValMap = pathToMap(child, vm.AsMap())
}
} else { } else {
// still it might be not a table but a simple value // still it might be not a table but a simple value
value, e := cvals.PathValue(parent) value, e := pvals.PathValue(parent)
if e != nil { if e != nil {
log.Printf("Warning: ExportValues defined in chart %q for its dependency %q can't get the parent path: %v", c.Name(), r.Name, err) log.Printf("Warning: ExportValues defined in chart %q for its dependency %q can't get the parent path: %s", parentName, r.Name, err.Error())
continue continue
} }
childSlice := parsePath(child) childSlice := parsePath(child)
childLen := len(childSlice) if len(childSlice) == 1 && childSlice[0] == "" {
if childLen == 1 { log.Printf("Warning: in ExportValues defined in chart %q for its dependency %q you are trying to assign a primitive data type (string, int, etc) to the root of your dependent chart values. We will ignore this ExportValues, because this is most likely not what you want. Fix the ExportValues to hide this warning.", parentName, r.Name)
log.Printf("Warning: in ExportValues defined in chart %q for its dependency %q you are trying to assign a primitive data type (string, int, etc) to the root of your dependent chart values. We will ignore this ExportValues, because this is most likely not what you want. Fix the ExportValues to hide this warning.", c.Name(), r.Name)
continue continue
} }
childValMap = pathToMap( childValMap = pathToMap(
joinPath(childSlice[:childLen-1]...), joinPath(childSlice[:len(childSlice)-1]...),
map[string]interface{}{ map[string]interface{}{
childSlice[childLen-1]: value, childSlice[len(childSlice)-1]: value,
}, },
) )
} }
@ -338,7 +371,7 @@ func getExportedValues(c *chart.Chart, r *chart.Dependency, cvals Values) map[st
} }
// Parse and validate export-values. // Parse and validate export-values.
func parseExportValues(rev interface{}, r *chart.Dependency) (string, string, error) { func parseExportValues(rev interface{}) (string, string, error) {
var parent, child string var parent, child string
switch ev := rev.(type) { switch ev := rev.(type) {
@ -348,30 +381,30 @@ func parseExportValues(rev interface{}, r *chart.Dependency) (string, string, er
if !ok { if !ok {
return "", "", fmt.Errorf("parent can't be of null type") return "", "", fmt.Errorf("parent can't be of null type")
} }
child, ok = ev["child"].(string) child, ok = ev["child"].(string)
if !ok { if !ok {
return "", "", fmt.Errorf("child can't be of null type") return "", "", fmt.Errorf("child can't be of null type")
} }
switch parent { if strings.TrimSpace(parent) == "" || strings.TrimSpace(parent) == "." {
case "", ".":
return "", "", fmt.Errorf("parent %q is not allowed", parent) return "", "", fmt.Errorf("parent %q is not allowed", parent)
} }
switch child { parent = strings.TrimSpace(parent)
case "", ".": child = strings.TrimSpace(child)
child = r.Name
default: if child == "." {
child = r.Name + "." + child child = ""
} }
case string: case string:
switch parent = ev; parent { switch parent = strings.TrimSpace(ev); parent {
case "", ".": case "", ".":
parent = "exports" parent = "exports"
default: default:
parent = "exports." + parent parent = "exports." + parent
} }
child = r.Name child = ""
default: default:
return "", "", fmt.Errorf("invalid type of ExportValues") return "", "", fmt.Errorf("invalid type of ExportValues")
} }
@ -382,11 +415,16 @@ func parseExportValues(rev interface{}, r *chart.Dependency) (string, string, er
// processDependencyImportExportValues imports (child to parent) and/or exports (parent to child) values if // processDependencyImportExportValues imports (child to parent) and/or exports (parent to child) values if
// import-values or export-values specified for the dependency. // import-values or export-values specified for the dependency.
func processDependencyImportExportValues(c *chart.Chart) error { func processDependencyImportExportValues(c *chart.Chart) error {
if err := processExportValues(c); err != nil {
return err
}
for _, d := range c.Dependencies() { for _, d := range c.Dependencies() {
// recurse // recurse
if err := processDependencyImportExportValues(d); err != nil { if err := processDependencyImportExportValues(d); err != nil {
return err return err
} }
} }
return processImportExportValues(c)
return processImportValues(c)
} }

Loading…
Cancel
Save