Refactor validation files into openapi/validation
Kubernetes-commit: 84b226409aa656fbacdcd633807dd0b04d1fb34e
This commit is contained in:
parent
248be67094
commit
fca10494ce
|
@ -33,7 +33,6 @@ import (
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubectl/pkg/util/openapi"
|
"k8s.io/kubectl/pkg/util/openapi"
|
||||||
openapivalidation "k8s.io/kubectl/pkg/util/openapi/validation"
|
|
||||||
"k8s.io/kubectl/pkg/validation"
|
"k8s.io/kubectl/pkg/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -159,7 +158,7 @@ func (f *factoryImpl) Validator(validationDirective string) (validation.Schema,
|
||||||
}
|
}
|
||||||
|
|
||||||
schema := validation.ConjunctiveSchema{
|
schema := validation.ConjunctiveSchema{
|
||||||
openapivalidation.NewSchemaValidation(resources),
|
validation.NewSchemaValidation(resources),
|
||||||
validation.NoDoubleKeySchema{},
|
validation.NoDoubleKeySchema{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ import (
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/cli-runtime/pkg/resource"
|
"k8s.io/cli-runtime/pkg/resource"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
schemavalidation "k8s.io/kubectl/pkg/util/openapi/validation"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Schema is an interface that knows how to validate an API object serialized to a byte array.
|
// Schema is an interface that knows how to validate an API object serialized to a byte array.
|
||||||
|
@ -127,12 +126,12 @@ type paramVerifyingSchema struct {
|
||||||
|
|
||||||
// ValidateBytes validates bytes per a ParamVerifyingSchema
|
// ValidateBytes validates bytes per a ParamVerifyingSchema
|
||||||
func (c *paramVerifyingSchema) ValidateBytes(data []byte) error {
|
func (c *paramVerifyingSchema) ValidateBytes(data []byte) error {
|
||||||
obj, err := schemavalidation.Parse(data)
|
obj, err := parse(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gvk, errs := schemavalidation.GetObjectKind(obj)
|
gvk, errs := getObjectKind(obj)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return utilerrors.NewAggregate(errs)
|
return utilerrors.NewAggregate(errs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
name: redis-master
|
|
||||||
name: name
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- args: "this is a bad command"
|
|
||||||
image: gcr.io/fake_project/fake_image:fake_tag
|
|
||||||
name: master
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"kind": "Pod",
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"metadata": {
|
|
||||||
"name": "name",
|
|
||||||
"labels": {
|
|
||||||
"name": "redis-master"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spec": {
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "master",
|
|
||||||
"image": "gcr.io/fake_project/fake_image:fake_tag",
|
|
||||||
"args": "this is a bad command"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"kind": "Pod",
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"metadata": {
|
|
||||||
"name": "apache-php",
|
|
||||||
"labels": {
|
|
||||||
"name": "apache-php"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spec": {
|
|
||||||
"volumes": [{
|
|
||||||
"name": "shared-disk"
|
|
||||||
}],
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "apache-php",
|
|
||||||
"image": "gcr.io/fake_project/fake_image:fake_tag",
|
|
||||||
"ports": [
|
|
||||||
{
|
|
||||||
"name": "apache",
|
|
||||||
"hostPort": "13380",
|
|
||||||
"containerPort": 80,
|
|
||||||
"protocol": "TCP"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"volumeMounts": [
|
|
||||||
{
|
|
||||||
"name": "shared-disk",
|
|
||||||
"mountPath": "/var/www/html"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"kind": "Pod",
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"metadata": {
|
|
||||||
"name": "apache-php",
|
|
||||||
"labels": {
|
|
||||||
"name": "apache-php"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"spec": {
|
|
||||||
"volumes": [
|
|
||||||
"name": "shared-disk"
|
|
||||||
],
|
|
||||||
"containers": [
|
|
||||||
{
|
|
||||||
"name": "apache-php",
|
|
||||||
"image": "gcr.io/fake_project/fake_image:fake_tag",
|
|
||||||
"ports": [
|
|
||||||
{
|
|
||||||
"name": "apache",
|
|
||||||
"hostPort": 13380,
|
|
||||||
"containerPort": 80,
|
|
||||||
"protocol": "TCP"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"volumeMounts": [
|
|
||||||
{
|
|
||||||
"name": "shared-disk",
|
|
||||||
"mountPath": "/var/www/html"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
name: redis-master
|
|
||||||
name: name
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- image: gcr.io/fake_project/fake_image:fake_tag
|
|
||||||
name: master
|
|
||||||
args:
|
|
||||||
-
|
|
||||||
command:
|
|
||||||
-
|
|
|
@ -1,16 +0,0 @@
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
name: redis-master
|
|
||||||
name: name
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- args:
|
|
||||||
- this
|
|
||||||
- is
|
|
||||||
- an
|
|
||||||
- ok
|
|
||||||
- command
|
|
||||||
image: gcr.io/fake_project/fake_image:fake_tag
|
|
||||||
name: master
|
|
|
@ -27,28 +27,28 @@ import (
|
||||||
"k8s.io/kubectl/pkg/util/openapi"
|
"k8s.io/kubectl/pkg/util/openapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SchemaValidation validates the object against an OpenAPI schema.
|
// schemaValidation validates the object against an OpenAPI schema.
|
||||||
type SchemaValidation struct {
|
type schemaValidation struct {
|
||||||
resources openapi.Resources
|
resources openapi.Resources
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSchemaValidation creates a new SchemaValidation that can be used
|
// NewSchemaValidation creates a new Schema that can be used
|
||||||
// to validate objects.
|
// to validate objects.
|
||||||
func NewSchemaValidation(resources openapi.Resources) *SchemaValidation {
|
func NewSchemaValidation(resources openapi.Resources) Schema {
|
||||||
return &SchemaValidation{
|
return &schemaValidation{
|
||||||
resources: resources,
|
resources: resources,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateBytes will validates the object against using the Resources
|
// ValidateBytes will validates the object against using the Resources
|
||||||
// object.
|
// object.
|
||||||
func (v *SchemaValidation) ValidateBytes(data []byte) error {
|
func (v *schemaValidation) ValidateBytes(data []byte) error {
|
||||||
obj, err := Parse(data)
|
obj, err := parse(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gvk, errs := GetObjectKind(obj)
|
gvk, errs := getObjectKind(obj)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return utilerrors.NewAggregate(errs)
|
return utilerrors.NewAggregate(errs)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ func (v *SchemaValidation) ValidateBytes(data []byte) error {
|
||||||
return utilerrors.NewAggregate(v.validateResource(obj, gvk))
|
return utilerrors.NewAggregate(v.validateResource(obj, gvk))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *SchemaValidation) validateList(object interface{}) []error {
|
func (v *schemaValidation) validateList(object interface{}) []error {
|
||||||
fields, ok := object.(map[string]interface{})
|
fields, ok := object.(map[string]interface{})
|
||||||
if !ok || fields == nil {
|
if !ok || fields == nil {
|
||||||
return []error{errors.New("invalid object to validate")}
|
return []error{errors.New("invalid object to validate")}
|
||||||
|
@ -71,7 +71,7 @@ func (v *SchemaValidation) validateList(object interface{}) []error {
|
||||||
return []error{errors.New("invalid object to validate")}
|
return []error{errors.New("invalid object to validate")}
|
||||||
}
|
}
|
||||||
for _, item := range fields["items"].([]interface{}) {
|
for _, item := range fields["items"].([]interface{}) {
|
||||||
if gvk, errs := GetObjectKind(item); errs != nil {
|
if gvk, errs := getObjectKind(item); errs != nil {
|
||||||
allErrors = append(allErrors, errs...)
|
allErrors = append(allErrors, errs...)
|
||||||
} else {
|
} else {
|
||||||
allErrors = append(allErrors, v.validateResource(item, gvk)...)
|
allErrors = append(allErrors, v.validateResource(item, gvk)...)
|
||||||
|
@ -80,7 +80,7 @@ func (v *SchemaValidation) validateList(object interface{}) []error {
|
||||||
return allErrors
|
return allErrors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *SchemaValidation) validateResource(obj interface{}, gvk schema.GroupVersionKind) []error {
|
func (v *schemaValidation) validateResource(obj interface{}, gvk schema.GroupVersionKind) []error {
|
||||||
resource := v.resources.LookupResource(gvk)
|
resource := v.resources.LookupResource(gvk)
|
||||||
if resource == nil {
|
if resource == nil {
|
||||||
// resource is not present, let's just skip validation.
|
// resource is not present, let's just skip validation.
|
||||||
|
@ -90,7 +90,7 @@ func (v *SchemaValidation) validateResource(obj interface{}, gvk schema.GroupVer
|
||||||
return validation.ValidateModel(obj, resource, gvk.Kind)
|
return validation.ValidateModel(obj, resource, gvk.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Parse(data []byte) (interface{}, error) {
|
func parse(data []byte) (interface{}, error) {
|
||||||
var obj interface{}
|
var obj interface{}
|
||||||
out, err := yaml.ToJSON(data)
|
out, err := yaml.ToJSON(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -102,7 +102,7 @@ func Parse(data []byte) (interface{}, error) {
|
||||||
return obj, nil
|
return obj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetObjectKind(object interface{}) (schema.GroupVersionKind, []error) {
|
func getObjectKind(object interface{}) (schema.GroupVersionKind, []error) {
|
||||||
var listErrors []error
|
var listErrors []error
|
||||||
fields, ok := object.(map[string]interface{})
|
fields, ok := object.(map[string]interface{})
|
||||||
if !ok || fields == nil {
|
if !ok || fields == nil {
|
|
@ -30,10 +30,10 @@ import (
|
||||||
"k8s.io/kubectl/pkg/util/openapi"
|
"k8s.io/kubectl/pkg/util/openapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
var fakeSchema = testing.Fake{Path: filepath.Join("..", "..", "..", "..", "testdata", "openapi", "swagger.json")}
|
var fakeSchema = testing.Fake{Path: filepath.Join("..", "..", "testdata", "openapi", "swagger.json")}
|
||||||
|
|
||||||
var _ = Describe("resource validation using OpenAPI Schema", func() {
|
var _ = Describe("resource validation using OpenAPI Schema", func() {
|
||||||
var validator *SchemaValidation
|
var validator Schema
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
s, err := fakeSchema.OpenAPISchema()
|
s, err := fakeSchema.OpenAPISchema()
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
Loading…
Reference in New Issue