...

Source file src/k8s.io/kubectl/pkg/validation/validation.go

Documentation: k8s.io/kubectl/pkg/validation

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package validation
    18  
    19  import (
    20  	"errors"
    21  
    22  	"k8s.io/apimachinery/pkg/runtime/schema"
    23  	utilerrors "k8s.io/apimachinery/pkg/util/errors"
    24  	"k8s.io/apimachinery/pkg/util/json"
    25  	"k8s.io/apimachinery/pkg/util/yaml"
    26  	"k8s.io/kube-openapi/pkg/util/proto/validation"
    27  	"k8s.io/kubectl/pkg/util/openapi"
    28  )
    29  
    30  // schemaValidation validates the object against an OpenAPI schema.
    31  type schemaValidation struct {
    32  	resourcesGetter openapi.OpenAPIResourcesGetter
    33  }
    34  
    35  // NewSchemaValidation creates a new Schema that can be used
    36  // to validate objects.
    37  func NewSchemaValidation(resourcesGetter openapi.OpenAPIResourcesGetter) Schema {
    38  	return &schemaValidation{
    39  		resourcesGetter: resourcesGetter,
    40  	}
    41  }
    42  
    43  // ValidateBytes will validates the object against using the Resources
    44  // object.
    45  func (v *schemaValidation) ValidateBytes(data []byte) error {
    46  	obj, err := parse(data)
    47  	if err != nil {
    48  		return err
    49  	}
    50  
    51  	gvk, errs := getObjectKind(obj)
    52  	if errs != nil {
    53  		return utilerrors.NewAggregate(errs)
    54  	}
    55  
    56  	if (gvk == schema.GroupVersionKind{Version: "v1", Kind: "List"}) {
    57  		return utilerrors.NewAggregate(v.validateList(obj))
    58  	}
    59  	return utilerrors.NewAggregate(v.validateResource(obj, gvk))
    60  }
    61  
    62  func (v *schemaValidation) validateList(object interface{}) []error {
    63  	fields, ok := object.(map[string]interface{})
    64  	if !ok || fields == nil {
    65  		return []error{errors.New("invalid object to validate")}
    66  	}
    67  
    68  	allErrors := []error{}
    69  	if _, ok := fields["items"].([]interface{}); !ok {
    70  		return []error{errors.New("invalid object to validate")}
    71  	}
    72  	for _, item := range fields["items"].([]interface{}) {
    73  		if gvk, errs := getObjectKind(item); errs != nil {
    74  			allErrors = append(allErrors, errs...)
    75  		} else {
    76  			allErrors = append(allErrors, v.validateResource(item, gvk)...)
    77  		}
    78  	}
    79  	return allErrors
    80  }
    81  
    82  func (v *schemaValidation) validateResource(obj interface{}, gvk schema.GroupVersionKind) []error {
    83  	// This lazy-loads the OpenAPI V2 specifications, caching the specs.
    84  	resources, err := v.resourcesGetter.OpenAPISchema()
    85  	if err != nil {
    86  		return []error{err}
    87  	}
    88  	resource := resources.LookupResource(gvk)
    89  	if resource == nil {
    90  		// resource is not present, let's just skip validation.
    91  		return nil
    92  	}
    93  
    94  	return validation.ValidateModel(obj, resource, gvk.Kind)
    95  }
    96  
    97  func parse(data []byte) (interface{}, error) {
    98  	var obj interface{}
    99  	out, err := yaml.ToJSON(data)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	if err := json.Unmarshal(out, &obj); err != nil {
   104  		return nil, err
   105  	}
   106  	return obj, nil
   107  }
   108  
   109  func getObjectKind(object interface{}) (schema.GroupVersionKind, []error) {
   110  	var listErrors []error
   111  	fields, ok := object.(map[string]interface{})
   112  	if !ok || fields == nil {
   113  		listErrors = append(listErrors, errors.New("invalid object to validate"))
   114  		return schema.GroupVersionKind{}, listErrors
   115  	}
   116  
   117  	var group string
   118  	var version string
   119  	apiVersion := fields["apiVersion"]
   120  	if apiVersion == nil {
   121  		listErrors = append(listErrors, errors.New("apiVersion not set"))
   122  	} else if _, ok := apiVersion.(string); !ok {
   123  		listErrors = append(listErrors, errors.New("apiVersion isn't string type"))
   124  	} else {
   125  		gv, err := schema.ParseGroupVersion(apiVersion.(string))
   126  		if err != nil {
   127  			listErrors = append(listErrors, err)
   128  		} else {
   129  			group = gv.Group
   130  			version = gv.Version
   131  		}
   132  	}
   133  	kind := fields["kind"]
   134  	if kind == nil {
   135  		listErrors = append(listErrors, errors.New("kind not set"))
   136  	} else if _, ok := kind.(string); !ok {
   137  		listErrors = append(listErrors, errors.New("kind isn't string type"))
   138  	}
   139  	if listErrors != nil {
   140  		return schema.GroupVersionKind{}, listErrors
   141  	}
   142  
   143  	return schema.GroupVersionKind{Group: group, Version: version, Kind: kind.(string)}, nil
   144  }
   145  

View as plain text