From fb9d44e7f4f9238bce06d3a057f5ca8750d21154 Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 03:45:23 +0000 Subject: [PATCH] fix: return gvk when loading resource (#8501) (#8503) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Charles-Edouard Brétéché Co-authored-by: Charles-Edouard Brétéché --- cmd/cli/kubectl-kyverno/policy/load.go | 55 ++++----- cmd/cli/kubectl-kyverno/resource/load.go | 20 +--- cmd/cli/kubectl-kyverno/resource/load_test.go | 107 ------------------ .../kubectl-kyverno/resource/loader/loader.go | 13 ++- .../resource/loader/loader_test.go | 2 +- 5 files changed, 34 insertions(+), 163 deletions(-) delete mode 100644 cmd/cli/kubectl-kyverno/resource/load_test.go diff --git a/cmd/cli/kubectl-kyverno/policy/load.go b/cmd/cli/kubectl-kyverno/policy/load.go index 4bda8f7c08..02e340a64a 100644 --- a/cmd/cli/kubectl-kyverno/policy/load.go +++ b/cmd/cli/kubectl-kyverno/policy/load.go @@ -14,27 +14,26 @@ import ( kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/data" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/experimental" + "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/convert" + resourceloader "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/source" "github.com/kyverno/kyverno/pkg/utils/git" yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml" "k8s.io/api/admissionregistration/v1alpha1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/kubectl-validate/pkg/openapiclient" - "sigs.k8s.io/kubectl-validate/pkg/validator" ) var ( - factory, _ = validator.New(client) - policyV1 = schema.GroupVersion(kyvernov1.GroupVersion).WithKind("Policy") - policyV2 = schema.GroupVersion(kyvernov2beta1.GroupVersion).WithKind("Policy") - clusterPolicyV1 = schema.GroupVersion(kyvernov1.GroupVersion).WithKind("ClusterPolicy") - clusterPolicyV2 = schema.GroupVersion(kyvernov2beta1.GroupVersion).WithKind("ClusterPolicy") - vapV1 = v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicy") - client = openapiclient.NewComposite( + factory, _ = resourceloader.New(openapiclient.NewComposite( openapiclient.NewHardcodedBuiltins("1.28"), openapiclient.NewLocalCRDFiles(data.Crds(), data.CrdsFolder), - ) + )) + policyV1 = schema.GroupVersion(kyvernov1.GroupVersion).WithKind("Policy") + policyV2 = schema.GroupVersion(kyvernov2beta1.GroupVersion).WithKind("Policy") + clusterPolicyV1 = schema.GroupVersion(kyvernov1.GroupVersion).WithKind("ClusterPolicy") + clusterPolicyV2 = schema.GroupVersion(kyvernov2beta1.GroupVersion).WithKind("ClusterPolicy") + vapV1Alpha1 = v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicy") LegacyLoader = yamlutils.GetPolicy KubectlValidateLoader = kubectlValidateLoader defaultLoader = func(bytes []byte) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { @@ -92,46 +91,42 @@ func LoadWithLoader(loader loader, fs billy.Filesystem, resourcePath string, pat return pols, vaps, nil } -func kubectlValidateLoader(bytes []byte) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { - var policies []kyvernov1.PolicyInterface - var validatingAdmissionPolicies []v1alpha1.ValidatingAdmissionPolicy - documents, err := yamlutils.SplitDocuments(bytes) +func kubectlValidateLoader(content []byte) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { + documents, err := yamlutils.SplitDocuments(content) if err != nil { return nil, nil, err } + var policies []kyvernov1.PolicyInterface + var vaps []v1alpha1.ValidatingAdmissionPolicy for _, document := range documents { - gvk, untyped, err := factory.Parse(document) + gvk, untyped, err := factory.Load(document) if err != nil { return nil, nil, err } - // TODO remove DeepCopy when fixed upstream - if err := factory.Validate(untyped.DeepCopy()); err != nil { - return nil, nil, err - } switch gvk { case policyV1, policyV2: - var policy kyvernov1.Policy - if err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(untyped.UnstructuredContent(), &policy, true); err != nil { + typed, err := convert.To[kyvernov1.Policy](untyped) + if err != nil { return nil, nil, err } - policies = append(policies, &policy) + policies = append(policies, typed) case clusterPolicyV1, clusterPolicyV2: - var policy kyvernov1.ClusterPolicy - if err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(untyped.UnstructuredContent(), &policy, true); err != nil { + typed, err := convert.To[kyvernov1.ClusterPolicy](untyped) + if err != nil { return nil, nil, err } - policies = append(policies, &policy) - case vapV1: - var policy v1alpha1.ValidatingAdmissionPolicy - if err := runtime.DefaultUnstructuredConverter.FromUnstructuredWithValidation(untyped.UnstructuredContent(), &policy, true); err != nil { + policies = append(policies, typed) + case vapV1Alpha1: + typed, err := convert.To[v1alpha1.ValidatingAdmissionPolicy](untyped) + if err != nil { return nil, nil, err } - validatingAdmissionPolicies = append(validatingAdmissionPolicies, policy) + vaps = append(vaps, *typed) default: return nil, nil, fmt.Errorf("policy type not supported %s", gvk) } } - return policies, validatingAdmissionPolicies, nil + return policies, vaps, nil } func fsLoad(loader loader, path string) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { diff --git a/cmd/cli/kubectl-kyverno/resource/load.go b/cmd/cli/kubectl-kyverno/resource/load.go index 37fa92a79f..26864c170b 100644 --- a/cmd/cli/kubectl-kyverno/resource/load.go +++ b/cmd/cli/kubectl-kyverno/resource/load.go @@ -3,12 +3,10 @@ package resource import ( "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/convert" "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" - yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) func Load[T any](l loader.Loader, content []byte) (*T, error) { - untyped, err := l.Load(content) + _, untyped, err := l.Load(content) if err != nil { return nil, err } @@ -18,19 +16,3 @@ func Load[T any](l loader.Loader, content []byte) (*T, error) { } return result, nil } - -func LoadResources(l loader.Loader, content []byte) ([]unstructured.Unstructured, error) { - documents, err := yamlutils.SplitDocuments(content) - if err != nil { - return nil, err - } - var resources []unstructured.Unstructured - for _, document := range documents { - untyped, err := l.Load(document) - if err != nil { - return nil, err - } - resources = append(resources, untyped) - } - return resources, nil -} diff --git a/cmd/cli/kubectl-kyverno/resource/load_test.go b/cmd/cli/kubectl-kyverno/resource/load_test.go deleted file mode 100644 index 2182373944..0000000000 --- a/cmd/cli/kubectl-kyverno/resource/load_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package resource - -import ( - "testing" - - "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource/loader" - "sigs.k8s.io/kubectl-validate/pkg/openapiclient" -) - -const ( - singleResource string = `apiVersion: v1 -kind: Namespace -metadata: - name: prod-bus-app1 - labels: - purpose: production` - - multipleResources string = ` -apiVersion: v1 -kind: Pod -metadata: - labels: - run: nginx - name: nginx - namespace: default -spec: - containers: - - image: nginx - name: nginx - resources: {} ---- -apiVersion: v1 -kind: Pod -metadata: - labels: - run: redis - name: redis - namespace: default -spec: - containers: - - image: redis - name: redis - resources: {}` - - resourceWithComment string = ` -### POD ### ---- -apiVersion: v1 -kind: Pod -metadata: - labels: - run: nginx - name: nginx - namespace: default -spec: - containers: - - image: nginx - name: nginx - resources: {}` -) - -func Test_LoadResources(t *testing.T) { - l, err := loader.New(openapiclient.NewHardcodedBuiltins("1.27")) - if err != nil { - t.Fatal(err) - } - tests := []struct { - name string - resources string - wantLoaded int - wantErr bool - }{ - { - name: "load no resource with empy string", - resources: "", - wantLoaded: 0, - wantErr: false, - }, - { - name: "load single resource", - resources: singleResource, - wantLoaded: 1, - wantErr: false, - }, - { - name: "load multiple resources", - resources: multipleResources, - wantLoaded: 2, - wantErr: false, - }, - { - name: "load resource with comment", - resources: resourceWithComment, - wantLoaded: 1, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if res, err := LoadResources(l, []byte(tt.resources)); (err != nil) != tt.wantErr { - t.Errorf("loader.Resources() error = %v, wantErr %v", err, tt.wantErr) - } else if len(res) != tt.wantLoaded { - t.Errorf("loader.Resources() loaded amount = %v, wantLoaded %v", len(res), tt.wantLoaded) - } - }) - } -} diff --git a/cmd/cli/kubectl-kyverno/resource/loader/loader.go b/cmd/cli/kubectl-kyverno/resource/loader/loader.go index a016036e3e..ad33a92c50 100644 --- a/cmd/cli/kubectl-kyverno/resource/loader/loader.go +++ b/cmd/cli/kubectl-kyverno/resource/loader/loader.go @@ -4,12 +4,13 @@ import ( "fmt" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/openapi" "sigs.k8s.io/kubectl-validate/pkg/validator" ) type Loader interface { - Load([]byte) (unstructured.Unstructured, error) + Load([]byte) (schema.GroupVersionKind, unstructured.Unstructured, error) } type loader struct { @@ -26,14 +27,14 @@ func New(client openapi.Client) (Loader, error) { }, nil } -func (l *loader) Load(document []byte) (unstructured.Unstructured, error) { - _, result, err := l.validator.Parse(document) +func (l *loader) Load(document []byte) (schema.GroupVersionKind, unstructured.Unstructured, error) { + gvk, result, err := l.validator.Parse(document) if err != nil { - return unstructured.Unstructured{}, fmt.Errorf("failed to parse document (%w)", err) + return gvk, unstructured.Unstructured{}, fmt.Errorf("failed to parse document (%w)", err) } // TODO: remove DeepCopy when fixed upstream if err := l.validator.Validate(result.DeepCopy()); err != nil { - return unstructured.Unstructured{}, fmt.Errorf("failed to validate resource (%w)", err) + return gvk, unstructured.Unstructured{}, fmt.Errorf("failed to validate resource (%w)", err) } - return *result, nil + return gvk, *result, nil } diff --git a/cmd/cli/kubectl-kyverno/resource/loader/loader_test.go b/cmd/cli/kubectl-kyverno/resource/loader/loader_test.go index 9f362a89a1..0398a731e1 100644 --- a/cmd/cli/kubectl-kyverno/resource/loader/loader_test.go +++ b/cmd/cli/kubectl-kyverno/resource/loader/loader_test.go @@ -163,7 +163,7 @@ func Test_loader_Load(t *testing.T) { }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := tt.loader.Load(tt.document) + _, got, err := tt.loader.Load(tt.document) if (err != nil) != tt.wantErr { t.Errorf("loader.Load() error = %v, wantErr %v", err, tt.wantErr) return