1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

fix: return gvk when loading resource (#8501)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-09-22 05:10:15 +02:00 committed by GitHub
parent 3c76cf5118
commit bc6b6e17b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 163 deletions

View file

@ -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) {

View file

@ -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
}

View file

@ -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)
}
})
}
}

View file

@ -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
}

View file

@ -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