func ValidateImageLabels(labels []buildapi.ImageLabel, fldPath *field.Path) (allErrs field.ErrorList) { for i, lbl := range labels { idxPath := fldPath.Index(i) if len(lbl.Name) == 0 { allErrs = append(allErrs, field.Required(idxPath.Child("name"), "")) continue } for _, msg := range kvalidation.IsConfigMapKey(lbl.Name) { allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), lbl.Name, msg)) } } // find duplicates seen := make(map[string]bool) for i, lbl := range labels { idxPath := fldPath.Index(i) if seen[lbl.Name] { allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), lbl.Name, "duplicate name")) continue } seen[lbl.Name] = true } return }
func ValidateDisabledFeatures(disabledFeatures []string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, feature := range disabledFeatures { if _, isKnown := api.NormalizeOpenShiftFeature(feature); !isKnown { allErrs = append(allErrs, field.Invalid(fldPath.Index(i), disabledFeatures[i], fmt.Sprintf("not one of valid features: %s", strings.Join(api.KnownOpenShiftFeatures, ", ")))) } } return allErrs }
func validateHookVolumes(volumes []string, fldPath *field.Path) field.ErrorList { errs := field.ErrorList{} for i, vol := range volumes { vErrs := field.ErrorList{} if len(vol) == 0 { vErrs = append(vErrs, field.Invalid(fldPath.Index(i), "", "must not be empty")) } errs = append(errs, vErrs...) } return errs }
func validateIngressTLS(spec *extensions.IngressSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} // Currently the Ingress only supports HTTP(S), so a secretName is required. // This will not be the case if we support SSL routing at L4 via SNI. for i, t := range spec.TLS { if t.SecretName == "" { allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("secretName"), spec.TLS[i].SecretName)) } } // TODO: Perform a more thorough validation of spec.TLS.Hosts that takes // the wildcard spec from RFC 6125 into account. return allErrs }
func validateIngressRules(ingressRules []extensions.IngressRule, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if len(ingressRules) == 0 { return append(allErrs, field.Required(fldPath, "")) } for i, ih := range ingressRules { if len(ih.Host) > 0 { if isIP := (net.ParseIP(ih.Host) != nil); isIP { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, "must be a DNS name, not an IP address")) } // TODO: Ports and ips are allowed in the host part of a url // according to RFC 3986, consider allowing them. if strings.Contains(ih.Host, "*") { for _, msg := range validation.IsWildcardDNS1123Subdomain(ih.Host) { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, msg)) } continue } for _, msg := range validation.IsDNS1123Subdomain(ih.Host) { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, msg)) } } allErrs = append(allErrs, validateIngressRuleValue(&ih.IngressRuleValue, fldPath.Index(0))...) } return allErrs }
func validateServiceAccountNames(serviceAccountNames []string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, sa := range serviceAccountNames { idxPath := fldPath.Index(i) switch { case len(sa) == 0: allErrs = append(allErrs, field.Invalid(idxPath, sa, "")) case len(sa) > 0: if reasons := kapivalidation.ValidateServiceAccountName(sa, false); len(reasons) != 0 { allErrs = append(allErrs, field.Invalid(idxPath, sa, strings.Join(reasons, ", "))) } } } return allErrs }
// validatePodSecurityPolicySysctls validates the sysctls fields of PodSecurityPolicy. func validatePodSecurityPolicySysctls(fldPath *field.Path, sysctls []string) field.ErrorList { allErrs := field.ErrorList{} for i, s := range sysctls { if !IsValidSysctlPattern(string(s)) { allErrs = append( allErrs, field.Invalid(fldPath.Index(i), sysctls[i], fmt.Sprintf("must have at most %d characters and match regex %s", apivalidation.SysctlMaxLength, SysctlPatternFmt, )), ) } } return allErrs }
func validateEnv(vars []kapi.EnvVar, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, ev := range vars { vErrs := field.ErrorList{} idxPath := fldPath.Index(i).Child("name") if len(ev.Name) == 0 { vErrs = append(vErrs, field.Required(idxPath, "")) } if errs := kvalidation.IsCIdentifier(ev.Name); len(errs) > 0 { vErrs = append(vErrs, field.Invalid(idxPath, ev.Name, strings.Join(errs, ", "))) } allErrs = append(allErrs, vErrs...) } return allErrs }
func ValidateStrategyEnv(vars []kapi.EnvVar, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, ev := range vars { idxPath := fldPath.Index(i) if len(ev.Name) == 0 { allErrs = append(allErrs, field.Required(idxPath.Child("name"), "")) } else if !kvalidation.IsCIdentifier(ev.Name) { allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, cIdentifierErrorMsg)) } if ev.ValueFrom != nil { allErrs = append(allErrs, field.Invalid(idxPath.Child("valueFrom"), ev.ValueFrom, "valueFrom is not supported in build strategy environment variables")) } } return allErrs }
func validateEnv(vars []kapi.EnvVar, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, ev := range vars { vErrs := field.ErrorList{} idxPath := fldPath.Index(i).Child("name") if len(ev.Name) == 0 { vErrs = append(vErrs, field.Required(idxPath, "")) } if !kvalidation.IsCIdentifier(ev.Name) { vErrs = append(vErrs, field.Invalid(idxPath, ev.Name, "must match regex "+kvalidation.CIdentifierFmt)) } allErrs = append(allErrs, vErrs...) } return allErrs }
func validateIngressTLS(spec *extensions.IngressSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} // TODO: Perform a more thorough validation of spec.TLS.Hosts that takes // the wildcard spec from RFC 6125 into account. for _, itls := range spec.TLS { for i, host := range itls.Hosts { if strings.Contains(host, "*") { for _, msg := range validation.IsWildcardDNS1123Subdomain(host) { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("hosts"), host, msg)) } continue } for _, msg := range validation.IsDNS1123Subdomain(host) { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("hosts"), host, msg)) } } } return allErrs }
func ValidateAPILevels(apiLevels []string, knownAPILevels, deadAPILevels []string, fldPath *field.Path) ValidationResults { validationResults := ValidationResults{} if len(apiLevels) == 0 { validationResults.AddErrors(field.Required(fldPath, "")) } deadLevels := sets.NewString(deadAPILevels...) knownLevels := sets.NewString(knownAPILevels...) for i, apiLevel := range apiLevels { idxPath := fldPath.Index(i) if deadLevels.Has(apiLevel) { validationResults.AddWarnings(field.Invalid(idxPath, apiLevel, "unsupported level")) } if !knownLevels.Has(apiLevel) { validationResults.AddWarnings(field.Invalid(idxPath, apiLevel, "unknown level")) } } return validationResults }
// Ensures that `nil` can be passed to validation functions validating top-level objects func TestNilPath(t *testing.T) { var nilPath *field.Path = nil if s := nilPath.String(); s != "" { t.Errorf("Unexpected nil path: %q", s) } child := nilPath.Child("child") if s := child.String(); s != "child" { t.Errorf("Unexpected child path: %q", s) } key := nilPath.Key("key") if s := key.String(); s != "[key]" { t.Errorf("Unexpected key path: %q", s) } index := nilPath.Index(1) if s := index.String(); s != "[1]" { t.Errorf("Unexpected index path: %q", s) } }
func AccumulateUniqueHostPorts(containers []v1.Container, accumulator *sets.String, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for ci, ctr := range containers { idxPath := fldPath.Index(ci) portsPath := idxPath.Child("ports") for pi := range ctr.Ports { idxPath := portsPath.Index(pi) port := ctr.Ports[pi].HostPort if port == 0 { continue } str := fmt.Sprintf("%d/%s", port, ctr.Ports[pi].Protocol) if accumulator.Has(str) { allErrs = append(allErrs, field.Duplicate(idxPath.Child("hostPort"), str)) } else { accumulator.Insert(str) } } } return allErrs }
func validateSecrets(secrets []buildapi.SecretBuildSource, isDockerStrategy bool, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, s := range secrets { if len(s.Secret.Name) == 0 { allErrs = append(allErrs, field.Required(fldPath.Index(i).Child("secret"))) } if ok, _ := validation.ValidateSecretName(s.Secret.Name, false); !ok { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("secret"), s, "must be valid secret name")) } if strings.HasPrefix(path.Clean(s.DestinationDir), "..") { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("destinationDir"), s.DestinationDir, "destination dir cannot start with '..'")) } if isDockerStrategy && filepath.IsAbs(s.DestinationDir) { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("destinationDir"), s.DestinationDir, "for the docker strategy the destinationDir has to be relative path")) } } return allErrs }
func validateIngressRules(IngressRules []extensions.IngressRule, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if len(IngressRules) == 0 { return append(allErrs, field.Required(fldPath, "")) } for i, ih := range IngressRules { if len(ih.Host) > 0 { // TODO: Ports and ips are allowed in the host part of a url // according to RFC 3986, consider allowing them. if valid, errMsg := apivalidation.NameIsDNSSubdomain(ih.Host, false); !valid { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, errMsg)) } if isIP := (net.ParseIP(ih.Host) != nil); isIP { allErrs = append(allErrs, field.Invalid(fldPath.Index(i).Child("host"), ih.Host, "must be a DNS name, not an IP address")) } } allErrs = append(allErrs, validateIngressRuleValue(&ih.IngressRuleValue, fldPath.Index(0))...) } return allErrs }
func ValidateScopes(scopes []string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, scope := range scopes { illegalCharacter := false // https://tools.ietf.org/html/rfc6749#section-3.3 (full list of allowed chars is %x21 / %x23-5B / %x5D-7E) // for those without an ascii table, that's `!`, `#-[`, `]-~` inclusive. for _, ch := range scope { switch { case ch == '!': case ch >= '#' && ch <= '[': case ch >= ']' && ch <= '~': default: allErrs = append(allErrs, field.Invalid(fldPath.Index(i), scope, fmt.Sprintf("%v not allowed", ch))) illegalCharacter = true } } if illegalCharacter { continue } found := false for _, evaluator := range authorizerscopes.ScopeEvaluators { if !evaluator.Handles(scope) { continue } found = true if err := evaluator.Validate(scope); err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Index(i), scope, err.Error())) break } } if !found { allErrs = append(allErrs, field.Invalid(fldPath.Index(i), scope, "no scope handler found")) } } return allErrs }
func objectReflectDiff(path *field.Path, a, b reflect.Value) []diff { switch a.Type().Kind() { case reflect.Struct: var changes []diff for i := 0; i < a.Type().NumField(); i++ { if !public(a.Type().Field(i).Name) { if reflect.DeepEqual(a.Interface(), b.Interface()) { return nil } return []diff{{path: path, a: fmt.Sprintf("%#v", a), b: fmt.Sprintf("%#v", b)}} } if sub := objectReflectDiff(path.Child(a.Type().Field(i).Name), a.Field(i), b.Field(i)); len(sub) > 0 { changes = append(changes, sub...) } } return changes case reflect.Ptr: if a.IsNil() || b.IsNil() { switch { case a.IsNil() && b.IsNil(): return nil case a.IsNil(): return []diff{{path: path, a: nil, b: b.Interface()}} default: return []diff{{path: path, a: a.Interface(), b: nil}} } } return objectReflectDiff(path, a.Elem(), b.Elem()) case reflect.Chan: if !reflect.DeepEqual(a.Interface(), b.Interface()) { return []diff{{path: path, a: a.Interface(), b: b.Interface()}} } return nil case reflect.Slice: if reflect.DeepEqual(a, b) { return nil } lA, lB := a.Len(), b.Len() l := lA if lB < lA { l = lB } for i := 0; i < l; i++ { if !reflect.DeepEqual(a.Index(i), b.Index(i)) { return objectReflectDiff(path.Index(i), a.Index(i), b.Index(i)) } } var diffs []diff for i := l; l < lA; i++ { diffs = append(diffs, diff{path: path.Index(i), a: a.Index(i), b: nil}) } for i := l; l < lB; i++ { diffs = append(diffs, diff{path: path.Index(i), a: nil, b: b.Index(i)}) } return diffs case reflect.Map: if reflect.DeepEqual(a, b) { return nil } aKeys := make(map[interface{}]interface{}) for _, key := range a.MapKeys() { aKeys[key.Interface()] = a.MapIndex(key).Interface() } var missing []diff for _, key := range b.MapKeys() { if _, ok := aKeys[key.Interface()]; ok { delete(aKeys, key.Interface()) if reflect.DeepEqual(a.MapIndex(key).Interface(), b.MapIndex(key).Interface()) { continue } missing = append(missing, diff{path: path.Key(fmt.Sprintf("%s", key.Interface())), a: a.MapIndex(key).Interface(), b: b.MapIndex(key).Interface()}) continue } missing = append(missing, diff{path: path.Key(fmt.Sprintf("%s", key.Interface())), a: nil, b: b.MapIndex(key).Interface()}) } for key, value := range aKeys { missing = append(missing, diff{path: path.Key(fmt.Sprintf("%s", key)), a: value, b: nil}) } sort.Sort(orderedDiffs(missing)) return missing default: if reflect.DeepEqual(a.Interface(), b.Interface()) { return nil } if !a.CanInterface() { return []diff{{path: path, a: fmt.Sprintf("%#v", a), b: fmt.Sprintf("%#v", b)}} } return []diff{{path: path, a: a.Interface(), b: b.Interface()}} } }
func ValidateNamedCertificates(fldPath *field.Path, namedCertificates []api.NamedCertificate) ValidationResults { validationResults := ValidationResults{} takenNames := sets.NewString() for i, namedCertificate := range namedCertificates { idxPath := fldPath.Index(i) certDNSNames := []string{} if len(namedCertificate.CertFile) == 0 { validationResults.AddErrors(field.Required(idxPath.Child("certInfo"), "")) } else if certInfoErrors := ValidateCertInfo(namedCertificate.CertInfo, false, idxPath); len(certInfoErrors) > 0 { validationResults.AddErrors(certInfoErrors...) } else if cert, err := tls.LoadX509KeyPair(namedCertificate.CertFile, namedCertificate.KeyFile); err != nil { validationResults.AddErrors(field.Invalid(idxPath.Child("certInfo"), namedCertificate.CertInfo, fmt.Sprintf("error loading certificate/key: %v", err))) } else { leaf, _ := x509.ParseCertificate(cert.Certificate[0]) certDNSNames = append(certDNSNames, leaf.Subject.CommonName) certDNSNames = append(certDNSNames, leaf.DNSNames...) } if len(namedCertificate.Names) == 0 { validationResults.AddErrors(field.Required(idxPath.Child("names"), "")) } for j, name := range namedCertificate.Names { jdxPath := idxPath.Child("names").Index(j) if len(name) == 0 { validationResults.AddErrors(field.Required(jdxPath, "")) continue } if takenNames.Has(name) { validationResults.AddErrors(field.Invalid(jdxPath, name, "this name is already used in another named certificate")) continue } // validate names as domain names or *.*.foo.com domain names validDNSName := true for _, s := range strings.Split(name, ".") { if s != "*" && len(utilvalidation.IsDNS1123Label(s)) != 0 { validDNSName = false } } if !validDNSName { validationResults.AddErrors(field.Invalid(jdxPath, name, "must be a valid DNS name")) continue } takenNames.Insert(name) // validate certificate has common name or subject alt names that match if len(certDNSNames) > 0 { foundMatch := false for _, dnsName := range certDNSNames { if cmdutil.HostnameMatches(dnsName, name) { foundMatch = true break } // if the cert has a wildcard dnsName, and we've configured a non-wildcard name, see if our specified name will match against the dnsName. if strings.HasPrefix(dnsName, "*.") && !strings.HasPrefix(name, "*.") && cmdutil.HostnameMatches(name, dnsName) { foundMatch = true break } } if !foundMatch { validationResults.AddWarnings(field.Invalid(jdxPath, name, "the specified certificate does not have a CommonName or DNS subjectAltName that matches this name")) } } } } return validationResults }