mirror of https://github.com/helm/helm
commit
4da1210edd
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Helm Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package action
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
release "helm.sh/helm/v4/pkg/release/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetMetadata_Labels(t *testing.T) {
|
||||||
|
rel := releaseStub()
|
||||||
|
rel.Info.Status = release.StatusDeployed
|
||||||
|
customLabels := map[string]string{"key1": "value1", "key2": "value2"}
|
||||||
|
rel.Labels = customLabels
|
||||||
|
|
||||||
|
metaGetter := NewGetMetadata(actionConfigFixture(t))
|
||||||
|
err := metaGetter.cfg.Releases.Create(rel)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
metadata, err := metaGetter.Run(rel.Name)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, metadata.Name, rel.Name)
|
||||||
|
assert.Equal(t, metadata.Labels, customLabels)
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
{"name":"thomas-guide","chart":"foo","version":"0.1.0-beta.1","appVersion":"1.0","annotations":{"category":"web-apps","supported":"true"},"dependencies":[{"name":"cool-plugin","version":"1.0.0","repository":"https://coolplugin.io/charts","condition":"coolPlugin.enabled","enabled":true},{"name":"crds","version":"2.7.1","repository":"","condition":"crds.enabled"}],"namespace":"default","revision":1,"status":"deployed","deployedAt":"1977-09-02T22:04:05Z"}
|
{"name":"thomas-guide","chart":"foo","version":"0.1.0-beta.1","appVersion":"1.0","annotations":{"category":"web-apps","supported":"true"},"labels":{"key1":"value1"},"dependencies":[{"name":"cool-plugin","version":"1.0.0","repository":"https://coolplugin.io/charts","condition":"coolPlugin.enabled","enabled":true},{"name":"crds","version":"2.7.1","repository":"","condition":"crds.enabled"}],"namespace":"default","revision":1,"status":"deployed","deployedAt":"1977-09-02T22:04:05Z"}
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
==> Linting testdata/testcharts/chart-with-only-crds
|
||||||
|
[WARNING] templates/: directory does not exist
|
||||||
|
|
||||||
|
1 chart(s) linted, 0 chart(s) failed
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Helm Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package rules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/util/yaml"
|
||||||
|
|
||||||
|
"helm.sh/helm/v4/pkg/chart/v2/loader"
|
||||||
|
"helm.sh/helm/v4/pkg/lint/support"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Crds lints the CRDs in the Linter.
|
||||||
|
func Crds(linter *support.Linter) {
|
||||||
|
fpath := "crds/"
|
||||||
|
crdsPath := filepath.Join(linter.ChartDir, fpath)
|
||||||
|
|
||||||
|
// crds directory is optional
|
||||||
|
if _, err := os.Stat(crdsPath); errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
crdsDirValid := linter.RunLinterRule(support.ErrorSev, fpath, validateCrdsDir(crdsPath))
|
||||||
|
if !crdsDirValid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load chart and parse CRDs
|
||||||
|
chart, err := loader.Load(linter.ChartDir)
|
||||||
|
|
||||||
|
chartLoaded := linter.RunLinterRule(support.ErrorSev, fpath, err)
|
||||||
|
|
||||||
|
if !chartLoaded {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate over all the CRDs to check:
|
||||||
|
1. It is a YAML file and not a template
|
||||||
|
2. The API version is apiextensions.k8s.io
|
||||||
|
3. The kind is CustomResourceDefinition
|
||||||
|
*/
|
||||||
|
for _, crd := range chart.CRDObjects() {
|
||||||
|
fileName := crd.Name
|
||||||
|
fpath = fileName
|
||||||
|
|
||||||
|
decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(crd.File.Data), 4096)
|
||||||
|
for {
|
||||||
|
var yamlStruct *k8sYamlStruct
|
||||||
|
|
||||||
|
err := decoder.Decode(&yamlStruct)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// If YAML parsing fails here, it will always fail in the next block as well, so we should return here.
|
||||||
|
// This also confirms the YAML is not a template, since templates can't be decoded into a K8sYamlStruct.
|
||||||
|
if !linter.RunLinterRule(support.ErrorSev, fpath, validateYamlContent(err)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
linter.RunLinterRule(support.ErrorSev, fpath, validateCrdAPIVersion(yamlStruct))
|
||||||
|
linter.RunLinterRule(support.ErrorSev, fpath, validateCrdKind(yamlStruct))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation functions
|
||||||
|
func validateCrdsDir(crdsPath string) error {
|
||||||
|
fi, err := os.Stat(crdsPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !fi.IsDir() {
|
||||||
|
return errors.New("not a directory")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateCrdAPIVersion(obj *k8sYamlStruct) error {
|
||||||
|
if !strings.HasPrefix(obj.APIVersion, "apiextensions.k8s.io") {
|
||||||
|
return fmt.Errorf("apiVersion is not in 'apiextensions.k8s.io'")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateCrdKind(obj *k8sYamlStruct) error {
|
||||||
|
if obj.Kind != "CustomResourceDefinition" {
|
||||||
|
return fmt.Errorf("object kind is not 'CustomResourceDefinition'")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Helm Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package rules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"helm.sh/helm/v4/pkg/lint/support"
|
||||||
|
)
|
||||||
|
|
||||||
|
const invalidCrdsDir = "./testdata/invalidcrdsdir"
|
||||||
|
|
||||||
|
func TestInvalidCrdsDir(t *testing.T) {
|
||||||
|
linter := support.Linter{ChartDir: invalidCrdsDir}
|
||||||
|
Crds(&linter)
|
||||||
|
res := linter.Messages
|
||||||
|
|
||||||
|
assert.Len(t, res, 1)
|
||||||
|
assert.ErrorContains(t, res[0].Err, "not a directory")
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
version: 0.1.0
|
||||||
|
name: badcrdfile
|
||||||
|
type: application
|
||||||
|
icon: http://riverrun.io
|
@ -0,0 +1,2 @@
|
|||||||
|
apiVersion: bad.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
@ -0,0 +1,2 @@
|
|||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: NotACustomResourceDefinition
|
@ -0,0 +1 @@
|
|||||||
|
# Default values for badcrdfile.
|
@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: tests.test.io
|
||||||
|
spec:
|
||||||
|
group: test.io
|
||||||
|
names:
|
||||||
|
kind: Test
|
||||||
|
listKind: TestList
|
||||||
|
plural: tests
|
||||||
|
singular: test
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name : v1alpha2
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
- name : v1alpha1
|
||||||
|
served: true
|
||||||
|
storage: false
|
@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
description: A Helm chart for Kubernetes
|
||||||
|
version: 0.1.0
|
||||||
|
name: invalidcrdsdir
|
||||||
|
type: application
|
||||||
|
icon: http://riverrun.io
|
@ -0,0 +1 @@
|
|||||||
|
# Default values for invalidcrdsdir.
|
Loading…
Reference in new issue