feat: Detect missing selector during lint

Signed-off-by: Matt Butcher <matt.butcher@microsoft.com>
pull/8142/head
Matt Butcher 4 years ago
parent 08e546f169
commit 118d46eb3e
No known key found for this signature in database
GPG Key ID: DCD5F5E5EF32C345

@ -131,6 +131,7 @@ func Templates(linter *support.Linter, values map[string]interface{}, namespace
linter.RunLinterRule(support.ErrorSev, path, validateYamlContent(err))
linter.RunLinterRule(support.ErrorSev, path, validateMetadataName(&yamlStruct))
linter.RunLinterRule(support.ErrorSev, path, validateNoDeprecations(&yamlStruct))
linter.RunLinterRule(support.ErrorSev, path, validateMatchSelector(&yamlStruct, renderedContent))
}
}
}
@ -185,6 +186,19 @@ func validateNoReleaseTime(manifest []byte) error {
return nil
}
// validateMatchSelector ensures that template specs have a selector declared.
// See https://github.com/helm/helm/issues/1990
func validateMatchSelector(yamlStruct *K8sYamlStruct, manifest string) error {
switch yamlStruct.Kind {
case "Deployment", "ReplicaSet", "DaemonSet", "StatefulSet":
// verify that matchLabels or matchExpressions is present
if !(strings.Contains(manifest, "matchLabels") || strings.Contains(manifest, "matchExpressions")) {
return fmt.Errorf("a %s must contain matchLabels or matchExpressions, and %q does not", yamlStruct.Kind, yamlStruct.Metadata.Name)
}
}
return nil
}
// K8sYamlStruct stubs a Kubernetes YAML file.
//
// DEPRECATED: In Helm 4, this will be made a private type, as it is for use only within

@ -145,7 +145,7 @@ func TestDeprecatedAPIFails(t *testing.T) {
Templates: []*chart.File{
{
Name: "templates/baddeployment.yaml",
Data: []byte("apiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n name: baddep"),
Data: []byte("apiVersion: apps/v1beta1\nkind: Deployment\nmetadata:\n name: baddep\nspec: {selector: {matchLabels: {foo: bar}}}"),
},
{
Name: "templates/goodsecret.yaml",
@ -226,3 +226,82 @@ func TestStrictTemplateParsingMapError(t *testing.T) {
}
}
}
func TestValidateMatchSelector(t *testing.T) {
md := &K8sYamlStruct{
APIVersion: "apps/v1",
Kind: "Deployment",
Metadata: k8sYamlMetadata{
Name: "mydeployment",
},
}
manifest := `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
`
if err := validateMatchSelector(md, manifest); err != nil {
t.Error(err)
}
manifest = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchExpressions:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
`
if err := validateMatchSelector(md, manifest); err != nil {
t.Error(err)
}
manifest = `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
`
if err := validateMatchSelector(md, manifest); err == nil {
t.Error("expected Deployment with no selector to fail")
}
}

Loading…
Cancel
Save