github.imxd.top/openshift/source-to-image@v1.2.0/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/openshift/source-to-image/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, NewFieldInvalidValue("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, NewFieldInvalidValue("dockerNetworkMode"))
    28  	}
    29  	if config.Labels != nil {
    30  		for k := range config.Labels {
    31  			if len(k) == 0 {
    32  				allErrs = append(allErrs, NewFieldInvalidValue("labels"))
    33  			}
    34  		}
    35  	}
    36  	if config.Tag != "" {
    37  		if err := validateDockerReference(config.Tag); err != nil {
    38  			allErrs = append(allErrs, NewFieldInvalidValueWithReason("tag", err.Error()))
    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  // NewFieldInvalidValueWithReason returns a ValidationError indicating "invalid value" and a reason for the error
    76  func NewFieldInvalidValueWithReason(field, reason string) Error {
    77  	return Error{Type: ErrorInvalidValue, Field: field, Reason: reason}
    78  }
    79  
    80  // ErrorType is a machine readable value providing more detail about why a field
    81  // is invalid.
    82  type ErrorType string
    83  
    84  const (
    85  	// ErrorTypeRequired is used to report required values that are not provided
    86  	// (e.g. empty strings, null values, or empty arrays).
    87  	ErrorTypeRequired ErrorType = "FieldValueRequired"
    88  
    89  	// ErrorInvalidValue is used to report values that do not conform to the
    90  	// expected schema.
    91  	ErrorInvalidValue ErrorType = "InvalidValue"
    92  )
    93  
    94  // Error is an implementation of the 'error' interface, which represents an
    95  // error of validation.
    96  type Error struct {
    97  	Type   ErrorType
    98  	Field  string
    99  	Reason string
   100  }
   101  
   102  func (v Error) Error() string {
   103  	var msg string
   104  	switch v.Type {
   105  	case ErrorInvalidValue:
   106  		msg = fmt.Sprintf("Invalid value specified for %q", v.Field)
   107  	case ErrorTypeRequired:
   108  		msg = fmt.Sprintf("Required value not specified for %q", v.Field)
   109  	default:
   110  		msg = fmt.Sprintf("%s: %s", v.Type, v.Field)
   111  	}
   112  	if len(v.Reason) > 0 {
   113  		msg = fmt.Sprintf("%s: %s", msg, v.Reason)
   114  	}
   115  	return msg
   116  }