mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	Fixes # https://github.com/kubernetes/kubernetes/issues/70802 Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
		
			
				
	
	
		
			134 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2016 Qiang Xue. All rights reserved.
 | |
| // Use of this source code is governed by a MIT-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| // Package validation provides configurable and extensible rules for validating data of various types.
 | |
| package validation
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"reflect"
 | |
| 	"strconv"
 | |
| )
 | |
| 
 | |
| type (
 | |
| 	// Validatable is the interface indicating the type implementing it supports data validation.
 | |
| 	Validatable interface {
 | |
| 		// Validate validates the data and returns an error if validation fails.
 | |
| 		Validate() error
 | |
| 	}
 | |
| 
 | |
| 	// Rule represents a validation rule.
 | |
| 	Rule interface {
 | |
| 		// Validate validates a value and returns a value if validation fails.
 | |
| 		Validate(value interface{}) error
 | |
| 	}
 | |
| 
 | |
| 	// RuleFunc represents a validator function.
 | |
| 	// You may wrap it as a Rule by calling By().
 | |
| 	RuleFunc func(value interface{}) error
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// ErrorTag is the struct tag name used to customize the error field name for a struct field.
 | |
| 	ErrorTag = "json"
 | |
| 
 | |
| 	// Skip is a special validation rule that indicates all rules following it should be skipped.
 | |
| 	Skip = &skipRule{}
 | |
| 
 | |
| 	validatableType = reflect.TypeOf((*Validatable)(nil)).Elem()
 | |
| )
 | |
| 
 | |
| // Validate validates the given value and returns the validation error, if any.
 | |
| //
 | |
| // Validate performs validation using the following steps:
 | |
| // - validate the value against the rules passed in as parameters
 | |
| // - if the value is a map and the map values implement `Validatable`, call `Validate` of every map value
 | |
| // - if the value is a slice or array whose values implement `Validatable`, call `Validate` of every element
 | |
| func Validate(value interface{}, rules ...Rule) error {
 | |
| 	for _, rule := range rules {
 | |
| 		if _, ok := rule.(*skipRule); ok {
 | |
| 			return nil
 | |
| 		}
 | |
| 		if err := rule.Validate(value); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	rv := reflect.ValueOf(value)
 | |
| 	if (rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface) && rv.IsNil() {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	if v, ok := value.(Validatable); ok {
 | |
| 		return v.Validate()
 | |
| 	}
 | |
| 
 | |
| 	switch rv.Kind() {
 | |
| 	case reflect.Map:
 | |
| 		if rv.Type().Elem().Implements(validatableType) {
 | |
| 			return validateMap(rv)
 | |
| 		}
 | |
| 	case reflect.Slice, reflect.Array:
 | |
| 		if rv.Type().Elem().Implements(validatableType) {
 | |
| 			return validateSlice(rv)
 | |
| 		}
 | |
| 	case reflect.Ptr, reflect.Interface:
 | |
| 		return Validate(rv.Elem().Interface())
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // validateMap validates a map of validatable elements
 | |
| func validateMap(rv reflect.Value) error {
 | |
| 	errs := Errors{}
 | |
| 	for _, key := range rv.MapKeys() {
 | |
| 		if mv := rv.MapIndex(key).Interface(); mv != nil {
 | |
| 			if err := mv.(Validatable).Validate(); err != nil {
 | |
| 				errs[fmt.Sprintf("%v", key.Interface())] = err
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if len(errs) > 0 {
 | |
| 		return errs
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // validateMap validates a slice/array of validatable elements
 | |
| func validateSlice(rv reflect.Value) error {
 | |
| 	errs := Errors{}
 | |
| 	l := rv.Len()
 | |
| 	for i := 0; i < l; i++ {
 | |
| 		if ev := rv.Index(i).Interface(); ev != nil {
 | |
| 			if err := ev.(Validatable).Validate(); err != nil {
 | |
| 				errs[strconv.Itoa(i)] = err
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if len(errs) > 0 {
 | |
| 		return errs
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type skipRule struct{}
 | |
| 
 | |
| func (r *skipRule) Validate(interface{}) error {
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type inlineRule struct {
 | |
| 	f RuleFunc
 | |
| }
 | |
| 
 | |
| func (r *inlineRule) Validate(value interface{}) error {
 | |
| 	return r.f(value)
 | |
| }
 | |
| 
 | |
| // By wraps a RuleFunc into a Rule.
 | |
| func By(f RuleFunc) Rule {
 | |
| 	return &inlineRule{f}
 | |
| }
 |