Merge pull request #9175 from dastrobu/copy-dependencies-on-aliasing

fix: copy dependencies on aliasing to avoid sharing chart references on multiply aliased dependencies
pull/30786/head
Scott Rigby 5 months ago committed by GitHub
commit a911aa2112
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -113,6 +113,8 @@ func (ch *Chart) ChartPath() string {
} }
// ChartFullPath returns the full path to this chart. // ChartFullPath returns the full path to this chart.
// Note that the path may not correspond to the path where the file can be found on the file system if the path
// points to an aliased subchart.
func (ch *Chart) ChartFullPath() string { func (ch *Chart) ChartFullPath() string {
if !ch.IsRoot() { if !ch.IsRoot() {
return ch.Parent().ChartFullPath() + "/charts/" + ch.Name() return ch.Parent().ChartFullPath() + "/charts/" + ch.Name()

@ -91,6 +91,7 @@ func processDependencyTags(reqs []*chart.Dependency, cvals Values) {
} }
} }
// getAliasDependency finds the chart for an alias dependency and copies parts that will be modified
func getAliasDependency(charts []*chart.Chart, dep *chart.Dependency) *chart.Chart { func getAliasDependency(charts []*chart.Chart, dep *chart.Dependency) *chart.Chart {
for _, c := range charts { for _, c := range charts {
if c == nil { if c == nil {
@ -104,17 +105,38 @@ func getAliasDependency(charts []*chart.Chart, dep *chart.Dependency) *chart.Cha
} }
out := *c out := *c
md := *c.Metadata out.Metadata = copyMetadata(c.Metadata)
out.Metadata = &md
// empty dependencies and shallow copy all dependencies, otherwise parent info may be corrupted if
// there is more than one dependency aliasing this chart
out.SetDependencies()
for _, dependency := range c.Dependencies() {
cpy := *dependency
out.AddDependency(&cpy)
}
if dep.Alias != "" { if dep.Alias != "" {
md.Name = dep.Alias out.Metadata.Name = dep.Alias
} }
return &out return &out
} }
return nil return nil
} }
func copyMetadata(metadata *chart.Metadata) *chart.Metadata {
md := *metadata
if md.Dependencies != nil {
dependencies := make([]*chart.Dependency, len(md.Dependencies))
for i := range md.Dependencies {
dependency := *md.Dependencies[i]
dependencies[i] = &dependency
}
md.Dependencies = dependencies
}
return &md
}
// processDependencyEnabled removes disabled charts from dependencies // processDependencyEnabled removes disabled charts from dependencies
func processDependencyEnabled(c *chart.Chart, v map[string]interface{}, path string) error { func processDependencyEnabled(c *chart.Chart, v map[string]interface{}, path string) error {
if c.Metadata.Dependencies == nil { if c.Metadata.Dependencies == nil {

@ -286,6 +286,38 @@ func TestProcessDependencyImportValues(t *testing.T) {
} }
} }
func TestProcessDependencyImportValuesFromSharedDependencyToAliases(t *testing.T) {
c := loadChart(t, "testdata/chart-with-import-from-aliased-dependencies")
if err := processDependencyEnabled(c, c.Values, ""); err != nil {
t.Fatalf("expected no errors but got %q", err)
}
if err := processDependencyImportValues(c, true); err != nil {
t.Fatalf("processing import values dependencies %v", err)
}
e := make(map[string]string)
e["foo-defaults.defaultValue"] = "42"
e["bar-defaults.defaultValue"] = "42"
e["foo.defaults.defaultValue"] = "42"
e["bar.defaults.defaultValue"] = "42"
e["foo.grandchild.defaults.defaultValue"] = "42"
e["bar.grandchild.defaults.defaultValue"] = "42"
cValues := Values(c.Values)
for kk, vv := range e {
pv, err := cValues.PathValue(kk)
if err != nil {
t.Fatalf("retrieving import values table %v %v", kk, err)
}
if pv != vv {
t.Errorf("failed to match imported value %v with expected %v", pv, vv)
}
}
}
func TestProcessDependencyImportValuesMultiLevelPrecedence(t *testing.T) { func TestProcessDependencyImportValuesMultiLevelPrecedence(t *testing.T) {
c := loadChart(t, "testdata/three-level-dependent-chart/umbrella") c := loadChart(t, "testdata/three-level-dependent-chart/umbrella")
@ -430,6 +462,9 @@ func TestDependentChartAliases(t *testing.T) {
if aliasChart == nil { if aliasChart == nil {
t.Fatalf("failed to get dependency chart for alias %s", req[2].Name) t.Fatalf("failed to get dependency chart for alias %s", req[2].Name)
} }
if aliasChart.Parent() != c {
t.Fatalf("dependency chart has wrong parent, expected %s but got %s", c.Name(), aliasChart.Parent().Name())
}
if req[2].Alias != "" { if req[2].Alias != "" {
if aliasChart.Name() != req[2].Alias { if aliasChart.Name() != req[2].Alias {
t.Fatalf("dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name()) t.Fatalf("dependency chart name should be %s but got %s", req[2].Alias, aliasChart.Name())
@ -521,3 +556,32 @@ func TestDependentChartsWithSomeSubchartsSpecifiedInDependency(t *testing.T) {
t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies)) t.Fatalf("expected 1 dependency specified in Chart.yaml, got %d", len(c.Metadata.Dependencies))
} }
} }
func validateDependencyTree(t *testing.T, c *chart.Chart) {
for _, dependency := range c.Dependencies() {
if dependency.Parent() != c {
if dependency.Parent() != c {
t.Fatalf("dependency chart %s has wrong parent, expected %s but got %s", dependency.Name(), c.Name(), dependency.Parent().Name())
}
}
// recurse entire tree
validateDependencyTree(t, dependency)
}
}
func TestChartWithDependencyAliasedTwiceAndDoublyReferencedSubDependency(t *testing.T) {
c := loadChart(t, "testdata/chart-with-dependency-aliased-twice")
if len(c.Dependencies()) != 1 {
t.Fatalf("expected one dependency for this chart, but got %d", len(c.Dependencies()))
}
if err := processDependencyEnabled(c, c.Values, ""); err != nil {
t.Fatalf("expected no errors but got %q", err)
}
if len(c.Dependencies()) != 2 {
t.Fatal("expected two dependencies after processing aliases")
}
validateDependencyTree(t, c)
}

@ -0,0 +1,14 @@
apiVersion: v2
appVersion: 1.0.0
name: chart-with-dependency-aliased-twice
type: application
version: 1.0.0
dependencies:
- name: child
alias: foo
version: 1.0.0
- name: child
alias: bar
version: 1.0.0

@ -0,0 +1,6 @@
apiVersion: v2
appVersion: 1.0.0
name: child
type: application
version: 1.0.0

@ -0,0 +1,6 @@
apiVersion: v2
appVersion: 1.0.0
name: grandchild
type: application
version: 1.0.0

@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Chart.Name }}-{{ .Values.from }}
data:
{{- toYaml .Values | nindent 2 }}

@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Chart.Name }}
data:
{{- toYaml .Values | nindent 2 }}

@ -0,0 +1,7 @@
foo:
grandchild:
from: foo
bar:
grandchild:
from: bar

@ -0,0 +1,20 @@
apiVersion: v2
appVersion: 1.0.0
name: chart-with-dependency-aliased-twice
type: application
version: 1.0.0
dependencies:
- name: child
alias: foo
version: 1.0.0
import-values:
- parent: foo-defaults
child: defaults
- name: child
alias: bar
version: 1.0.0
import-values:
- parent: bar-defaults
child: defaults

@ -0,0 +1,12 @@
apiVersion: v2
appVersion: 1.0.0
name: child
type: application
version: 1.0.0
dependencies:
- name: grandchild
version: 1.0.0
import-values:
- parent: defaults
child: defaults

@ -0,0 +1,6 @@
apiVersion: v2
appVersion: 1.0.0
name: grandchild
type: application
version: 1.0.0

@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Chart.Name }}
data:
{{ .Values.defaults | toYaml }}

@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Chart.Name }}
data:
{{ toYaml .Values.defaults | indent 2 }}
Loading…
Cancel
Save