Commit 7ea4d8c7 authored by Justin Scott's avatar Justin Scott

Refactor so parent's values win

parent 4a5721fb
...@@ -302,6 +302,98 @@ helm install --set tags.front-end=true --set subchart2.enabled=false ...@@ -302,6 +302,98 @@ helm install --set tags.front-end=true --set subchart2.enabled=false
* The `tags:` key in values must be a top level key. Globals and nested `tags:` tables * The `tags:` key in values must be a top level key. Globals and nested `tags:` tables
are not currently supported. are not currently supported.
#### Importing Child Values via requirements.yaml
In some cases it is desirable to allow a child chart's values to propagate to the parent chart and be shared
as common defaults. The values to be imported can be specified in the parent chart's requirements.yaml
using a YAML list format that contains the source of the values to be imported (child) and the
destination path in the parent chart's values (parent).
The optional `import-values` in the example below instructs Helm to take any values found at `child:`
path and copy them to the path at `parent:`
````
# parent's requirements.yaml
dependencies:
- name: subchart1
repository: http://localhost:10191
version: 0.1.0
...
import-values:
- child: default.data
parent: myimports
````
In the above example, values found at `default.data` in the subchart1's values will be imported
to the `myimports` key in the parent chart's values as detailed below:
````
# parent's values
myimports:
myint: 0
mybool: false
mystring: "helm rocks"
````
````
# subchart1's values.yaml
default:
data:
myint: 999
mybool: true
````
The parent chart's resulting values would be:
````
# parent's final values
myimports:
myint: 999
mybool: true
mystring: "helm rocks"
````
The parent's final values now contains the `myint` and `mybool` fields imported from subchart1.
##### Using the exports convention
If a values.yaml contains an `exports` field at the root, it's contents may be imported
directly into the parent's values by using a simple string format as in the example below:
````
# parent's requirements.yaml
...
import-values:
- data
````
````
# child values
...
exports:
data:
myint:99
````
Since we are using the simple string `data` in our import list, Helm looks in the the `exports`
field of the child chart for `data` key and imports its contents.
The final parent values would contain our exported field.
````
# parent's values
...
myint: 99
````
Please note the parent key `data` is not contained in the parent's final values. If
you need to specify the parent key, use the 'child/parent' format.
## Templates and Values ## Templates and Values
Helm Chart templates are written in the Helm Chart templates are written in the
......
...@@ -271,6 +271,9 @@ func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error { ...@@ -271,6 +271,9 @@ func ProcessRequirementsEnabled(c *chart.Chart, v *chart.Config) error {
// pathToMap creates a nested map given a YAML path in dot notation. // pathToMap creates a nested map given a YAML path in dot notation.
func pathToMap(path string, data map[string]interface{}) map[string]interface{} { func pathToMap(path string, data map[string]interface{}) map[string]interface{} {
if path == "." {
return data
}
ap := strings.Split(path, ".") ap := strings.Split(path, ".")
if len(ap) == 0 { if len(ap) == 0 {
return nil return nil
...@@ -318,15 +321,18 @@ func processImportValues(c *chart.Chart, v *chart.Config) error { ...@@ -318,15 +321,18 @@ func processImportValues(c *chart.Chart, v *chart.Config) error {
if err != nil { if err != nil {
return err return err
} }
// combine chart values and its dependencies' values
cvals, err := CoalesceValues(c, v) cvals, err := CoalesceValues(c, v)
if err != nil { if err != nil {
return err return err
} }
nv := v.GetValues() nv := v.GetValues()
b := make(map[string]interface{}) b := make(map[string]interface{})
for kk, v3 := range nv { // convert values to map
b[kk] = v3 for kk, vvv := range nv {
b[kk] = vvv
} }
// import values from each dependency if specified in import-values
for _, r := range reqs.Dependencies { for _, r := range reqs.Dependencies {
if len(r.ImportValues) > 0 { if len(r.ImportValues) > 0 {
var outiv []interface{} var outiv []interface{}
...@@ -339,47 +345,40 @@ func processImportValues(c *chart.Chart, v *chart.Config) error { ...@@ -339,47 +345,40 @@ func processImportValues(c *chart.Chart, v *chart.Config) error {
} }
outiv = append(outiv, nm) outiv = append(outiv, nm)
s := r.Name + "." + nm["child"] s := r.Name + "." + nm["child"]
// get child table
vv, err := cvals.Table(s) vv, err := cvals.Table(s)
if err != nil { if err != nil {
log.Printf("Warning: ImportValues missing table %v", err) log.Printf("Warning: ImportValues missing table %v", err)
continue continue
} }
if nm["parent"] == "." { // create value map from child to be merged into parent
coalesceTables(b, vv.AsMap())
} else {
vm := pathToMap(nm["parent"], vv.AsMap()) vm := pathToMap(nm["parent"], vv.AsMap())
coalesceTables(b, vm) b = coalesceTables(cvals, vm)
}
case string: case string:
nm := make(map[string]string) nm := make(map[string]string)
nm["child"] = "exports." + iv nm["child"] = "exports." + iv
nm["parent"] = "." nm["parent"] = "."
outiv = append(outiv, nm) outiv = append(outiv, nm)
s := r.Name + "." + nm["child"] s := r.Name + "." + nm["child"]
vv, err := cvals.Table(s) vm, err := cvals.Table(s)
if err != nil { if err != nil {
log.Printf("Warning: ImportValues missing table %v", err) log.Printf("Warning: ImportValues missing table %v", err)
continue continue
} }
coalesceTables(b, vv.AsMap()) b = coalesceTables(b, vm.AsMap())
} }
} }
// set our formatted import values // set our formatted import values
r.ImportValues = outiv r.ImportValues = outiv
} }
} }
cv, err := coalesceValues(c, b) b = coalesceTables(b, cvals)
if err != nil { y, err := yaml.Marshal(b)
return err
}
y, err := yaml.Marshal(cv)
if err != nil { if err != nil {
return err return err
} }
bb := &chart.Config{Raw: string(y)} // set the new values
v = bb c.Values.Raw = string(y)
c.Values = bb
return nil return nil
} }
......
...@@ -217,21 +217,65 @@ func TestProcessRequirementsImportValues(t *testing.T) { ...@@ -217,21 +217,65 @@ func TestProcessRequirementsImportValues(t *testing.T) {
v := &chart.Config{Raw: ""} v := &chart.Config{Raw: ""}
e := make(map[string]string) e := make(map[string]string)
e["imported-from-chart1.type"] = "ClusterIP"
e["imported-from-chart1.name"] = "nginx" e["imported-chart1.SC1bool"] = "true"
e["imported-from-chart1.externalPort"] = "80" e["imported-chart1.SC1float"] = "3.14"
// this doesn't exist in imported table. it should merge and remain unchanged e["imported-chart1.SC1int"] = "100"
e["imported-from-chart1.notimported1"] = "1" e["imported-chart1.SC1string"] = "dollywood"
e["imported-from-chartA-via-chart1.limits.cpu"] = "300m" e["imported-chart1.SC1extra1"] = "11"
e["imported-from-chartA-via-chart1.limits.memory"] = "300Mi" e["imported-chart1.SPextra1"] = "helm rocks"
e["imported-from-chartA-via-chart1.limits.volume"] = "11" e["imported-chart1.SC1extra1"] = "11"
e["imported-from-chartA-via-chart1.requests.truthiness"] = "0.01"
// single list items (looks for exports. parent key) e["imported-chartA.SCAbool"] = "false"
e["imported-from-chartB-via-chart1.databint"] = "1" e["imported-chartA.SCAfloat"] = "3.1"
e["imported-from-chartB-via-chart1.databstr"] = "x.y.z" e["imported-chartA.SCAint"] = "55"
e["parent1c3"] = "true" e["imported-chartA.SCAstring"] = "jabba"
// checks that a chartb value was merged in with charta values e["imported-chartA.SPextra3"] = "1.337"
e["imported-from-chartA-via-chart1.resources.limits.shares"] = "100" e["imported-chartA.SC1extra2"] = "1.337"
e["imported-chartA.SCAnested1.SCAnested2"] = "true"
e["imported-chartA-B.SCAbool"] = "false"
e["imported-chartA-B.SCAfloat"] = "3.1"
e["imported-chartA-B.SCAint"] = "55"
e["imported-chartA-B.SCAstring"] = "jabba"
e["imported-chartA-B.SCBbool"] = "true"
e["imported-chartA-B.SCBfloat"] = "7.77"
e["imported-chartA-B.SCBint"] = "33"
e["imported-chartA-B.SCBstring"] = "boba"
e["imported-chartA-B.SPextra5"] = "k8s"
e["imported-chartA-B.SC1extra5"] = "tiller"
e["overridden-chart1.SC1bool"] = "false"
e["overridden-chart1.SC1float"] = "3.141592"
e["overridden-chart1.SC1int"] = "99"
e["overridden-chart1.SC1string"] = "pollywog"
e["overridden-chart1.SPextra2"] = "42"
e["overridden-chartA.SCAbool"] = "true"
e["overridden-chartA.SCAfloat"] = "41.3"
e["overridden-chartA.SCAint"] = "808"
e["overridden-chartA.SCAstring"] = "jaberwocky"
e["overridden-chartA.SPextra4"] = "true"
e["overridden-chartA-B.SCAbool"] = "true"
e["overridden-chartA-B.SCAfloat"] = "41.3"
e["overridden-chartA-B.SCAint"] = "808"
e["overridden-chartA-B.SCAstring"] = "jaberwocky"
e["overridden-chartA-B.SCBbool"] = "false"
e["overridden-chartA-B.SCBfloat"] = "1.99"
e["overridden-chartA-B.SCBint"] = "77"
e["overridden-chartA-B.SCBstring"] = "jango"
e["overridden-chartA-B.SPextra6"] = "111"
e["overridden-chartA-B.SCAextra1"] = "23"
e["overridden-chartA-B.SCBextra1"] = "13"
e["overridden-chartA-B.SC1extra6"] = "77"
// `exports` style
e["SCBexported1B"] = "1965"
e["SC1extra7"] = "true"
e["SCBexported2A"] = "blaster"
e["global.SC1exported2.all.SC1exported3"] = "SC1expstr"
verifyRequirementsImportValues(t, c, v, e) verifyRequirementsImportValues(t, c, v, e)
} }
......
...@@ -2,24 +2,16 @@ ...@@ -2,24 +2,16 @@
# This is a YAML-formatted file. # This is a YAML-formatted file.
# Declare variables to be passed into your templates. # Declare variables to be passed into your templates.
# subchartA # subchartA
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service: service:
name: nginx name: nginx
type: ClusterIP type: ClusterIP
externalPort: 80 externalPort: 80
internalPort: 80 internalPort: 80
resources: SCAdata:
limits: SCAbool: false
cpu: 300m SCAfloat: 3.1
memory: 300Mi SCAint: 55
plasticity: 1.7331 SCAstring: "jabba"
volume: 11 SCAnested1:
requests: SCAnested2: true
cpu: 350m
memory: 350Mi
truthiness: 0.01
# Default values for subchart. # Default values for subchart.
# This is a YAML-formatted file. # This is a YAML-formatted file.
# Declare variables to be passed into your templates. # Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service: service:
name: nginx name: nginx
type: ClusterIP type: ClusterIP
externalPort: 80 externalPort: 80
internalPort: 80 internalPort: 80
resources:
limits: SCBdata:
cpu: 100m SCBbool: true
memory: 128Mi SCBfloat: 7.77
requests: SCBint: 33
cpu: 100m SCBstring: "boba"
memory: 128Mi
exports: exports:
convention1: SCBexported1:
data: SCBexported1A:
databint: 1 SCBexported1B: 1965
databstr: x.y.z
convention2: SCBexported2:
resources: SCBexported2A: "blaster"
limits:
shares: 100 global:
kolla:
nova:
api:
all:
port: 8774
metadata:
all:
port: 8775
test:
dummy: 1
...@@ -7,18 +7,26 @@ dependencies: ...@@ -7,18 +7,26 @@ dependencies:
- front-end - front-end
- subcharta - subcharta
import-values: import-values:
- child: resources.limits - child: SCAdata
parent: imported-from-chartA.limits parent: imported-chartA
- child: resources.requests - child: SCAdata
parent: imported-from-chartA.requests parent: overridden-chartA
- child: SCAdata
parent: imported-chartA-B
- name: subchartb - name: subchartb
repository: http://localhost:10191 repository: http://localhost:10191
version: 0.1.0 version: 0.1.0
condition: subchartb.enabled condition: subchartb.enabled
import-values: import-values:
- convention1 - child: SCBdata
- convention2 parent: imported-chartB
- child: SCBdata
parent: imported-chartA-B
- child: exports.SCBexported2
parent: exports.SCBexported2
- SCBexported1
tags: tags:
- front-end - front-end
- subchartb - subchartb
...@@ -2,26 +2,54 @@ ...@@ -2,26 +2,54 @@
# This is a YAML-formatted file. # This is a YAML-formatted file.
# Declare variables to be passed into your templates. # Declare variables to be passed into your templates.
# subchart1 # subchart1
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service: service:
name: nginx name: nginx
type: ClusterIP type: ClusterIP
externalPort: 80 externalPort: 80
internalPort: 80 internalPort: 80
resources:
limits:
cpu: 200m
memory: 200Mi
plasticity: 0
requests:
cpu: 250m
memory: 250Mi
truthiness: 200
exports:
convention3:
parent1c3: true
SC1data:
SC1bool: true
SC1float: 3.14
SC1int: 100
SC1string: "dollywood"
SC1extra1: 11
imported-chartA:
SC1extra2: 1.337
overridden-chartA:
SCAbool: true
SCAfloat: 3.14
SCAint: 100
SCAstring: "jabathehut"
SC1extra3: true
imported-chartA-B:
SC1extra5: "tiller"
overridden-chartA-B:
SCAbool: true
SCAfloat: 3.33
SCAint: 555
SCAstring: "wormwood"
SCAextra1: 23
SCBbool: true
SCBfloat: 0.25
SCBint: 98
SCBstring: "murkwood"
SCBextra1: 13
SC1extra6: 77
SCBexported1A:
SC1extra7: true
exports:
SC1exported1:
global:
SC1exported2:
all:
SC1exported3: "SC1expstr"
\ No newline at end of file
...@@ -7,16 +7,21 @@ dependencies: ...@@ -7,16 +7,21 @@ dependencies:
- front-end - front-end
- subchart1 - subchart1
import-values: import-values:
- child: service - child: SC1data
parent: imported-from-chart1 parent: imported-chart1
- child: imported-from-chartA - child: SC1data
parent: imported-from-chartA-via-chart1 parent: overridden-chart1
- convention3 - child: imported-chartA
# this merges chartb "shares" into charta "limits" parent: imported-chartA
- child: resources.limits - child: imported-chartA-B
parent: imported-from-chartA-via-chart1.resources.limits parent: imported-chartA-B
- child: data - child: overridden-chartA-B
parent: imported-from-chartB-via-chart1 parent: overridden-chartA-B
- child: SCBexported1A
parent: .
- SCBexported2
- SC1exported1
- name: subchart2 - name: subchart2
repository: http://localhost:10191 repository: http://localhost:10191
version: 0.1.0 version: 0.1.0
......
# parent/values.yaml # parent/values.yaml
# switch-like imported-chart1:
imported-from-chart1: SPextra1: "helm rocks"
name: bathtubginx
type: None overridden-chart1:
externalPort: 25 SC1bool: false
notimported1: 1 SC1float: 3.141592
SC1int: 99
imported-from-chartA-via-chart1: SC1string: "pollywog"
limits: SPextra2: 42
cpu: 100m
memory: 100Mi
notimported2: 100 imported-chartA:
requests: SPextra3: 1.337
truthiness: 33.3
overridden-chartA:
SCAbool: true
SCAfloat: 41.3
SCAint: 808
SCAstring: "jaberwocky"
SPextra4: true
imported-chartA-B:
SPextra5: "k8s"
overridden-chartA-B:
SCAbool: true
SCAfloat: 41.3
SCAint: 808
SCAstring: "jaberwocky"
SCBbool: false
SCBfloat: 1.99
SCBint: 77
SCBstring: "jango"
SPextra6: 111
tags: tags:
front-end: true front-end: true
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment