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
* The `tags:` key in values must be a top level key. Globals and nested `tags:` tables
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
Helm Chart templates are written in the
......
......@@ -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.
func pathToMap(path string, data map[string]interface{}) map[string]interface{} {
if path == "." {
return data
}
ap := strings.Split(path, ".")
if len(ap) == 0 {
return nil
......@@ -318,15 +321,18 @@ func processImportValues(c *chart.Chart, v *chart.Config) error {
if err != nil {
return err
}
// combine chart values and its dependencies' values
cvals, err := CoalesceValues(c, v)
if err != nil {
return err
}
nv := v.GetValues()
b := make(map[string]interface{})
for kk, v3 := range nv {
b[kk] = v3
// convert values to map
for kk, vvv := range nv {
b[kk] = vvv
}
// import values from each dependency if specified in import-values
for _, r := range reqs.Dependencies {
if len(r.ImportValues) > 0 {
var outiv []interface{}
......@@ -339,47 +345,40 @@ func processImportValues(c *chart.Chart, v *chart.Config) error {
}
outiv = append(outiv, nm)
s := r.Name + "." + nm["child"]
// get child table
vv, err := cvals.Table(s)
if err != nil {
log.Printf("Warning: ImportValues missing table %v", err)
continue
}
if nm["parent"] == "." {
coalesceTables(b, vv.AsMap())
} else {
// create value map from child to be merged into parent
vm := pathToMap(nm["parent"], vv.AsMap())
coalesceTables(b, vm)
}
b = coalesceTables(cvals, vm)
case string:
nm := make(map[string]string)
nm["child"] = "exports." + iv
nm["parent"] = "."
outiv = append(outiv, nm)
s := r.Name + "." + nm["child"]
vv, err := cvals.Table(s)
vm, err := cvals.Table(s)
if err != nil {
log.Printf("Warning: ImportValues missing table %v", err)
continue
}
coalesceTables(b, vv.AsMap())
b = coalesceTables(b, vm.AsMap())
}
}
// set our formatted import values
r.ImportValues = outiv
}
}
cv, err := coalesceValues(c, b)
if err != nil {
return err
}
y, err := yaml.Marshal(cv)
b = coalesceTables(b, cvals)
y, err := yaml.Marshal(b)
if err != nil {
return err
}
bb := &chart.Config{Raw: string(y)}
v = bb
c.Values = bb
// set the new values
c.Values.Raw = string(y)
return nil
}
......
......@@ -217,21 +217,65 @@ func TestProcessRequirementsImportValues(t *testing.T) {
v := &chart.Config{Raw: ""}
e := make(map[string]string)
e["imported-from-chart1.type"] = "ClusterIP"
e["imported-from-chart1.name"] = "nginx"
e["imported-from-chart1.externalPort"] = "80"
// this doesn't exist in imported table. it should merge and remain unchanged
e["imported-from-chart1.notimported1"] = "1"
e["imported-from-chartA-via-chart1.limits.cpu"] = "300m"
e["imported-from-chartA-via-chart1.limits.memory"] = "300Mi"
e["imported-from-chartA-via-chart1.limits.volume"] = "11"
e["imported-from-chartA-via-chart1.requests.truthiness"] = "0.01"
// single list items (looks for exports. parent key)
e["imported-from-chartB-via-chart1.databint"] = "1"
e["imported-from-chartB-via-chart1.databstr"] = "x.y.z"
e["parent1c3"] = "true"
// checks that a chartb value was merged in with charta values
e["imported-from-chartA-via-chart1.resources.limits.shares"] = "100"
e["imported-chart1.SC1bool"] = "true"
e["imported-chart1.SC1float"] = "3.14"
e["imported-chart1.SC1int"] = "100"
e["imported-chart1.SC1string"] = "dollywood"
e["imported-chart1.SC1extra1"] = "11"
e["imported-chart1.SPextra1"] = "helm rocks"
e["imported-chart1.SC1extra1"] = "11"
e["imported-chartA.SCAbool"] = "false"
e["imported-chartA.SCAfloat"] = "3.1"
e["imported-chartA.SCAint"] = "55"
e["imported-chartA.SCAstring"] = "jabba"
e["imported-chartA.SPextra3"] = "1.337"
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)
}
......
......@@ -2,24 +2,16 @@
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# subchartA
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service:
name: nginx
type: ClusterIP
externalPort: 80
internalPort: 80
resources:
limits:
cpu: 300m
memory: 300Mi
plasticity: 1.7331
volume: 11
requests:
cpu: 350m
memory: 350Mi
truthiness: 0.01
SCAdata:
SCAbool: false
SCAfloat: 3.1
SCAint: 55
SCAstring: "jabba"
SCAnested1:
SCAnested2: true
# Default values for subchart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service:
name: nginx
type: ClusterIP
externalPort: 80
internalPort: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
SCBdata:
SCBbool: true
SCBfloat: 7.77
SCBint: 33
SCBstring: "boba"
exports:
convention1:
data:
databint: 1
databstr: x.y.z
convention2:
resources:
limits:
shares: 100
SCBexported1:
SCBexported1A:
SCBexported1B: 1965
SCBexported2:
SCBexported2A: "blaster"
global:
kolla:
nova:
api:
all:
port: 8774
metadata:
all:
port: 8775
test:
dummy: 1
......@@ -7,18 +7,26 @@ dependencies:
- front-end
- subcharta
import-values:
- child: resources.limits
parent: imported-from-chartA.limits
- child: resources.requests
parent: imported-from-chartA.requests
- child: SCAdata
parent: imported-chartA
- child: SCAdata
parent: overridden-chartA
- child: SCAdata
parent: imported-chartA-B
- name: subchartb
repository: http://localhost:10191
version: 0.1.0
condition: subchartb.enabled
import-values:
- convention1
- convention2
- child: SCBdata
parent: imported-chartB
- child: SCBdata
parent: imported-chartA-B
- child: exports.SCBexported2
parent: exports.SCBexported2
- SCBexported1
tags:
- front-end
- subchartb
......@@ -2,26 +2,54 @@
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# subchart1
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
service:
name: nginx
type: ClusterIP
externalPort: 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:
- front-end
- subchart1
import-values:
- child: service
parent: imported-from-chart1
- child: imported-from-chartA
parent: imported-from-chartA-via-chart1
- convention3
# this merges chartb "shares" into charta "limits"
- child: resources.limits
parent: imported-from-chartA-via-chart1.resources.limits
- child: data
parent: imported-from-chartB-via-chart1
- child: SC1data
parent: imported-chart1
- child: SC1data
parent: overridden-chart1
- child: imported-chartA
parent: imported-chartA
- child: imported-chartA-B
parent: imported-chartA-B
- child: overridden-chartA-B
parent: overridden-chartA-B
- child: SCBexported1A
parent: .
- SCBexported2
- SC1exported1
- name: subchart2
repository: http://localhost:10191
version: 0.1.0
......
# parent/values.yaml
# switch-like
imported-from-chart1:
name: bathtubginx
type: None
externalPort: 25
notimported1: 1
imported-from-chartA-via-chart1:
limits:
cpu: 100m
memory: 100Mi
notimported2: 100
requests:
truthiness: 33.3
imported-chart1:
SPextra1: "helm rocks"
overridden-chart1:
SC1bool: false
SC1float: 3.141592
SC1int: 99
SC1string: "pollywog"
SPextra2: 42
imported-chartA:
SPextra3: 1.337
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:
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