Update godeps

This commit is contained in:
Manuel de Brito Fontes 2016-07-11 23:42:47 -04:00
parent 8b25cc67a5
commit a736fba0e1
769 changed files with 15495 additions and 7996 deletions

View file

@ -1,5 +1,5 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Copyright 2014 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,12 +19,10 @@ package validation
import (
"encoding/json"
"fmt"
"math"
"net"
"os"
"path"
"reflect"
"regexp"
"strings"
"github.com/golang/glog"
@ -51,17 +49,9 @@ var RepairMalformedUpdates bool = true
const isNegativeErrorMsg string = `must be greater than or equal to 0`
const isInvalidQuotaResource string = `must be a standard resource for quota`
const fieldImmutableErrorMsg string = `field is immutable`
const cIdentifierErrorMsg string = `must be a C identifier (matching regex ` + validation.CIdentifierFmt + `): e.g. "my_name" or "MyName"`
const isNotIntegerErrorMsg string = `must be an integer`
func InclusiveRangeErrorMsg(lo, hi int) string {
return fmt.Sprintf(`must be between %d and %d, inclusive`, lo, hi)
}
var pdPartitionErrorMsg string = InclusiveRangeErrorMsg(1, 255)
var PortRangeErrorMsg string = InclusiveRangeErrorMsg(1, 65535)
var IdRangeErrorMsg string = InclusiveRangeErrorMsg(0, math.MaxInt32)
var PortNameErrorMsg string = fmt.Sprintf(`must be an IANA_SVC_NAME (at most 15 characters, matching regex %s, it must contain at least one letter [a-z], and hyphens cannot be adjacent to other hyphens): e.g. "http"`, validation.IdentifierNoHyphensBeginEndFmt)
var pdPartitionErrorMsg string = validation.InclusiveRangeError(1, 255)
const totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
@ -75,11 +65,13 @@ func ValidateHasLabel(meta api.ObjectMeta, fldPath *field.Path, key, expectedVal
allErrs := field.ErrorList{}
actualValue, found := meta.Labels[key]
if !found {
allErrs = append(allErrs, field.Required(fldPath.Child("labels"), key+"="+expectedValue))
allErrs = append(allErrs, field.Required(fldPath.Child("labels").Key(key),
fmt.Sprintf("must be '%s'", expectedValue)))
return allErrs
}
if actualValue != expectedValue {
allErrs = append(allErrs, field.Invalid(fldPath.Child("labels"), meta.Labels, "expected "+key+"="+expectedValue))
allErrs = append(allErrs, field.Invalid(fldPath.Child("labels").Key(key), meta.Labels,
fmt.Sprintf("must be '%s'", expectedValue)))
}
return allErrs
}
@ -100,6 +92,14 @@ func ValidateAnnotations(annotations map[string]string, fldPath *field.Path) fie
return allErrs
}
func ValidateDNS1123Label(value string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
for _, msg := range validation.IsDNS1123Label(value) {
allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
}
return allErrs
}
func ValidatePodSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if annotations[api.AffinityAnnotationKey] != "" {
@ -110,16 +110,12 @@ func ValidatePodSpecificAnnotations(annotations map[string]string, fldPath *fiel
allErrs = append(allErrs, ValidateTolerationsInPodAnnotations(annotations, fldPath)...)
}
// TODO: remove these after we EOL the annotations.
if hostname, exists := annotations[utilpod.PodHostnameAnnotation]; exists {
for _, msg := range validation.IsDNS1123Label(hostname) {
allErrs = append(allErrs, field.Invalid(fldPath, utilpod.PodHostnameAnnotation, msg))
}
allErrs = append(allErrs, ValidateDNS1123Label(hostname, fldPath.Key(utilpod.PodHostnameAnnotation))...)
}
if subdomain, exists := annotations[utilpod.PodSubdomainAnnotation]; exists {
for _, msg := range validation.IsDNS1123Label(subdomain) {
allErrs = append(allErrs, field.Invalid(fldPath, utilpod.PodSubdomainAnnotation, msg))
}
allErrs = append(allErrs, ValidateDNS1123Label(subdomain, fldPath.Key(utilpod.PodSubdomainAnnotation))...)
}
allErrs = append(allErrs, ValidateSeccompPodAnnotations(annotations, fldPath)...)
@ -129,6 +125,7 @@ func ValidatePodSpecificAnnotations(annotations map[string]string, fldPath *fiel
func ValidateEndpointsSpecificAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
// TODO: remove this after we EOL the annotation.
hostnamesMap, exists := annotations[endpoints.PodHostnamesAnnotation]
if exists && !isValidHostnamesMap(hostnamesMap) {
allErrs = append(allErrs, field.Invalid(fldPath, endpoints.PodHostnamesAnnotation,
@ -382,6 +379,11 @@ func ValidateObjectMetaUpdate(newMeta, oldMeta *api.ObjectMeta, fldPath *field.P
allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newMeta.ResourceVersion, "must be specified for an update"))
}
// Generation shouldn't be decremented
if newMeta.Generation < oldMeta.Generation {
allErrs = append(allErrs, field.Invalid(fldPath.Child("generation"), newMeta.Generation, "must not be decremented"))
}
allErrs = append(allErrs, ValidateImmutableField(newMeta.Name, oldMeta.Name, fldPath.Child("name"))...)
allErrs = append(allErrs, ValidateImmutableField(newMeta.Namespace, oldMeta.Namespace, fldPath.Child("namespace"))...)
allErrs = append(allErrs, ValidateImmutableField(newMeta.UID, oldMeta.UID, fldPath.Child("uid"))...)
@ -400,15 +402,15 @@ func validateVolumes(volumes []api.Volume, fldPath *field.Path) (sets.String, fi
allNames := sets.String{}
for i, vol := range volumes {
idxPath := fldPath.Index(i)
namePath := idxPath.Child("name")
el := validateVolumeSource(&vol.VolumeSource, idxPath)
if len(vol.Name) == 0 {
el = append(el, field.Required(idxPath.Child("name"), ""))
} else if msgs := validation.IsDNS1123Label(vol.Name); len(msgs) != 0 {
for i := range msgs {
el = append(el, field.Invalid(idxPath.Child("name"), vol.Name, msgs[i]))
}
} else if allNames.Has(vol.Name) {
el = append(el, field.Duplicate(idxPath.Child("name"), vol.Name))
el = append(el, field.Required(namePath, ""))
} else {
el = append(el, ValidateDNS1123Label(vol.Name, namePath)...)
}
if allNames.Has(vol.Name) {
el = append(el, field.Duplicate(namePath, vol.Name))
}
if len(el) == 0 {
allNames.Insert(vol.Name)
@ -610,7 +612,7 @@ func validateISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, fldPath *field.Path
allErrs = append(allErrs, field.Required(fldPath.Child("iqn"), ""))
}
if iscsi.Lun < 0 || iscsi.Lun > 255 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, InclusiveRangeErrorMsg(0, 255)))
allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), iscsi.Lun, validation.InclusiveRangeError(0, 255)))
}
return allErrs
}
@ -625,7 +627,7 @@ func validateFCVolumeSource(fc *api.FCVolumeSource, fldPath *field.Path) field.E
allErrs = append(allErrs, field.Required(fldPath.Child("lun"), ""))
} else {
if *fc.Lun < 0 || *fc.Lun > 255 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), fc.Lun, InclusiveRangeErrorMsg(0, 255)))
allErrs = append(allErrs, field.Invalid(fldPath.Child("lun"), fc.Lun, validation.InclusiveRangeError(0, 255)))
}
}
return allErrs
@ -1020,11 +1022,18 @@ func ValidatePersistentVolumeClaim(pvc *api.PersistentVolumeClaim) field.ErrorLi
func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidatePersistentVolumeClaim(newPvc)...)
// if a pvc had a bound volume, we should not allow updates to resources or access modes
if len(oldPvc.Spec.VolumeName) != 0 {
if !api.Semantic.DeepEqual(newPvc.Spec, oldPvc.Spec) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "spec is immutable once a claim has been bound to a volume"))
}
// PVController needs to update PVC.Spec w/ VolumeName.
// Claims are immutable in order to enforce quota, range limits, etc. without gaming the system.
if len(oldPvc.Spec.VolumeName) == 0 {
// volumeName changes are allowed once.
// Reset back to empty string after equality check
oldPvc.Spec.VolumeName = newPvc.Spec.VolumeName
defer func() { oldPvc.Spec.VolumeName = "" }()
}
// changes to Spec are not allowed, but updates to label/annotations are OK.
// no-op updates pass validation.
if !api.Semantic.DeepEqual(newPvc.Spec, oldPvc.Spec) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "field is immutable after creation"))
}
newPvc.Status = oldPvc.Status
return allErrs
@ -1055,8 +1064,10 @@ func validateContainerPorts(ports []api.ContainerPort, fldPath *field.Path) fiel
for i, port := range ports {
idxPath := fldPath.Index(i)
if len(port.Name) > 0 {
if !validation.IsValidPortName(port.Name) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), port.Name, PortNameErrorMsg))
if msgs := validation.IsValidPortName(port.Name); len(msgs) != 0 {
for i = range msgs {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), port.Name, msgs[i]))
}
} else if allNames.Has(port.Name) {
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), port.Name))
} else {
@ -1064,12 +1075,16 @@ func validateContainerPorts(ports []api.ContainerPort, fldPath *field.Path) fiel
}
}
if port.ContainerPort == 0 {
allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, PortRangeErrorMsg))
} else if !validation.IsValidPortNum(int(port.ContainerPort)) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, PortRangeErrorMsg))
allErrs = append(allErrs, field.Required(idxPath.Child("containerPort"), ""))
} else {
for _, msg := range validation.IsValidPortNum(int(port.ContainerPort)) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("containerPort"), port.ContainerPort, msg))
}
}
if port.HostPort != 0 && !validation.IsValidPortNum(int(port.HostPort)) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("hostPort"), port.HostPort, PortRangeErrorMsg))
if port.HostPort != 0 {
for _, msg := range validation.IsValidPortNum(int(port.HostPort)) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("hostPort"), port.HostPort, msg))
}
}
if len(port.Protocol) == 0 {
allErrs = append(allErrs, field.Required(idxPath.Child("protocol"), ""))
@ -1087,8 +1102,10 @@ func validateEnv(vars []api.EnvVar, fldPath *field.Path) field.ErrorList {
idxPath := fldPath.Index(i)
if len(ev.Name) == 0 {
allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
} else if !validation.IsCIdentifier(ev.Name) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, cIdentifierErrorMsg))
} else {
for _, msg := range validation.IsCIdentifier(ev.Name) {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ev.Name, msg))
}
}
allErrs = append(allErrs, validateEnvVarValueFrom(ev, idxPath.Child("valueFrom"))...)
}
@ -1198,8 +1215,10 @@ func validateConfigMapKeySelector(s *api.ConfigMapKeySelector, fldPath *field.Pa
}
if len(s.Key) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
} else if !IsSecretKey(s.Key) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt)))
} else {
for _, msg := range validation.IsConfigMapKey(s.Key) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg))
}
}
return allErrs
@ -1213,8 +1232,10 @@ func validateSecretKeySelector(s *api.SecretKeySelector, fldPath *field.Path) fi
}
if len(s.Key) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
} else if !IsSecretKey(s.Key) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt)))
} else {
for _, msg := range validation.IsConfigMapKey(s.Key) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("key"), s.Key, msg))
}
}
return allErrs
@ -1303,36 +1324,43 @@ func validateExecAction(exec *api.ExecAction, fldPath *field.Path) field.ErrorLi
return allErrors
}
var supportedHTTPSchemes = sets.NewString(string(api.URISchemeHTTP), string(api.URISchemeHTTPS))
func validateHTTPGetAction(http *api.HTTPGetAction, fldPath *field.Path) field.ErrorList {
allErrors := field.ErrorList{}
if len(http.Path) == 0 {
allErrors = append(allErrors, field.Required(fldPath.Child("path"), ""))
}
if http.Port.Type == intstr.Int && !validation.IsValidPortNum(http.Port.IntValue()) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), http.Port, PortRangeErrorMsg))
} else if http.Port.Type == intstr.String && !validation.IsValidPortName(http.Port.StrVal) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), http.Port.StrVal, PortNameErrorMsg))
}
supportedSchemes := sets.NewString(string(api.URISchemeHTTP), string(api.URISchemeHTTPS))
if !supportedSchemes.Has(string(http.Scheme)) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("scheme"), http.Scheme, fmt.Sprintf("must be one of %v", supportedSchemes.List())))
allErrors = append(allErrors, ValidatePortNumOrName(http.Port, fldPath.Child("port"))...)
if !supportedHTTPSchemes.Has(string(http.Scheme)) {
allErrors = append(allErrors, field.NotSupported(fldPath.Child("scheme"), http.Scheme, supportedHTTPSchemes.List()))
}
for _, header := range http.HTTPHeaders {
if !validation.IsHTTPHeaderName(header.Name) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("httpHeaders"), header.Name, fmt.Sprintf("name must match %s", validation.HTTPHeaderNameFmt)))
for _, msg := range validation.IsHTTPHeaderName(header.Name) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("httpHeaders"), header.Name, msg))
}
}
return allErrors
}
func validateTCPSocketAction(tcp *api.TCPSocketAction, fldPath *field.Path) field.ErrorList {
allErrors := field.ErrorList{}
if tcp.Port.Type == intstr.Int && !validation.IsValidPortNum(tcp.Port.IntValue()) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), tcp.Port, PortRangeErrorMsg))
} else if tcp.Port.Type == intstr.String && !validation.IsValidPortName(tcp.Port.StrVal) {
allErrors = append(allErrors, field.Invalid(fldPath.Child("port"), tcp.Port.StrVal, PortNameErrorMsg))
func ValidatePortNumOrName(port intstr.IntOrString, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if port.Type == intstr.Int {
for _, msg := range validation.IsValidPortNum(port.IntValue()) {
allErrs = append(allErrs, field.Invalid(fldPath, port.IntValue(), msg))
}
} else if port.Type == intstr.String {
for _, msg := range validation.IsValidPortName(port.StrVal) {
allErrs = append(allErrs, field.Invalid(fldPath, port.StrVal, msg))
}
} else {
allErrs = append(allErrs, field.InternalError(fldPath, fmt.Errorf("unknown type: %v", port.Type)))
}
return allErrors
return allErrs
}
func validateTCPSocketAction(tcp *api.TCPSocketAction, fldPath *field.Path) field.ErrorList {
return ValidatePortNumOrName(tcp.Port, fldPath.Child("port"))
}
func validateHandler(handler *api.Handler, fldPath *field.Path) field.ErrorList {
@ -1437,14 +1465,14 @@ func validateContainers(containers []api.Container, volumes sets.String, fldPath
allNames := sets.String{}
for i, ctr := range containers {
idxPath := fldPath.Index(i)
namePath := idxPath.Child("name")
if len(ctr.Name) == 0 {
allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
} else if msgs := validation.IsDNS1123Label(ctr.Name); len(msgs) != 0 {
for i := range msgs {
allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), ctr.Name, msgs[i]))
}
} else if allNames.Has(ctr.Name) {
allErrs = append(allErrs, field.Duplicate(idxPath.Child("name"), ctr.Name))
allErrs = append(allErrs, field.Required(namePath, ""))
} else {
allErrs = append(allErrs, ValidateDNS1123Label(ctr.Name, namePath)...)
}
if allNames.Has(ctr.Name) {
allErrs = append(allErrs, field.Duplicate(namePath, ctr.Name))
} else {
allNames.Insert(ctr.Name)
}
@ -1633,15 +1661,11 @@ func ValidatePodSpec(spec *api.PodSpec, fldPath *field.Path) field.ErrorList {
}
if len(spec.Hostname) > 0 {
for _, msg := range validation.IsDNS1123Label(spec.Hostname) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("hostname"), spec.Hostname, msg))
}
allErrs = append(allErrs, ValidateDNS1123Label(spec.Hostname, fldPath.Child("hostname"))...)
}
if len(spec.Subdomain) > 0 {
for _, msg := range validation.IsDNS1123Label(spec.Subdomain) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("subdomain"), spec.Subdomain, msg))
}
allErrs = append(allErrs, ValidateDNS1123Label(spec.Subdomain, fldPath.Child("subdomain"))...)
}
return allErrs
@ -1881,16 +1905,19 @@ func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *a
if securityContext != nil {
allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers, specPath.Child("containers"))...)
if securityContext.FSGroup != nil && !validation.IsValidGroupId(*securityContext.FSGroup) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), IdRangeErrorMsg))
if securityContext.FSGroup != nil {
for _, msg := range validation.IsValidGroupId(*securityContext.FSGroup) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("fsGroup"), *(securityContext.FSGroup), msg))
}
}
if securityContext.RunAsUser != nil && !validation.IsValidUserId(*securityContext.RunAsUser) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *(securityContext.RunAsUser), IdRangeErrorMsg))
if securityContext.RunAsUser != nil {
for _, msg := range validation.IsValidUserId(*securityContext.RunAsUser) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("runAsUser"), *(securityContext.RunAsUser), msg))
}
}
for i, gid := range securityContext.SupplementalGroups {
if !validation.IsValidGroupId(gid) {
supplementalGroup := fmt.Sprintf(`supplementalGroups[%d]`, i)
allErrs = append(allErrs, field.Invalid(fldPath.Child(supplementalGroup), gid, IdRangeErrorMsg))
for g, gid := range securityContext.SupplementalGroups {
for _, msg := range validation.IsValidGroupId(gid) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("supplementalGroups").Index(g), gid, msg))
}
}
}
@ -2064,10 +2091,13 @@ func ValidateService(service *api.Service) field.ErrorList {
ipPath := specPath.Child("externalIPs")
for i, ip := range service.Spec.ExternalIPs {
idxPath := ipPath.Index(i)
if ip == "0.0.0.0" {
allErrs = append(allErrs, field.Invalid(idxPath, ip, "must be a valid IP address"))
if msgs := validation.IsValidIP(ip); len(msgs) != 0 {
for i := range msgs {
allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i]))
}
} else {
allErrs = append(allErrs, validateNonSpecialIP(ip, idxPath)...)
}
allErrs = append(allErrs, validateIpIsNotLinkLocalOrLoopback(ip, idxPath)...)
}
if len(service.Spec.Type) == 0 {
@ -2150,19 +2180,16 @@ func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService boo
if requireName && len(sp.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
} else if len(sp.Name) != 0 {
if msgs := validation.IsDNS1123Label(sp.Name); len(msgs) != 0 {
for i := range msgs {
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), sp.Name, msgs[i]))
}
} else if allNames.Has(sp.Name) {
allErrs = append(allErrs, ValidateDNS1123Label(sp.Name, fldPath.Child("name"))...)
if allNames.Has(sp.Name) {
allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), sp.Name))
} else {
allNames.Insert(sp.Name)
}
}
if !validation.IsValidPortNum(int(sp.Port)) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, PortRangeErrorMsg))
for _, msg := range validation.IsValidPortNum(int(sp.Port)) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), sp.Port, msg))
}
if len(sp.Protocol) == 0 {
@ -2171,12 +2198,7 @@ func validateServicePort(sp *api.ServicePort, requireName, isHeadlessService boo
allErrs = append(allErrs, field.NotSupported(fldPath.Child("protocol"), sp.Protocol, supportedPortProtocols.List()))
}
if sp.TargetPort.Type == intstr.Int && !validation.IsValidPortNum(sp.TargetPort.IntValue()) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, PortRangeErrorMsg))
}
if sp.TargetPort.Type == intstr.String && !validation.IsValidPortName(sp.TargetPort.StrVal) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("targetPort"), sp.TargetPort, PortNameErrorMsg))
}
allErrs = append(allErrs, ValidatePortNumOrName(sp.TargetPort, fldPath.Child("targetPort"))...)
// in the v1 API, targetPorts on headless services were tolerated.
// once we have version-specific validation, we can reject this on newer API versions, but until then, we have to tolerate it for compatibility.
@ -2243,7 +2265,7 @@ func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *field.Path
return allErrs
}
// Validates the given template and ensures that it is in accordance with the desrired selector and replicas.
// Validates the given template and ensures that it is in accordance with the desired selector and replicas.
func ValidatePodTemplateSpecForRC(template *api.PodTemplateSpec, selectorMap map[string]string, replicas int32, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if template == nil {
@ -2442,7 +2464,7 @@ func validateContainerResourceName(value string, fldPath *field.Path) field.Erro
// Validate resource names that can go in a resource quota
// Refer to docs/design/resources.md for more details.
func validateResourceQuotaResourceName(value string, fldPath *field.Path) field.ErrorList {
func ValidateResourceQuotaResourceName(value string, fldPath *field.Path) field.ErrorList {
allErrs := validateResourceName(value, fldPath)
if len(strings.Split(value, "/")) == 1 {
if !api.IsStandardQuotaResourceName(value) {
@ -2610,16 +2632,6 @@ func ValidateServiceAccountUpdate(newServiceAccount, oldServiceAccount *api.Serv
return allErrs
}
const SecretKeyFmt string = "\\.?" + validation.DNS1123LabelFmt + "(\\." + validation.DNS1123LabelFmt + ")*"
var secretKeyRegexp = regexp.MustCompile("^" + SecretKeyFmt + "$")
// IsSecretKey tests for a string that conforms to the definition of a
// subdomain in DNS (RFC 1123), except that a leading dot is allowed
func IsSecretKey(value string) bool {
return len(value) <= validation.DNS1123SubdomainMaxLength && secretKeyRegexp.MatchString(value)
}
// ValidateSecret tests if required fields in the Secret are set.
func ValidateSecret(secret *api.Secret) field.ErrorList {
allErrs := ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName, field.NewPath("metadata"))
@ -2627,8 +2639,8 @@ func ValidateSecret(secret *api.Secret) field.ErrorList {
dataPath := field.NewPath("data")
totalSize := 0
for key, value := range secret.Data {
if !IsSecretKey(key) {
allErrs = append(allErrs, field.Invalid(dataPath.Key(key), key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt)))
for _, msg := range validation.IsConfigMapKey(key) {
allErrs = append(allErrs, field.Invalid(dataPath.Key(key), key, msg))
}
totalSize += len(value)
}
@ -2725,8 +2737,8 @@ func ValidateConfigMap(cfg *api.ConfigMap) field.ErrorList {
totalSize := 0
for key, value := range cfg.Data {
if !IsSecretKey(key) {
allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt)))
for _, msg := range validation.IsConfigMapKey(key) {
allErrs = append(allErrs, field.Invalid(field.NewPath("data").Key(key), key, msg))
}
totalSize += len(value)
}
@ -2788,24 +2800,24 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat
}
// validateResourceQuotaScopes ensures that each enumerated hard resource constraint is valid for set of scopes
func validateResourceQuotaScopes(resourceQuota *api.ResourceQuota) field.ErrorList {
func validateResourceQuotaScopes(resourceQuotaSpec *api.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(resourceQuota.Spec.Scopes) == 0 {
if len(resourceQuotaSpec.Scopes) == 0 {
return allErrs
}
hardLimits := sets.NewString()
for k := range resourceQuota.Spec.Hard {
for k := range resourceQuotaSpec.Hard {
hardLimits.Insert(string(k))
}
fldPath := field.NewPath("spec", "scopes")
fldPath := fld.Child("scopes")
scopeSet := sets.NewString()
for _, scope := range resourceQuota.Spec.Scopes {
for _, scope := range resourceQuotaSpec.Scopes {
if !api.IsStandardResourceQuotaScope(string(scope)) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuota.Spec.Scopes, "unsupported scope"))
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope"))
}
for _, k := range hardLimits.List() {
if api.IsStandardQuotaResourceName(k) && !api.IsResourceQuotaScopeValidForResource(scope, k) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuota.Spec.Scopes, "unsupported scope applied to resource"))
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "unsupported scope applied to resource"))
}
}
scopeSet.Insert(string(scope))
@ -2816,7 +2828,7 @@ func validateResourceQuotaScopes(resourceQuota *api.ResourceQuota) field.ErrorLi
}
for _, invalidScopePair := range invalidScopePairs {
if scopeSet.HasAll(invalidScopePair.List()...) {
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuota.Spec.Scopes, "conflicting scopes"))
allErrs = append(allErrs, field.Invalid(fldPath, resourceQuotaSpec.Scopes, "conflicting scopes"))
}
}
return allErrs
@ -2826,32 +2838,47 @@ func validateResourceQuotaScopes(resourceQuota *api.ResourceQuota) field.ErrorLi
func ValidateResourceQuota(resourceQuota *api.ResourceQuota) field.ErrorList {
allErrs := ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName, field.NewPath("metadata"))
fldPath := field.NewPath("spec", "hard")
for k, v := range resourceQuota.Spec.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuota)...)
allErrs = append(allErrs, ValidateResourceQuotaSpec(&resourceQuota.Spec, field.NewPath("spec"))...)
allErrs = append(allErrs, ValidateResourceQuotaStatus(&resourceQuota.Status, field.NewPath("status"))...)
fldPath = field.NewPath("status", "hard")
for k, v := range resourceQuota.Status.Hard {
return allErrs
}
func ValidateResourceQuotaStatus(status *api.ResourceQuotaStatus, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
fldPath := fld.Child("hard")
for k, v := range status.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
}
fldPath = field.NewPath("status", "used")
for k, v := range resourceQuota.Status.Used {
fldPath = fld.Child("used")
for k, v := range status.Used {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
}
return allErrs
}
// validateResourceQuantityValue enforces that specified quantity is valid for specified resource
func validateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList {
func ValidateResourceQuotaSpec(resourceQuotaSpec *api.ResourceQuotaSpec, fld *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
fldPath := fld.Child("hard")
for k, v := range resourceQuotaSpec.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
}
allErrs = append(allErrs, validateResourceQuotaScopes(resourceQuotaSpec, fld)...)
return allErrs
}
// ValidateResourceQuantityValue enforces that specified quantity is valid for specified resource
func ValidateResourceQuantityValue(resource string, value resource.Quantity, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateNonnegativeQuantity(value, fldPath)...)
if api.IsIntegerResourceName(resource) {
@ -2866,15 +2893,10 @@ func validateResourceQuantityValue(resource string, value resource.Quantity, fld
// newResourceQuota is updated with fields that cannot be changed.
func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) field.ErrorList {
allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
fldPath := field.NewPath("spec", "hard")
for k, v := range newResourceQuota.Spec.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
}
allErrs = append(allErrs, ValidateResourceQuotaSpec(&newResourceQuota.Spec, field.NewPath("spec"))...)
// ensure scopes cannot change, and that resources are still valid for scope
fldPath = field.NewPath("spec", "scopes")
fldPath := field.NewPath("spec", "scopes")
oldScopes := sets.NewString()
newScopes := sets.NewString()
for _, scope := range newResourceQuota.Spec.Scopes {
@ -2886,7 +2908,6 @@ func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.Resourc
if !oldScopes.Equal(newScopes) {
allErrs = append(allErrs, field.Invalid(fldPath, newResourceQuota.Spec.Scopes, "field is immutable"))
}
allErrs = append(allErrs, validateResourceQuotaScopes(newResourceQuota)...)
newResourceQuota.Status = oldResourceQuota.Status
return allErrs
@ -2902,14 +2923,14 @@ func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *api.R
fldPath := field.NewPath("status", "hard")
for k, v := range newResourceQuota.Status.Hard {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
}
fldPath = field.NewPath("status", "used")
for k, v := range newResourceQuota.Status.Used {
resPath := fldPath.Key(string(k))
allErrs = append(allErrs, validateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, validateResourceQuantityValue(string(k), v, resPath)...)
allErrs = append(allErrs, ValidateResourceQuotaResourceName(string(k), resPath)...)
allErrs = append(allErrs, ValidateResourceQuantityValue(string(k), v, resPath)...)
}
newResourceQuota.Spec = oldResourceQuota.Spec
return allErrs
@ -3021,29 +3042,33 @@ func validateEndpointSubsets(subsets []api.EndpointSubset, fldPath *field.Path)
func validateEndpointAddress(address *api.EndpointAddress, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if !validation.IsValidIP(address.IP) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, "must be a valid IP address"))
for _, msg := range validation.IsValidIP(address.IP) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("ip"), address.IP, msg))
}
if len(address.Hostname) > 0 {
for _, msg := range validation.IsDNS1123Label(address.Hostname) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("hostname"), address.Hostname, msg))
}
allErrs = append(allErrs, ValidateDNS1123Label(address.Hostname, fldPath.Child("hostname"))...)
}
if len(allErrs) > 0 {
return allErrs
}
return validateIpIsNotLinkLocalOrLoopback(address.IP, fldPath.Child("ip"))
allErrs = append(allErrs, validateNonSpecialIP(address.IP, fldPath.Child("ip"))...)
return allErrs
}
func validateIpIsNotLinkLocalOrLoopback(ipAddress string, fldPath *field.Path) field.ErrorList {
// We disallow some IPs as endpoints or external-ips. Specifically, loopback addresses are
// nonsensical and link-local addresses tend to be used for node-centric purposes (e.g. metadata service).
func validateNonSpecialIP(ipAddress string, fldPath *field.Path) field.ErrorList {
// We disallow some IPs as endpoints or external-ips. Specifically,
// unspecified and loopback addresses are nonsensical and link-local
// addresses tend to be used for node-centric purposes (e.g. metadata
// service).
allErrs := field.ErrorList{}
ip := net.ParseIP(ipAddress)
if ip == nil {
allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "must be a valid IP address"))
return allErrs
}
if ip.IsUnspecified() {
allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be unspecified (0.0.0.0)"))
}
if ip.IsLoopback() {
allErrs = append(allErrs, field.Invalid(fldPath, ipAddress, "may not be in the loopback range (127.0.0.0/8)"))
}
@ -3061,12 +3086,10 @@ func validateEndpointPort(port *api.EndpointPort, requireName bool, fldPath *fie
if requireName && len(port.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
} else if len(port.Name) != 0 {
for _, msg := range validation.IsDNS1123Label(port.Name) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), port.Name, msg))
}
allErrs = append(allErrs, ValidateDNS1123Label(port.Name, fldPath.Child("name"))...)
}
if !validation.IsValidPortNum(int(port.Port)) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, PortRangeErrorMsg))
for _, msg := range validation.IsValidPortNum(int(port.Port)) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("port"), port.Port, msg))
}
if len(port.Protocol) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("protocol"), ""))
@ -3147,6 +3170,7 @@ func ValidateLoadBalancerStatus(status *api.LoadBalancerStatus, fldPath *field.P
return allErrs
}
// TODO: remove this after we EOL the annotation that carries it.
func isValidHostnamesMap(serializedPodHostNames string) bool {
if len(serializedPodHostNames) == 0 {
return false