Skip to content

Commit acf7158

Browse files
committed
feat(helm): add --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint'
When --skip-schema-validation is set, any schema contain in the helm chart is ignored. Defaults to 'false'. Closes #10398 Signed-off-by: anessi <[email protected]>
1 parent ff03c66 commit acf7158

File tree

16 files changed

+149
-21
lines changed

16 files changed

+149
-21
lines changed

cmd/helm/install.go

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ func addInstallFlags(cmd *cobra.Command, f *pflag.FlagSet, client *action.Instal
197197
f.BoolVar(&client.Atomic, "atomic", false, "if set, the installation process deletes the installation on failure. The --wait flag will be set automatically if --atomic is used")
198198
f.BoolVar(&client.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed. By default, CRDs are installed if not already present")
199199
f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
200+
f.BoolVar(&client.SkipSchemaValidation, "skip-schema-validation", false, "if set, disables JSON schema validation")
200201
f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be divided by comma.")
201202
f.BoolVar(&client.EnableDNS, "enable-dns", false, "enable DNS lookups when rendering templates")
202203
f.BoolVar(&client.HideNotes, "hide-notes", false, "if set, do not show notes in install output. Does not affect presence in chart metadata")

cmd/helm/install_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,12 @@ func TestInstall(t *testing.T) {
225225
wantError: true,
226226
golden: "output/subchart-schema-cli-negative.txt",
227227
},
228+
// Install, values from yaml, schematized with errors but skip schema validation, expect success
229+
{
230+
name: "install with schema file and schematized subchart, extra values from cli, skip schema validation",
231+
cmd: "install schema testdata/testcharts/chart-with-schema-and-subchart --set lastname=doe --set subchart-with-schema.age=-25 --skip-schema-validation",
232+
golden: "output/schema.txt",
233+
},
228234
// Install deprecated chart
229235
{
230236
name: "install with warning about deprecated chart",

cmd/helm/lint.go

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
148148
f.BoolVar(&client.Strict, "strict", false, "fail on lint warnings")
149149
f.BoolVar(&client.WithSubcharts, "with-subcharts", false, "lint dependent charts")
150150
f.BoolVar(&client.Quiet, "quiet", false, "print only warnings and errors")
151+
f.BoolVar(&client.SkipSchemaValidation, "skip-schema-validation", false, "if set, disables JSON schema validation")
151152
f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for capabilities and deprecation checks")
152153
addValueOptionsFlags(f, valueOpts)
153154

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: v1
2+
description: Empty testing chart
3+
home: https://k8s.io/helm
4+
name: empty
5+
sources:
6+
- https://github.com/kubernetes/helm
7+
version: 0.1.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This file is intentionally blank
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"properties": {
4+
"addresses": {
5+
"description": "List of addresses",
6+
"items": {
7+
"properties": {
8+
"city": {
9+
"type": "string"
10+
},
11+
"number": {
12+
"type": "number"
13+
},
14+
"street": {
15+
"type": "string"
16+
}
17+
},
18+
"type": "object"
19+
},
20+
"type": "array"
21+
},
22+
"age": {
23+
"description": "Age",
24+
"minimum": 0,
25+
"type": "integer"
26+
},
27+
"employmentInfo": {
28+
"properties": {
29+
"salary": {
30+
"minimum": 0,
31+
"type": "number"
32+
},
33+
"title": {
34+
"type": "string"
35+
}
36+
},
37+
"required": [
38+
"salary"
39+
],
40+
"type": "object"
41+
},
42+
"firstname": {
43+
"description": "First name",
44+
"type": "string"
45+
},
46+
"lastname": {
47+
"type": "string"
48+
},
49+
"likesCoffee": {
50+
"type": "boolean"
51+
},
52+
"phoneNumbers": {
53+
"items": {
54+
"type": "string"
55+
},
56+
"type": "array"
57+
}
58+
},
59+
"required": [
60+
"firstname",
61+
"lastname",
62+
"addresses",
63+
"employmentInfo"
64+
],
65+
"title": "Values",
66+
"type": "object"
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
firstname: John
2+
lastname: Doe
3+
age: -5
4+
likesCoffee: true
5+
addresses:
6+
- city: Springfield
7+
street: Main
8+
number: 12345
9+
- city: New York
10+
street: Broadway
11+
number: 67890
12+
phoneNumbers:
13+
- "(888) 888-8888"
14+
- "(555) 555-5555"

cmd/helm/upgrade.go

+2
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
145145
instClient.DisableOpenAPIValidation = client.DisableOpenAPIValidation
146146
instClient.SubNotes = client.SubNotes
147147
instClient.HideNotes = client.HideNotes
148+
instClient.SkipSchemaValidation = client.SkipSchemaValidation
148149
instClient.Description = client.Description
149150
instClient.DependencyUpdate = client.DependencyUpdate
150151
instClient.Labels = client.Labels
@@ -274,6 +275,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
274275
f.BoolVar(&client.CleanupOnFail, "cleanup-on-fail", false, "allow deletion of new resources created in this upgrade when upgrade fails")
275276
f.BoolVar(&client.SubNotes, "render-subchart-notes", false, "if set, render subchart notes along with the parent")
276277
f.BoolVar(&client.HideNotes, "hide-notes", false, "if set, do not show notes in upgrade output. Does not affect presence in chart metadata")
278+
f.BoolVar(&client.SkipSchemaValidation, "skip-schema-validation", false, "if set, disables JSON schema validation")
277279
f.StringToStringVarP(&client.Labels, "labels", "l", nil, "Labels that would be added to release metadata. Should be separated by comma. Original release labels will be merged with upgrade labels. You can unset label using null.")
278280
f.StringVar(&client.Description, "description", "", "add a custom description")
279281
f.BoolVar(&client.DependencyUpdate, "dependency-update", false, "update dependencies if they are missing before installing the chart")

pkg/action/install.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ type Install struct {
9494
SkipCRDs bool
9595
SubNotes bool
9696
HideNotes bool
97+
SkipSchemaValidation bool
9798
DisableOpenAPIValidation bool
9899
IncludeCRDs bool
99100
Labels map[string]string
@@ -298,7 +299,7 @@ func (i *Install) RunWithContext(ctx context.Context, chrt *chart.Chart, vals ma
298299
IsInstall: !isUpgrade,
299300
IsUpgrade: isUpgrade,
300301
}
301-
valuesToRender, err := chartutil.ToRenderValues(chrt, vals, options, caps)
302+
valuesToRender, err := chartutil.ToRenderValuesWithSchemaValidation(chrt, vals, options, caps, i.SkipSchemaValidation)
302303
if err != nil {
303304
return nil, err
304305
}

pkg/action/lint.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ import (
3232
//
3333
// It provides the implementation of 'helm lint'.
3434
type Lint struct {
35-
Strict bool
36-
Namespace string
37-
WithSubcharts bool
38-
Quiet bool
39-
KubeVersion *chartutil.KubeVersion
35+
Strict bool
36+
Namespace string
37+
WithSubcharts bool
38+
Quiet bool
39+
SkipSchemaValidation bool
40+
KubeVersion *chartutil.KubeVersion
4041
}
4142

4243
// LintResult is the result of Lint
@@ -59,7 +60,7 @@ func (l *Lint) Run(paths []string, vals map[string]interface{}) *LintResult {
5960
}
6061
result := &LintResult{}
6162
for _, path := range paths {
62-
linter, err := lintChart(path, vals, l.Namespace, l.KubeVersion)
63+
linter, err := lintChart(path, vals, l.Namespace, l.KubeVersion, l.SkipSchemaValidation)
6364
if err != nil {
6465
result.Errors = append(result.Errors, err)
6566
continue
@@ -86,7 +87,7 @@ func HasWarningsOrErrors(result *LintResult) bool {
8687
return len(result.Errors) > 0
8788
}
8889

89-
func lintChart(path string, vals map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion) (support.Linter, error) {
90+
func lintChart(path string, vals map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion, skipSchemaValidation bool) (support.Linter, error) {
9091
var chartPath string
9192
linter := support.Linter{}
9293

@@ -125,5 +126,5 @@ func lintChart(path string, vals map[string]interface{}, namespace string, kubeV
125126
return linter, errors.Wrap(err, "unable to check Chart.yaml file in chart")
126127
}
127128

128-
return lint.AllWithKubeVersion(chartPath, vals, namespace, kubeVersion), nil
129+
return lint.AllWithKubeVersionAndSchemaValidation(chartPath, vals, namespace, kubeVersion, skipSchemaValidation), nil
129130
}

pkg/action/lint_test.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ var (
3131

3232
func TestLintChart(t *testing.T) {
3333
tests := []struct {
34-
name string
35-
chartPath string
36-
err bool
34+
name string
35+
chartPath string
36+
err bool
37+
skipSchemaValidation bool
3738
}{
3839
{
3940
name: "decompressed-chart",
@@ -69,6 +70,11 @@ func TestLintChart(t *testing.T) {
6970
name: "chart-with-schema-negative",
7071
chartPath: "testdata/charts/chart-with-schema-negative",
7172
},
73+
{
74+
name: "chart-with-schema-negative-skip-validation",
75+
chartPath: "testdata/charts/chart-with-schema-negative",
76+
skipSchemaValidation: true,
77+
},
7278
{
7379
name: "pre-release-chart",
7480
chartPath: "testdata/charts/pre-release-chart-0.1.0-alpha.tgz",
@@ -77,7 +83,7 @@ func TestLintChart(t *testing.T) {
7783

7884
for _, tt := range tests {
7985
t.Run(tt.name, func(t *testing.T) {
80-
_, err := lintChart(tt.chartPath, map[string]interface{}{}, namespace, nil)
86+
_, err := lintChart(tt.chartPath, map[string]interface{}{}, namespace, nil, tt.skipSchemaValidation)
8187
switch {
8288
case err != nil && !tt.err:
8389
t.Errorf("%s", err)

pkg/action/upgrade.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ type Upgrade struct {
9999
SubNotes bool
100100
// HideNotes determines whether notes are output during upgrade
101101
HideNotes bool
102+
// SkipSchemaValidation determines if JSON schema validation is disabled.
103+
SkipSchemaValidation bool
102104
// Description is the description of this operation
103105
Description string
104106
Labels map[string]string
@@ -258,7 +260,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin
258260
if err != nil {
259261
return nil, nil, err
260262
}
261-
valuesToRender, err := chartutil.ToRenderValues(chart, vals, options, caps)
263+
valuesToRender, err := chartutil.ToRenderValuesWithSchemaValidation(chart, vals, options, caps, u.SkipSchemaValidation)
262264
if err != nil {
263265
return nil, nil, err
264266
}

pkg/chartutil/values.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ type ReleaseOptions struct {
135135
//
136136
// This takes both ReleaseOptions and Capabilities to merge into the render values.
137137
func ToRenderValues(chrt *chart.Chart, chrtVals map[string]interface{}, options ReleaseOptions, caps *Capabilities) (Values, error) {
138+
return ToRenderValuesWithSchemaValidation(chrt, chrtVals, options, caps, false)
139+
}
140+
141+
// ToRenderValuesWithSchemaValidation composes the struct from the data coming from the Releases, Charts and Values files
142+
//
143+
// This takes both ReleaseOptions and Capabilities to merge into the render values.
144+
func ToRenderValuesWithSchemaValidation(chrt *chart.Chart, chrtVals map[string]interface{}, options ReleaseOptions, caps *Capabilities, skipSchemaValidation bool) (Values, error) {
138145
if caps == nil {
139146
caps = DefaultCapabilities
140147
}
@@ -156,9 +163,11 @@ func ToRenderValues(chrt *chart.Chart, chrtVals map[string]interface{}, options
156163
return top, err
157164
}
158165

159-
if err := ValidateAgainstSchema(chrt, vals); err != nil {
160-
errFmt := "values don't meet the specifications of the schema(s) in the following chart(s):\n%s"
161-
return top, fmt.Errorf(errFmt, err.Error())
166+
if !skipSchemaValidation {
167+
if err := ValidateAgainstSchema(chrt, vals); err != nil {
168+
errFmt := "values don't meet the specifications of the schema(s) in the following chart(s):\n%s"
169+
return top, fmt.Errorf(errFmt, err.Error())
170+
}
162171
}
163172

164173
top["Values"] = vals

pkg/chartutil/values_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func TestToRenderValues(t *testing.T) {
103103
IsInstall: true,
104104
}
105105

106-
res, err := ToRenderValues(c, overrideValues, o, nil)
106+
res, err := ToRenderValuesWithSchemaValidation(c, overrideValues, o, nil, false)
107107
if err != nil {
108108
t.Fatal(err)
109109
}

pkg/lint/lint.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,25 @@ import (
2424
"helm.sh/helm/v3/pkg/lint/support"
2525
)
2626

27-
// All runs all of the available linters on the given base directory.
27+
// All runs all the available linters on the given base directory.
2828
func All(basedir string, values map[string]interface{}, namespace string, _ bool) support.Linter {
2929
return AllWithKubeVersion(basedir, values, namespace, nil)
3030
}
3131

3232
// AllWithKubeVersion runs all the available linters on the given base directory, allowing to specify the kubernetes version.
3333
func AllWithKubeVersion(basedir string, values map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion) support.Linter {
34+
return AllWithKubeVersionAndSchemaValidation(basedir, values, namespace, kubeVersion, false)
35+
}
36+
37+
// AllWithKubeVersionAndSchemaValidation runs all the available linters on the given base directory, allowing to specify the kubernetes version and if schema validation is enabled or not.
38+
func AllWithKubeVersionAndSchemaValidation(basedir string, values map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion, skipSchemaValidation bool) support.Linter {
3439
// Using abs path to get directory context
3540
chartDir, _ := filepath.Abs(basedir)
3641

3742
linter := support.Linter{ChartDir: chartDir}
3843
rules.Chartfile(&linter)
3944
rules.ValuesWithOverrides(&linter, values)
40-
rules.TemplatesWithKubeVersion(&linter, values, namespace, kubeVersion)
45+
rules.TemplatesWithSkipSchemaValidation(&linter, values, namespace, kubeVersion, skipSchemaValidation)
4146
rules.Dependencies(&linter)
4247
return linter
4348
}

pkg/lint/rules/template.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace
5151

5252
// TemplatesWithKubeVersion lints the templates in the Linter, allowing to specify the kubernetes version.
5353
func TemplatesWithKubeVersion(linter *support.Linter, values map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion) {
54+
TemplatesWithSkipSchemaValidation(linter, values, namespace, kubeVersion, false)
55+
}
56+
57+
// TemplatesWithSkipSchemaValidation lints the templates in the Linter, allowing to specify the kubernetes version and if schema validation is enabled or not.
58+
func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion, skipSchemaValidation bool) {
5459
fpath := "templates/"
5560
templatesPath := filepath.Join(linter.ChartDir, fpath)
5661

@@ -91,7 +96,7 @@ func TemplatesWithKubeVersion(linter *support.Linter, values map[string]interfac
9196
return
9297
}
9398

94-
valuesToRender, err := chartutil.ToRenderValues(chart, cvals, options, caps)
99+
valuesToRender, err := chartutil.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, skipSchemaValidation)
95100
if err != nil {
96101
linter.RunLinterRule(support.ErrorSev, fpath, err)
97102
return

0 commit comments

Comments
 (0)