github.com/openshift/source-to-image@v1.4.1-0.20240516041539-bf52fc02204e/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 }