github.com/kubesphere/s2irun@v3.2.1+incompatible/pkg/api/validation/validation.go (about)

     1  package validation
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/docker/distribution/reference"
     8  
     9  	"github.com/kubesphere/s2irun/pkg/api"
    10  )
    11  
    12  // ValidateConfig returns a list of error from validation.
    13  func ValidateConfig(config *api.Config) []Error {
    14  	allErrs := []Error{}
    15  	if len(config.BuilderImage) == 0 {
    16  		allErrs = append(allErrs, NewFieldRequired("builderImage"))
    17  	}
    18  	switch config.BuilderPullPolicy {
    19  	case api.PullNever, api.PullAlways, api.PullIfNotPresent:
    20  	default:
    21  		allErrs = append(allErrs, NewFieldInvalidValueObj("builderPullPolicy", config.BuilderPullPolicy))
    22  	}
    23  	if config.DockerConfig == nil || len(config.DockerConfig.Endpoint) == 0 {
    24  		allErrs = append(allErrs, NewFieldRequired("dockerConfig.endpoint"))
    25  	}
    26  	if config.DockerNetworkMode != "" && !validateDockerNetworkMode(config.DockerNetworkMode) {
    27  		allErrs = append(allErrs, NewFieldInvalidValueObj("dockerNetworkMode", config.DockerNetworkMode))
    28  	}
    29  	if config.Labels != nil {
    30  		for k := range config.Labels {
    31  			if len(k) == 0 {
    32  				allErrs = append(allErrs, NewFieldInvalidValueWithReason("labels", "contains empty label"))
    33  			}
    34  		}
    35  	}
    36  	if config.Tag != "" {
    37  		if err := validateDockerReference(config.Tag); err != nil {
    38  			allErrs = append(allErrs, NewFieldInvalidValueWithReasonAndValue("tag", err.Error(), config.Tag))
    39  		}
    40  	}
    41  	return allErrs
    42  }
    43  
    44  // validateDockerNetworkMode checks wether the network mode conforms to the docker remote API specification (v1.19)
    45  // Supported values are: bridge, host, container:<name|id>, and netns:/proc/<pid>/ns/net
    46  func validateDockerNetworkMode(mode api.DockerNetworkMode) bool {
    47  	switch mode {
    48  	case api.DockerNetworkModeBridge, api.DockerNetworkModeHost:
    49  		return true
    50  	}
    51  	if strings.HasPrefix(string(mode), api.DockerNetworkModeContainerPrefix) {
    52  		return true
    53  	}
    54  	if strings.HasPrefix(string(mode), api.DockerNetworkModeNetworkNamespacePrefix) {
    55  		return true
    56  	}
    57  	return false
    58  }
    59  
    60  func validateDockerReference(ref string) error {
    61  	_, err := reference.Parse(ref)
    62  	return err
    63  }
    64  
    65  // NewFieldRequired returns a *ValidationError indicating "value required"
    66  func NewFieldRequired(field string) Error {
    67  	return Error{Type: ErrorTypeRequired, Field: field}
    68  }
    69  
    70  // NewFieldInvalidValue returns a ValidationError indicating "invalid value"
    71  func NewFieldInvalidValue(field string) Error {
    72  	return Error{Type: ErrorInvalidValue, Field: field}
    73  }
    74  
    75  // NewFieldInvalidValueObj returns a ValidationError indicating "invalid value"
    76  func NewFieldInvalidValueObj(field string, value interface{}) Error {
    77  	return Error{Type: ErrorInvalidValue, Field: field, Value: value}
    78  }
    79  
    80  // NewFieldInvalidValueWithReason returns a ValidationError indicating "invalid value" and a reason for the error
    81  func NewFieldInvalidValueWithReason(field, reason string) Error {
    82  	return Error{Type: ErrorInvalidValue, Field: field, Reason: reason}
    83  }
    84  
    85  // NewFieldInvalidValueWithReasonAndValue returns a ValidationError indicating the value and reason
    86  func NewFieldInvalidValueWithReasonAndValue(field, reason string, value interface{}) Error {
    87  	return Error{Type: ErrorInvalidValue, Field: field, Value: value, Reason: reason}
    88  }
    89  
    90  // ErrorType is a machine readable value providing more detail about why a field
    91  // is invalid.
    92  type ErrorType string
    93  
    94  const (
    95  	// ErrorTypeRequired is used to report required values that are not provided
    96  	// (e.g. empty strings, null values, or empty arrays).
    97  	ErrorTypeRequired ErrorType = "FieldValueRequired"
    98  
    99  	// ErrorInvalidValue is used to report values that do not conform to the
   100  	// expected schema.
   101  	ErrorInvalidValue ErrorType = "InvalidValue"
   102  )
   103  
   104  // Error is an implementation of the 'error' interface, which represents an
   105  // error of validation.
   106  type Error struct {
   107  	Type   ErrorType
   108  	Field  string
   109  	Value  interface{}
   110  	Reason string
   111  }
   112  
   113  func (v Error) Error() string {
   114  	var msg string
   115  	switch v.Type {
   116  	case ErrorInvalidValue:
   117  		msg = fmt.Sprintf("Invalid value specified for %q, value: %v", v.Field, v.Value)
   118  	case ErrorTypeRequired:
   119  		msg = fmt.Sprintf("Required value not specified for %q", v.Field)
   120  	default:
   121  		msg = fmt.Sprintf("%s: %s", v.Type, v.Field)
   122  	}
   123  	if len(v.Reason) > 0 {
   124  		msg = fmt.Sprintf("%s: %s", msg, v.Reason)
   125  	}
   126  	return msg
   127  }