github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/api/validation/validation.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package validation
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"net"
    23  	"os"
    24  	"path"
    25  	"reflect"
    26  	"regexp"
    27  	"strings"
    28  
    29  	"k8s.io/kubernetes/pkg/api"
    30  	"k8s.io/kubernetes/pkg/api/resource"
    31  	"k8s.io/kubernetes/pkg/capabilities"
    32  	"k8s.io/kubernetes/pkg/labels"
    33  	"k8s.io/kubernetes/pkg/util/intstr"
    34  	"k8s.io/kubernetes/pkg/util/sets"
    35  	"k8s.io/kubernetes/pkg/util/validation"
    36  
    37  	"github.com/golang/glog"
    38  )
    39  
    40  // TODO: delete this global variable when we enable the validation of common
    41  // fields by default.
    42  var RepairMalformedUpdates bool = true
    43  
    44  const isNegativeErrorMsg string = `must be non-negative`
    45  const fieldImmutableErrorMsg string = `field is immutable`
    46  const cIdentifierErrorMsg string = `must be a C identifier (matching regex ` + validation.CIdentifierFmt + `): e.g. "my_name" or "MyName"`
    47  const isNotIntegerErrorMsg string = `must be an integer`
    48  
    49  func IntervalErrorMsg(lo, hi int) string {
    50  	return fmt.Sprintf(`must be greater than %d and less than %d`, lo, hi)
    51  }
    52  
    53  var labelValueErrorMsg string = fmt.Sprintf(`must have at most %d characters, matching regex %s: e.g. "MyValue" or ""`, validation.LabelValueMaxLength, validation.LabelValueFmt)
    54  var qualifiedNameErrorMsg string = fmt.Sprintf(`must be a qualified name (at most %d characters, matching regex %s), with an optional DNS subdomain prefix (at most %d characters, matching regex %s) and slash (/): e.g. "MyName" or "example.com/MyName"`, validation.QualifiedNameMaxLength, validation.QualifiedNameFmt, validation.DNS1123SubdomainMaxLength, validation.DNS1123SubdomainFmt)
    55  var DNSSubdomainErrorMsg string = fmt.Sprintf(`must be a DNS subdomain (at most %d characters, matching regex %s): e.g. "example.com"`, validation.DNS1123SubdomainMaxLength, validation.DNS1123SubdomainFmt)
    56  var DNS1123LabelErrorMsg string = fmt.Sprintf(`must be a DNS label (at most %d characters, matching regex %s): e.g. "my-name"`, validation.DNS1123LabelMaxLength, validation.DNS1123LabelFmt)
    57  var DNS952LabelErrorMsg string = fmt.Sprintf(`must be a DNS 952 label (at most %d characters, matching regex %s): e.g. "my-name"`, validation.DNS952LabelMaxLength, validation.DNS952LabelFmt)
    58  var pdPartitionErrorMsg string = IntervalErrorMsg(0, 255)
    59  var PortRangeErrorMsg string = IntervalErrorMsg(0, 65536)
    60  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)
    61  
    62  const totalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
    63  
    64  func ValidateLabelName(labelName, fieldName string) validation.ErrorList {
    65  	allErrs := validation.ErrorList{}
    66  	if !validation.IsQualifiedName(labelName) {
    67  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, labelName, qualifiedNameErrorMsg))
    68  	}
    69  	return allErrs
    70  }
    71  
    72  // ValidateLabels validates that a set of labels are correctly defined.
    73  func ValidateLabels(labels map[string]string, field string) validation.ErrorList {
    74  	allErrs := validation.ErrorList{}
    75  	for k, v := range labels {
    76  		allErrs = append(allErrs, ValidateLabelName(k, field)...)
    77  		if !validation.IsValidLabelValue(v) {
    78  			allErrs = append(allErrs, validation.NewInvalidError(field, v, labelValueErrorMsg))
    79  		}
    80  	}
    81  	return allErrs
    82  }
    83  
    84  // ValidateAnnotations validates that a set of annotations are correctly defined.
    85  func ValidateAnnotations(annotations map[string]string, field string) validation.ErrorList {
    86  	allErrs := validation.ErrorList{}
    87  	var totalSize int64
    88  	for k, v := range annotations {
    89  		if !validation.IsQualifiedName(strings.ToLower(k)) {
    90  			allErrs = append(allErrs, validation.NewInvalidError(field, k, qualifiedNameErrorMsg))
    91  		}
    92  		totalSize += (int64)(len(k)) + (int64)(len(v))
    93  	}
    94  	if totalSize > (int64)(totalAnnotationSizeLimitB) {
    95  		allErrs = append(allErrs, validation.NewTooLongError(field, "", totalAnnotationSizeLimitB))
    96  	}
    97  	return allErrs
    98  }
    99  
   100  // ValidateNameFunc validates that the provided name is valid for a given resource type.
   101  // Not all resources have the same validation rules for names. Prefix is true if the
   102  // name will have a value appended to it.
   103  type ValidateNameFunc func(name string, prefix bool) (bool, string)
   104  
   105  // maskTrailingDash replaces the final character of a string with a subdomain safe
   106  // value if is a dash.
   107  func maskTrailingDash(name string) string {
   108  	if strings.HasSuffix(name, "-") {
   109  		return name[:len(name)-2] + "a"
   110  	}
   111  	return name
   112  }
   113  
   114  // ValidatePodName can be used to check whether the given pod name is valid.
   115  // Prefix indicates this name will be used as part of generation, in which case
   116  // trailing dashes are allowed.
   117  func ValidatePodName(name string, prefix bool) (bool, string) {
   118  	return NameIsDNSSubdomain(name, prefix)
   119  }
   120  
   121  // ValidateReplicationControllerName can be used to check whether the given replication
   122  // controller name is valid.
   123  // Prefix indicates this name will be used as part of generation, in which case
   124  // trailing dashes are allowed.
   125  func ValidateReplicationControllerName(name string, prefix bool) (bool, string) {
   126  	return NameIsDNSSubdomain(name, prefix)
   127  }
   128  
   129  // ValidateServiceName can be used to check whether the given service name is valid.
   130  // Prefix indicates this name will be used as part of generation, in which case
   131  // trailing dashes are allowed.
   132  func ValidateServiceName(name string, prefix bool) (bool, string) {
   133  	return NameIsDNS952Label(name, prefix)
   134  }
   135  
   136  // ValidateNodeName can be used to check whether the given node name is valid.
   137  // Prefix indicates this name will be used as part of generation, in which case
   138  // trailing dashes are allowed.
   139  func ValidateNodeName(name string, prefix bool) (bool, string) {
   140  	return NameIsDNSSubdomain(name, prefix)
   141  }
   142  
   143  // ValidateNamespaceName can be used to check whether the given namespace name is valid.
   144  // Prefix indicates this name will be used as part of generation, in which case
   145  // trailing dashes are allowed.
   146  func ValidateNamespaceName(name string, prefix bool) (bool, string) {
   147  	return NameIsDNSLabel(name, prefix)
   148  }
   149  
   150  // ValidateLimitRangeName can be used to check whether the given limit range name is valid.
   151  // Prefix indicates this name will be used as part of generation, in which case
   152  // trailing dashes are allowed.
   153  func ValidateLimitRangeName(name string, prefix bool) (bool, string) {
   154  	return NameIsDNSSubdomain(name, prefix)
   155  }
   156  
   157  // ValidateResourceQuotaName can be used to check whether the given
   158  // resource quota name is valid.
   159  // Prefix indicates this name will be used as part of generation, in which case
   160  // trailing dashes are allowed.
   161  func ValidateResourceQuotaName(name string, prefix bool) (bool, string) {
   162  	return NameIsDNSSubdomain(name, prefix)
   163  }
   164  
   165  // ValidateSecretName can be used to check whether the given secret name is valid.
   166  // Prefix indicates this name will be used as part of generation, in which case
   167  // trailing dashes are allowed.
   168  func ValidateSecretName(name string, prefix bool) (bool, string) {
   169  	return NameIsDNSSubdomain(name, prefix)
   170  }
   171  
   172  // ValidateServiceAccountName can be used to check whether the given service account name is valid.
   173  // Prefix indicates this name will be used as part of generation, in which case
   174  // trailing dashes are allowed.
   175  func ValidateServiceAccountName(name string, prefix bool) (bool, string) {
   176  	return NameIsDNSSubdomain(name, prefix)
   177  }
   178  
   179  // ValidateEndpointsName can be used to check whether the given endpoints name is valid.
   180  // Prefix indicates this name will be used as part of generation, in which case
   181  // trailing dashes are allowed.
   182  func ValidateEndpointsName(name string, prefix bool) (bool, string) {
   183  	return NameIsDNSSubdomain(name, prefix)
   184  }
   185  
   186  // NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain.
   187  func NameIsDNSSubdomain(name string, prefix bool) (bool, string) {
   188  	if prefix {
   189  		name = maskTrailingDash(name)
   190  	}
   191  	if validation.IsDNS1123Subdomain(name) {
   192  		return true, ""
   193  	}
   194  	return false, DNSSubdomainErrorMsg
   195  }
   196  
   197  // NameIsDNSLabel is a ValidateNameFunc for names that must be a DNS 1123 label.
   198  func NameIsDNSLabel(name string, prefix bool) (bool, string) {
   199  	if prefix {
   200  		name = maskTrailingDash(name)
   201  	}
   202  	if validation.IsDNS1123Label(name) {
   203  		return true, ""
   204  	}
   205  	return false, DNS1123LabelErrorMsg
   206  }
   207  
   208  // NameIsDNS952Label is a ValidateNameFunc for names that must be a DNS 952 label.
   209  func NameIsDNS952Label(name string, prefix bool) (bool, string) {
   210  	if prefix {
   211  		name = maskTrailingDash(name)
   212  	}
   213  	if validation.IsDNS952Label(name) {
   214  		return true, ""
   215  	}
   216  	return false, DNS952LabelErrorMsg
   217  }
   218  
   219  // Validates that given value is not negative.
   220  func ValidatePositiveField(value int64, fieldName string) validation.ErrorList {
   221  	allErrs := validation.ErrorList{}
   222  	if value < 0 {
   223  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, value, isNegativeErrorMsg))
   224  	}
   225  	return allErrs
   226  }
   227  
   228  // Validates that a Quantity is not negative
   229  func ValidatePositiveQuantity(value resource.Quantity, fieldName string) validation.ErrorList {
   230  	allErrs := validation.ErrorList{}
   231  	if value.Cmp(resource.Quantity{}) < 0 {
   232  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, value.String(), isNegativeErrorMsg))
   233  	}
   234  	return allErrs
   235  }
   236  
   237  func ValidateImmutableField(new, old interface{}, fieldName string) validation.ErrorList {
   238  	allErrs := validation.ErrorList{}
   239  	if !api.Semantic.DeepEqual(old, new) {
   240  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, new, fieldImmutableErrorMsg))
   241  	}
   242  	return allErrs
   243  }
   244  
   245  // ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
   246  // been performed.
   247  // It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
   248  // TODO: Remove calls to this method scattered in validations of specific resources, e.g., ValidatePodUpdate.
   249  func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn ValidateNameFunc) validation.ErrorList {
   250  	allErrs := validation.ErrorList{}
   251  
   252  	if len(meta.GenerateName) != 0 {
   253  		if ok, qualifier := nameFn(meta.GenerateName, true); !ok {
   254  			allErrs = append(allErrs, validation.NewInvalidError("generateName", meta.GenerateName, qualifier))
   255  		}
   256  	}
   257  	// If the generated name validates, but the calculated value does not, it's a problem with generation, and we
   258  	// report it here. This may confuse users, but indicates a programming bug and still must be validated.
   259  	// If there are multiple fields out of which one is required then add a or as a separator
   260  	if len(meta.Name) == 0 {
   261  		requiredErr := validation.NewRequiredError("name")
   262  		requiredErr.Detail = "name or generateName is required"
   263  		allErrs = append(allErrs, requiredErr)
   264  	} else {
   265  		if ok, qualifier := nameFn(meta.Name, false); !ok {
   266  			allErrs = append(allErrs, validation.NewInvalidError("name", meta.Name, qualifier))
   267  		}
   268  	}
   269  	allErrs = append(allErrs, ValidatePositiveField(meta.Generation, "generation")...)
   270  	if requiresNamespace {
   271  		if len(meta.Namespace) == 0 {
   272  			allErrs = append(allErrs, validation.NewRequiredError("namespace"))
   273  		} else if ok, _ := ValidateNamespaceName(meta.Namespace, false); !ok {
   274  			allErrs = append(allErrs, validation.NewInvalidError("namespace", meta.Namespace, DNS1123LabelErrorMsg))
   275  		}
   276  	} else {
   277  		if len(meta.Namespace) != 0 {
   278  			allErrs = append(allErrs, validation.NewInvalidError("namespace", meta.Namespace, "namespace is not allowed on this type"))
   279  		}
   280  	}
   281  	allErrs = append(allErrs, ValidateLabels(meta.Labels, "labels")...)
   282  	allErrs = append(allErrs, ValidateAnnotations(meta.Annotations, "annotations")...)
   283  
   284  	return allErrs
   285  }
   286  
   287  // ValidateObjectMetaUpdate validates an object's metadata when updated
   288  func ValidateObjectMetaUpdate(new, old *api.ObjectMeta) validation.ErrorList {
   289  	allErrs := validation.ErrorList{}
   290  
   291  	if !RepairMalformedUpdates && new.UID != old.UID {
   292  		allErrs = append(allErrs, validation.NewInvalidError("uid", new.UID, "field is immutable"))
   293  	}
   294  	// in the event it is left empty, set it, to allow clients more flexibility
   295  	// TODO: remove the following code that repairs the update request when we retire the clients that modify the immutable fields.
   296  	// Please do not copy this pattern elsewhere; validation functions should not be modifying the objects they are passed!
   297  	if RepairMalformedUpdates {
   298  		if len(new.UID) == 0 {
   299  			new.UID = old.UID
   300  		}
   301  		// ignore changes to timestamp
   302  		if old.CreationTimestamp.IsZero() {
   303  			old.CreationTimestamp = new.CreationTimestamp
   304  		} else {
   305  			new.CreationTimestamp = old.CreationTimestamp
   306  		}
   307  		// an object can never remove a deletion timestamp or clear/change grace period seconds
   308  		if !old.DeletionTimestamp.IsZero() {
   309  			new.DeletionTimestamp = old.DeletionTimestamp
   310  		}
   311  		if old.DeletionGracePeriodSeconds != nil && new.DeletionGracePeriodSeconds == nil {
   312  			new.DeletionGracePeriodSeconds = old.DeletionGracePeriodSeconds
   313  		}
   314  	}
   315  
   316  	// TODO: needs to check if new==nil && old !=nil after the repair logic is removed.
   317  	if new.DeletionGracePeriodSeconds != nil && old.DeletionGracePeriodSeconds != nil && *new.DeletionGracePeriodSeconds != *old.DeletionGracePeriodSeconds {
   318  		allErrs = append(allErrs, validation.NewInvalidError("deletionGracePeriodSeconds", new.DeletionGracePeriodSeconds, "field is immutable; may only be changed via deletion"))
   319  	}
   320  
   321  	// Reject updates that don't specify a resource version
   322  	if new.ResourceVersion == "" {
   323  		allErrs = append(allErrs, validation.NewInvalidError("resourceVersion", new.ResourceVersion, "resourceVersion must be specified for an update"))
   324  	}
   325  
   326  	allErrs = append(allErrs, ValidateImmutableField(new.Name, old.Name, "name")...)
   327  	allErrs = append(allErrs, ValidateImmutableField(new.Namespace, old.Namespace, "namespace")...)
   328  	allErrs = append(allErrs, ValidateImmutableField(new.UID, old.UID, "uid")...)
   329  	allErrs = append(allErrs, ValidateImmutableField(new.CreationTimestamp, old.CreationTimestamp, "creationTimestamp")...)
   330  
   331  	allErrs = append(allErrs, ValidateLabels(new.Labels, "labels")...)
   332  	allErrs = append(allErrs, ValidateAnnotations(new.Annotations, "annotations")...)
   333  
   334  	return allErrs
   335  }
   336  
   337  func validateVolumes(volumes []api.Volume) (sets.String, validation.ErrorList) {
   338  	allErrs := validation.ErrorList{}
   339  
   340  	allNames := sets.String{}
   341  	for i, vol := range volumes {
   342  		el := validateSource(&vol.VolumeSource).Prefix("source")
   343  		if len(vol.Name) == 0 {
   344  			el = append(el, validation.NewRequiredError("name"))
   345  		} else if !validation.IsDNS1123Label(vol.Name) {
   346  			el = append(el, validation.NewInvalidError("name", vol.Name, DNS1123LabelErrorMsg))
   347  		} else if allNames.Has(vol.Name) {
   348  			el = append(el, validation.NewDuplicateError("name", vol.Name))
   349  		}
   350  		if len(el) == 0 {
   351  			allNames.Insert(vol.Name)
   352  		} else {
   353  			allErrs = append(allErrs, el.PrefixIndex(i)...)
   354  		}
   355  	}
   356  	return allNames, allErrs
   357  }
   358  
   359  func validateSource(source *api.VolumeSource) validation.ErrorList {
   360  	numVolumes := 0
   361  	allErrs := validation.ErrorList{}
   362  	if source.HostPath != nil {
   363  		numVolumes++
   364  		allErrs = append(allErrs, validateHostPathVolumeSource(source.HostPath).Prefix("hostPath")...)
   365  	}
   366  	if source.EmptyDir != nil {
   367  		numVolumes++
   368  		// EmptyDirs have nothing to validate
   369  	}
   370  	if source.GitRepo != nil {
   371  		numVolumes++
   372  		allErrs = append(allErrs, validateGitRepoVolumeSource(source.GitRepo).Prefix("gitRepo")...)
   373  	}
   374  	if source.GCEPersistentDisk != nil {
   375  		numVolumes++
   376  		allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(source.GCEPersistentDisk).Prefix("persistentDisk")...)
   377  	}
   378  	if source.AWSElasticBlockStore != nil {
   379  		numVolumes++
   380  		allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(source.AWSElasticBlockStore).Prefix("awsElasticBlockStore")...)
   381  	}
   382  	if source.Secret != nil {
   383  		numVolumes++
   384  		allErrs = append(allErrs, validateSecretVolumeSource(source.Secret).Prefix("secret")...)
   385  	}
   386  	if source.NFS != nil {
   387  		numVolumes++
   388  		allErrs = append(allErrs, validateNFS(source.NFS).Prefix("nfs")...)
   389  	}
   390  	if source.ISCSI != nil {
   391  		numVolumes++
   392  		allErrs = append(allErrs, validateISCSIVolumeSource(source.ISCSI).Prefix("iscsi")...)
   393  	}
   394  	if source.Glusterfs != nil {
   395  		numVolumes++
   396  		allErrs = append(allErrs, validateGlusterfs(source.Glusterfs).Prefix("glusterfs")...)
   397  	}
   398  	if source.Flocker != nil {
   399  		numVolumes++
   400  		allErrs = append(allErrs, validateFlocker(source.Flocker).Prefix("flocker")...)
   401  	}
   402  	if source.PersistentVolumeClaim != nil {
   403  		numVolumes++
   404  		allErrs = append(allErrs, validatePersistentClaimVolumeSource(source.PersistentVolumeClaim).Prefix("persistentVolumeClaim")...)
   405  	}
   406  	if source.RBD != nil {
   407  		numVolumes++
   408  		allErrs = append(allErrs, validateRBD(source.RBD).Prefix("rbd")...)
   409  	}
   410  	if source.Cinder != nil {
   411  		numVolumes++
   412  		allErrs = append(allErrs, validateCinderVolumeSource(source.Cinder).Prefix("cinder")...)
   413  	}
   414  	if source.CephFS != nil {
   415  		numVolumes++
   416  		allErrs = append(allErrs, validateCephFS(source.CephFS).Prefix("cephfs")...)
   417  	}
   418  	if source.DownwardAPI != nil {
   419  		numVolumes++
   420  		allErrs = append(allErrs, validateDownwardAPIVolumeSource(source.DownwardAPI).Prefix("downwardApi")...)
   421  	}
   422  	if source.FC != nil {
   423  		numVolumes++
   424  		allErrs = append(allErrs, validateFCVolumeSource(source.FC).Prefix("fc")...)
   425  	}
   426  	if numVolumes != 1 {
   427  		allErrs = append(allErrs, validation.NewInvalidError("", source, "exactly 1 volume type is required"))
   428  	}
   429  
   430  	return allErrs
   431  }
   432  
   433  func validateHostPathVolumeSource(hostPath *api.HostPathVolumeSource) validation.ErrorList {
   434  	allErrs := validation.ErrorList{}
   435  	if hostPath.Path == "" {
   436  		allErrs = append(allErrs, validation.NewRequiredError("path"))
   437  	}
   438  	return allErrs
   439  }
   440  
   441  func validateGitRepoVolumeSource(gitRepo *api.GitRepoVolumeSource) validation.ErrorList {
   442  	allErrs := validation.ErrorList{}
   443  	if gitRepo.Repository == "" {
   444  		allErrs = append(allErrs, validation.NewRequiredError("repository"))
   445  	}
   446  	return allErrs
   447  }
   448  
   449  func validateISCSIVolumeSource(iscsi *api.ISCSIVolumeSource) validation.ErrorList {
   450  	allErrs := validation.ErrorList{}
   451  	if iscsi.TargetPortal == "" {
   452  		allErrs = append(allErrs, validation.NewRequiredError("targetPortal"))
   453  	}
   454  	if iscsi.IQN == "" {
   455  		allErrs = append(allErrs, validation.NewRequiredError("iqn"))
   456  	}
   457  	if iscsi.FSType == "" {
   458  		allErrs = append(allErrs, validation.NewRequiredError("fsType"))
   459  	}
   460  	if iscsi.Lun < 0 || iscsi.Lun > 255 {
   461  		allErrs = append(allErrs, validation.NewInvalidError("lun", iscsi.Lun, ""))
   462  	}
   463  	return allErrs
   464  }
   465  
   466  func validateFCVolumeSource(fc *api.FCVolumeSource) validation.ErrorList {
   467  	allErrs := validation.ErrorList{}
   468  	if len(fc.TargetWWNs) < 1 {
   469  		allErrs = append(allErrs, validation.NewRequiredError("targetWWNs"))
   470  	}
   471  	if fc.FSType == "" {
   472  		allErrs = append(allErrs, validation.NewRequiredError("fsType"))
   473  	}
   474  
   475  	if fc.Lun == nil {
   476  		allErrs = append(allErrs, validation.NewRequiredError("lun"))
   477  	} else {
   478  		if *fc.Lun < 0 || *fc.Lun > 255 {
   479  			allErrs = append(allErrs, validation.NewInvalidError("lun", fc.Lun, ""))
   480  		}
   481  	}
   482  	return allErrs
   483  }
   484  
   485  func validateGCEPersistentDiskVolumeSource(PD *api.GCEPersistentDiskVolumeSource) validation.ErrorList {
   486  	allErrs := validation.ErrorList{}
   487  	if PD.PDName == "" {
   488  		allErrs = append(allErrs, validation.NewRequiredError("pdName"))
   489  	}
   490  	if PD.FSType == "" {
   491  		allErrs = append(allErrs, validation.NewRequiredError("fsType"))
   492  	}
   493  	if PD.Partition < 0 || PD.Partition > 255 {
   494  		allErrs = append(allErrs, validation.NewInvalidError("partition", PD.Partition, pdPartitionErrorMsg))
   495  	}
   496  	return allErrs
   497  }
   498  
   499  func validateAWSElasticBlockStoreVolumeSource(PD *api.AWSElasticBlockStoreVolumeSource) validation.ErrorList {
   500  	allErrs := validation.ErrorList{}
   501  	if PD.VolumeID == "" {
   502  		allErrs = append(allErrs, validation.NewRequiredError("volumeID"))
   503  	}
   504  	if PD.FSType == "" {
   505  		allErrs = append(allErrs, validation.NewRequiredError("fsType"))
   506  	}
   507  	if PD.Partition < 0 || PD.Partition > 255 {
   508  		allErrs = append(allErrs, validation.NewInvalidError("partition", PD.Partition, pdPartitionErrorMsg))
   509  	}
   510  	return allErrs
   511  }
   512  
   513  func validateSecretVolumeSource(secretSource *api.SecretVolumeSource) validation.ErrorList {
   514  	allErrs := validation.ErrorList{}
   515  	if secretSource.SecretName == "" {
   516  		allErrs = append(allErrs, validation.NewRequiredError("secretName"))
   517  	}
   518  	return allErrs
   519  }
   520  
   521  func validatePersistentClaimVolumeSource(claim *api.PersistentVolumeClaimVolumeSource) validation.ErrorList {
   522  	allErrs := validation.ErrorList{}
   523  	if claim.ClaimName == "" {
   524  		allErrs = append(allErrs, validation.NewRequiredError("claimName"))
   525  	}
   526  	return allErrs
   527  }
   528  
   529  func validateNFS(nfs *api.NFSVolumeSource) validation.ErrorList {
   530  	allErrs := validation.ErrorList{}
   531  	if nfs.Server == "" {
   532  		allErrs = append(allErrs, validation.NewRequiredError("server"))
   533  	}
   534  	if nfs.Path == "" {
   535  		allErrs = append(allErrs, validation.NewRequiredError("path"))
   536  	}
   537  	if !path.IsAbs(nfs.Path) {
   538  		allErrs = append(allErrs, validation.NewInvalidError("path", nfs.Path, "must be an absolute path"))
   539  	}
   540  	return allErrs
   541  }
   542  
   543  func validateGlusterfs(glusterfs *api.GlusterfsVolumeSource) validation.ErrorList {
   544  	allErrs := validation.ErrorList{}
   545  	if glusterfs.EndpointsName == "" {
   546  		allErrs = append(allErrs, validation.NewRequiredError("endpoints"))
   547  	}
   548  	if glusterfs.Path == "" {
   549  		allErrs = append(allErrs, validation.NewRequiredError("path"))
   550  	}
   551  	return allErrs
   552  }
   553  
   554  func validateFlocker(flocker *api.FlockerVolumeSource) validation.ErrorList {
   555  	allErrs := validation.ErrorList{}
   556  	if flocker.DatasetName == "" {
   557  		allErrs = append(allErrs, validation.NewRequiredError("datasetName"))
   558  	}
   559  	if strings.Contains(flocker.DatasetName, "/") {
   560  		allErrs = append(allErrs, validation.NewInvalidError("datasetName", flocker.DatasetName, "must not contain '/'"))
   561  	}
   562  	return allErrs
   563  }
   564  
   565  var validDownwardAPIFieldPathExpressions = sets.NewString("metadata.name", "metadata.namespace", "metadata.labels", "metadata.annotations")
   566  
   567  func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSource) validation.ErrorList {
   568  	allErrs := validation.ErrorList{}
   569  	for _, downwardAPIVolumeFile := range downwardAPIVolume.Items {
   570  		if len(downwardAPIVolumeFile.Path) == 0 {
   571  			allErrs = append(allErrs, validation.NewRequiredError("path"))
   572  		}
   573  		if path.IsAbs(downwardAPIVolumeFile.Path) {
   574  			allErrs = append(allErrs, validation.NewForbiddenError("path", "must not be an absolute path"))
   575  		}
   576  		items := strings.Split(downwardAPIVolumeFile.Path, string(os.PathSeparator))
   577  		for _, item := range items {
   578  			if item == ".." {
   579  				allErrs = append(allErrs, validation.NewInvalidError("path", downwardAPIVolumeFile.Path, "must not contain \"..\"."))
   580  			}
   581  		}
   582  		if strings.HasPrefix(items[0], "..") && len(items[0]) > 2 {
   583  			allErrs = append(allErrs, validation.NewInvalidError("path", downwardAPIVolumeFile.Path, "must not start with \"..\"."))
   584  		}
   585  		allErrs = append(allErrs, validateObjectFieldSelector(&downwardAPIVolumeFile.FieldRef, &validDownwardAPIFieldPathExpressions).Prefix("FieldRef")...)
   586  	}
   587  	return allErrs
   588  }
   589  
   590  func validateRBD(rbd *api.RBDVolumeSource) validation.ErrorList {
   591  	allErrs := validation.ErrorList{}
   592  	if len(rbd.CephMonitors) == 0 {
   593  		allErrs = append(allErrs, validation.NewRequiredError("monitors"))
   594  	}
   595  	if rbd.RBDImage == "" {
   596  		allErrs = append(allErrs, validation.NewRequiredError("image"))
   597  	}
   598  	if rbd.FSType == "" {
   599  		allErrs = append(allErrs, validation.NewRequiredError("fsType"))
   600  	}
   601  	return allErrs
   602  }
   603  
   604  func validateCinderVolumeSource(cd *api.CinderVolumeSource) validation.ErrorList {
   605  	allErrs := validation.ErrorList{}
   606  	if cd.VolumeID == "" {
   607  		allErrs = append(allErrs, validation.NewRequiredError("volumeID"))
   608  	}
   609  	if cd.FSType == "" || (cd.FSType != "ext3" && cd.FSType != "ext4") {
   610  		allErrs = append(allErrs, validation.NewRequiredError("fsType required and should be of type ext3 or ext4"))
   611  	}
   612  	return allErrs
   613  }
   614  
   615  func validateCephFS(cephfs *api.CephFSVolumeSource) validation.ErrorList {
   616  	allErrs := validation.ErrorList{}
   617  	if len(cephfs.Monitors) == 0 {
   618  		allErrs = append(allErrs, validation.NewRequiredError("monitors"))
   619  	}
   620  	return allErrs
   621  }
   622  
   623  func ValidatePersistentVolumeName(name string, prefix bool) (bool, string) {
   624  	return NameIsDNSSubdomain(name, prefix)
   625  }
   626  
   627  func ValidatePersistentVolume(pv *api.PersistentVolume) validation.ErrorList {
   628  	allErrs := validation.ErrorList{}
   629  	allErrs = append(allErrs, ValidateObjectMeta(&pv.ObjectMeta, false, ValidatePersistentVolumeName).Prefix("metadata")...)
   630  
   631  	if len(pv.Spec.AccessModes) == 0 {
   632  		allErrs = append(allErrs, validation.NewRequiredError("persistentVolume.AccessModes"))
   633  	}
   634  
   635  	for _, mode := range pv.Spec.AccessModes {
   636  		if mode != api.ReadWriteOnce && mode != api.ReadOnlyMany && mode != api.ReadWriteMany {
   637  			allErrs = append(allErrs, validation.NewInvalidError("persistentVolume.Spec.AccessModes", mode, fmt.Sprintf("only %s, %s, and %s are valid", api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany)))
   638  		}
   639  	}
   640  
   641  	if len(pv.Spec.Capacity) == 0 {
   642  		allErrs = append(allErrs, validation.NewRequiredError("persistentVolume.Capacity"))
   643  	}
   644  
   645  	if _, ok := pv.Spec.Capacity[api.ResourceStorage]; !ok || len(pv.Spec.Capacity) > 1 {
   646  		allErrs = append(allErrs, validation.NewInvalidError("", pv.Spec.Capacity, fmt.Sprintf("only %s is expected", api.ResourceStorage)))
   647  	}
   648  
   649  	for _, qty := range pv.Spec.Capacity {
   650  		allErrs = append(allErrs, validateBasicResource(qty)...)
   651  	}
   652  
   653  	numVolumes := 0
   654  	if pv.Spec.HostPath != nil {
   655  		numVolumes++
   656  		allErrs = append(allErrs, validateHostPathVolumeSource(pv.Spec.HostPath).Prefix("hostPath")...)
   657  	}
   658  	if pv.Spec.GCEPersistentDisk != nil {
   659  		numVolumes++
   660  		allErrs = append(allErrs, validateGCEPersistentDiskVolumeSource(pv.Spec.GCEPersistentDisk).Prefix("persistentDisk")...)
   661  	}
   662  	if pv.Spec.AWSElasticBlockStore != nil {
   663  		numVolumes++
   664  		allErrs = append(allErrs, validateAWSElasticBlockStoreVolumeSource(pv.Spec.AWSElasticBlockStore).Prefix("awsElasticBlockStore")...)
   665  	}
   666  	if pv.Spec.Glusterfs != nil {
   667  		numVolumes++
   668  		allErrs = append(allErrs, validateGlusterfs(pv.Spec.Glusterfs).Prefix("glusterfs")...)
   669  	}
   670  	if pv.Spec.Flocker != nil {
   671  		numVolumes++
   672  		allErrs = append(allErrs, validateFlocker(pv.Spec.Flocker).Prefix("flocker")...)
   673  	}
   674  	if pv.Spec.NFS != nil {
   675  		numVolumes++
   676  		allErrs = append(allErrs, validateNFS(pv.Spec.NFS).Prefix("nfs")...)
   677  	}
   678  	if pv.Spec.RBD != nil {
   679  		numVolumes++
   680  		allErrs = append(allErrs, validateRBD(pv.Spec.RBD).Prefix("rbd")...)
   681  	}
   682  	if pv.Spec.CephFS != nil {
   683  		numVolumes++
   684  		allErrs = append(allErrs, validateCephFS(pv.Spec.CephFS).Prefix("cephfs")...)
   685  	}
   686  	if pv.Spec.ISCSI != nil {
   687  		numVolumes++
   688  		allErrs = append(allErrs, validateISCSIVolumeSource(pv.Spec.ISCSI).Prefix("iscsi")...)
   689  	}
   690  	if pv.Spec.Cinder != nil {
   691  		numVolumes++
   692  		allErrs = append(allErrs, validateCinderVolumeSource(pv.Spec.Cinder).Prefix("cinder")...)
   693  	}
   694  	if pv.Spec.FC != nil {
   695  		numVolumes++
   696  		allErrs = append(allErrs, validateFCVolumeSource(pv.Spec.FC).Prefix("fc")...)
   697  	}
   698  	if numVolumes != 1 {
   699  		allErrs = append(allErrs, validation.NewInvalidError("", pv.Spec.PersistentVolumeSource, "exactly 1 volume type is required"))
   700  	}
   701  	return allErrs
   702  }
   703  
   704  // ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make.
   705  // newPv is updated with fields that cannot be changed.
   706  func ValidatePersistentVolumeUpdate(newPv, oldPv *api.PersistentVolume) validation.ErrorList {
   707  	allErrs := validation.ErrorList{}
   708  	allErrs = ValidatePersistentVolume(newPv)
   709  	newPv.Status = oldPv.Status
   710  	return allErrs
   711  }
   712  
   713  // ValidatePersistentVolumeStatusUpdate tests to see if the status update is legal for an end user to make.
   714  // newPv is updated with fields that cannot be changed.
   715  func ValidatePersistentVolumeStatusUpdate(newPv, oldPv *api.PersistentVolume) validation.ErrorList {
   716  	allErrs := validation.ErrorList{}
   717  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPv.ObjectMeta, &oldPv.ObjectMeta).Prefix("metadata")...)
   718  	if newPv.ResourceVersion == "" {
   719  		allErrs = append(allErrs, validation.NewRequiredError("resourceVersion"))
   720  	}
   721  	newPv.Spec = oldPv.Spec
   722  	return allErrs
   723  }
   724  
   725  func ValidatePersistentVolumeClaim(pvc *api.PersistentVolumeClaim) validation.ErrorList {
   726  	allErrs := ValidateObjectMeta(&pvc.ObjectMeta, true, ValidatePersistentVolumeName)
   727  	if len(pvc.Spec.AccessModes) == 0 {
   728  		allErrs = append(allErrs, validation.NewInvalidError("persistentVolumeClaim.Spec.AccessModes", pvc.Spec.AccessModes, "at least 1 PersistentVolumeAccessMode is required"))
   729  	}
   730  	for _, mode := range pvc.Spec.AccessModes {
   731  		if mode != api.ReadWriteOnce && mode != api.ReadOnlyMany && mode != api.ReadWriteMany {
   732  			allErrs = append(allErrs, validation.NewInvalidError("persistentVolumeClaim.Spec.AccessModes", mode, fmt.Sprintf("only %s, %s, and %s are valid", api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany)))
   733  		}
   734  	}
   735  	if _, ok := pvc.Spec.Resources.Requests[api.ResourceStorage]; !ok {
   736  		allErrs = append(allErrs, validation.NewInvalidError("persistentVolumeClaim.Spec.Resources.Requests", pvc.Spec.Resources.Requests, "No Storage size specified"))
   737  	}
   738  	return allErrs
   739  }
   740  
   741  func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) validation.ErrorList {
   742  	allErrs := validation.ErrorList{}
   743  	allErrs = ValidatePersistentVolumeClaim(newPvc)
   744  	newPvc.Status = oldPvc.Status
   745  	return allErrs
   746  }
   747  
   748  func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *api.PersistentVolumeClaim) validation.ErrorList {
   749  	allErrs := validation.ErrorList{}
   750  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPvc.ObjectMeta, &oldPvc.ObjectMeta).Prefix("metadata")...)
   751  	if newPvc.ResourceVersion == "" {
   752  		allErrs = append(allErrs, validation.NewRequiredError("resourceVersion"))
   753  	}
   754  	if len(newPvc.Spec.AccessModes) == 0 {
   755  		allErrs = append(allErrs, validation.NewRequiredError("persistentVolume.AccessModes"))
   756  	}
   757  	for _, qty := range newPvc.Status.Capacity {
   758  		allErrs = append(allErrs, validateBasicResource(qty)...)
   759  	}
   760  	newPvc.Spec = oldPvc.Spec
   761  	return allErrs
   762  }
   763  
   764  var supportedPortProtocols = sets.NewString(string(api.ProtocolTCP), string(api.ProtocolUDP))
   765  
   766  func validatePorts(ports []api.ContainerPort) validation.ErrorList {
   767  	allErrs := validation.ErrorList{}
   768  
   769  	allNames := sets.String{}
   770  	for i, port := range ports {
   771  		pErrs := validation.ErrorList{}
   772  		if len(port.Name) > 0 {
   773  			if !validation.IsValidPortName(port.Name) {
   774  				pErrs = append(pErrs, validation.NewInvalidError("name", port.Name, PortNameErrorMsg))
   775  			} else if allNames.Has(port.Name) {
   776  				pErrs = append(pErrs, validation.NewDuplicateError("name", port.Name))
   777  			} else {
   778  				allNames.Insert(port.Name)
   779  			}
   780  		}
   781  		if port.ContainerPort == 0 {
   782  			pErrs = append(pErrs, validation.NewInvalidError("containerPort", port.ContainerPort, PortRangeErrorMsg))
   783  		} else if !validation.IsValidPortNum(port.ContainerPort) {
   784  			pErrs = append(pErrs, validation.NewInvalidError("containerPort", port.ContainerPort, PortRangeErrorMsg))
   785  		}
   786  		if port.HostPort != 0 && !validation.IsValidPortNum(port.HostPort) {
   787  			pErrs = append(pErrs, validation.NewInvalidError("hostPort", port.HostPort, PortRangeErrorMsg))
   788  		}
   789  		if len(port.Protocol) == 0 {
   790  			pErrs = append(pErrs, validation.NewRequiredError("protocol"))
   791  		} else if !supportedPortProtocols.Has(string(port.Protocol)) {
   792  			pErrs = append(pErrs, validation.NewNotSupportedError("protocol", port.Protocol, supportedPortProtocols.List()))
   793  		}
   794  		allErrs = append(allErrs, pErrs.PrefixIndex(i)...)
   795  	}
   796  	return allErrs
   797  }
   798  
   799  func validateEnv(vars []api.EnvVar) validation.ErrorList {
   800  	allErrs := validation.ErrorList{}
   801  
   802  	for i, ev := range vars {
   803  		vErrs := validation.ErrorList{}
   804  		if len(ev.Name) == 0 {
   805  			vErrs = append(vErrs, validation.NewRequiredError("name"))
   806  		} else if !validation.IsCIdentifier(ev.Name) {
   807  			vErrs = append(vErrs, validation.NewInvalidError("name", ev.Name, cIdentifierErrorMsg))
   808  		}
   809  		vErrs = append(vErrs, validateEnvVarValueFrom(ev).Prefix("valueFrom")...)
   810  		allErrs = append(allErrs, vErrs.PrefixIndex(i)...)
   811  	}
   812  	return allErrs
   813  }
   814  
   815  var validFieldPathExpressionsEnv = sets.NewString("metadata.name", "metadata.namespace", "status.podIP")
   816  
   817  func validateEnvVarValueFrom(ev api.EnvVar) validation.ErrorList {
   818  	allErrs := validation.ErrorList{}
   819  
   820  	if ev.ValueFrom == nil {
   821  		return allErrs
   822  	}
   823  
   824  	numSources := 0
   825  
   826  	switch {
   827  	case ev.ValueFrom.FieldRef != nil:
   828  		numSources++
   829  		allErrs = append(allErrs, validateObjectFieldSelector(ev.ValueFrom.FieldRef, &validFieldPathExpressionsEnv).Prefix("fieldRef")...)
   830  	}
   831  
   832  	if ev.Value != "" && numSources != 0 {
   833  		allErrs = append(allErrs, validation.NewInvalidError("", "", "sources cannot be specified when value is not empty"))
   834  	}
   835  
   836  	return allErrs
   837  }
   838  
   839  func validateObjectFieldSelector(fs *api.ObjectFieldSelector, expressions *sets.String) validation.ErrorList {
   840  	allErrs := validation.ErrorList{}
   841  
   842  	if fs.APIVersion == "" {
   843  		allErrs = append(allErrs, validation.NewRequiredError("apiVersion"))
   844  	} else if fs.FieldPath == "" {
   845  		allErrs = append(allErrs, validation.NewRequiredError("fieldPath"))
   846  	} else {
   847  		internalFieldPath, _, err := api.Scheme.ConvertFieldLabel(fs.APIVersion, "Pod", fs.FieldPath, "")
   848  		if err != nil {
   849  			allErrs = append(allErrs, validation.NewInvalidError("fieldPath", fs.FieldPath, "error converting fieldPath"))
   850  		} else if !expressions.Has(internalFieldPath) {
   851  			allErrs = append(allErrs, validation.NewNotSupportedError("fieldPath", internalFieldPath, expressions.List()))
   852  		}
   853  	}
   854  
   855  	return allErrs
   856  }
   857  
   858  func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String) validation.ErrorList {
   859  	allErrs := validation.ErrorList{}
   860  
   861  	for i, mnt := range mounts {
   862  		mErrs := validation.ErrorList{}
   863  		if len(mnt.Name) == 0 {
   864  			mErrs = append(mErrs, validation.NewRequiredError("name"))
   865  		} else if !volumes.Has(mnt.Name) {
   866  			mErrs = append(mErrs, validation.NewNotFoundError("name", mnt.Name))
   867  		}
   868  		if len(mnt.MountPath) == 0 {
   869  			mErrs = append(mErrs, validation.NewRequiredError("mountPath"))
   870  		}
   871  		allErrs = append(allErrs, mErrs.PrefixIndex(i)...)
   872  	}
   873  	return allErrs
   874  }
   875  
   876  func validateProbe(probe *api.Probe) validation.ErrorList {
   877  	allErrs := validation.ErrorList{}
   878  
   879  	if probe == nil {
   880  		return allErrs
   881  	}
   882  	allErrs = append(allErrs, validateHandler(&probe.Handler)...)
   883  	allErrs = append(allErrs, ValidatePositiveField(probe.InitialDelaySeconds, "initialDelaySeconds")...)
   884  	allErrs = append(allErrs, ValidatePositiveField(probe.TimeoutSeconds, "timeoutSeconds")...)
   885  	allErrs = append(allErrs, ValidatePositiveField(int64(probe.PeriodSeconds), "periodSeconds")...)
   886  	allErrs = append(allErrs, ValidatePositiveField(int64(probe.SuccessThreshold), "successThreshold")...)
   887  	allErrs = append(allErrs, ValidatePositiveField(int64(probe.FailureThreshold), "failureThreshold")...)
   888  	return allErrs
   889  }
   890  
   891  // AccumulateUniqueHostPorts extracts each HostPort of each Container,
   892  // accumulating the results and returning an error if any ports conflict.
   893  func AccumulateUniqueHostPorts(containers []api.Container, accumulator *sets.String) validation.ErrorList {
   894  	allErrs := validation.ErrorList{}
   895  
   896  	for ci, ctr := range containers {
   897  		cErrs := validation.ErrorList{}
   898  		for pi := range ctr.Ports {
   899  			port := ctr.Ports[pi].HostPort
   900  			if port == 0 {
   901  				continue
   902  			}
   903  			str := fmt.Sprintf("%d/%s", port, ctr.Ports[pi].Protocol)
   904  			if accumulator.Has(str) {
   905  				cErrs = append(cErrs, validation.NewDuplicateError("port", str))
   906  			} else {
   907  				accumulator.Insert(str)
   908  			}
   909  		}
   910  		allErrs = append(allErrs, cErrs.PrefixIndex(ci)...)
   911  	}
   912  	return allErrs
   913  }
   914  
   915  // checkHostPortConflicts checks for colliding Port.HostPort values across
   916  // a slice of containers.
   917  func checkHostPortConflicts(containers []api.Container) validation.ErrorList {
   918  	allPorts := sets.String{}
   919  	return AccumulateUniqueHostPorts(containers, &allPorts)
   920  }
   921  
   922  func validateExecAction(exec *api.ExecAction) validation.ErrorList {
   923  	allErrors := validation.ErrorList{}
   924  	if len(exec.Command) == 0 {
   925  		allErrors = append(allErrors, validation.NewRequiredError("command"))
   926  	}
   927  	return allErrors
   928  }
   929  
   930  func validateHTTPGetAction(http *api.HTTPGetAction) validation.ErrorList {
   931  	allErrors := validation.ErrorList{}
   932  	if len(http.Path) == 0 {
   933  		allErrors = append(allErrors, validation.NewRequiredError("path"))
   934  	}
   935  	if http.Port.Type == intstr.Int && !validation.IsValidPortNum(http.Port.IntVal) {
   936  		allErrors = append(allErrors, validation.NewInvalidError("port", http.Port, PortRangeErrorMsg))
   937  	} else if http.Port.Type == intstr.String && !validation.IsValidPortName(http.Port.StrVal) {
   938  		allErrors = append(allErrors, validation.NewInvalidError("port", http.Port.StrVal, PortNameErrorMsg))
   939  	}
   940  	supportedSchemes := sets.NewString(string(api.URISchemeHTTP), string(api.URISchemeHTTPS))
   941  	if !supportedSchemes.Has(string(http.Scheme)) {
   942  		allErrors = append(allErrors, validation.NewInvalidError("scheme", http.Scheme, fmt.Sprintf("must be one of %v", supportedSchemes.List())))
   943  	}
   944  	return allErrors
   945  }
   946  
   947  func validateTCPSocketAction(tcp *api.TCPSocketAction) validation.ErrorList {
   948  	allErrors := validation.ErrorList{}
   949  	if tcp.Port.Type == intstr.Int && !validation.IsValidPortNum(tcp.Port.IntVal) {
   950  		allErrors = append(allErrors, validation.NewInvalidError("port", tcp.Port, PortRangeErrorMsg))
   951  	} else if tcp.Port.Type == intstr.String && !validation.IsValidPortName(tcp.Port.StrVal) {
   952  		allErrors = append(allErrors, validation.NewInvalidError("port", tcp.Port.StrVal, PortNameErrorMsg))
   953  	}
   954  	return allErrors
   955  }
   956  
   957  func validateHandler(handler *api.Handler) validation.ErrorList {
   958  	numHandlers := 0
   959  	allErrors := validation.ErrorList{}
   960  	if handler.Exec != nil {
   961  		numHandlers++
   962  		allErrors = append(allErrors, validateExecAction(handler.Exec).Prefix("exec")...)
   963  	}
   964  	if handler.HTTPGet != nil {
   965  		numHandlers++
   966  		allErrors = append(allErrors, validateHTTPGetAction(handler.HTTPGet).Prefix("httpGet")...)
   967  	}
   968  	if handler.TCPSocket != nil {
   969  		numHandlers++
   970  		allErrors = append(allErrors, validateTCPSocketAction(handler.TCPSocket).Prefix("tcpSocket")...)
   971  	}
   972  	if numHandlers != 1 {
   973  		allErrors = append(allErrors, validation.NewInvalidError("", handler, "exactly 1 handler type is required"))
   974  	}
   975  	return allErrors
   976  }
   977  
   978  func validateLifecycle(lifecycle *api.Lifecycle) validation.ErrorList {
   979  	allErrs := validation.ErrorList{}
   980  	if lifecycle.PostStart != nil {
   981  		allErrs = append(allErrs, validateHandler(lifecycle.PostStart).Prefix("postStart")...)
   982  	}
   983  	if lifecycle.PreStop != nil {
   984  		allErrs = append(allErrs, validateHandler(lifecycle.PreStop).Prefix("preStop")...)
   985  	}
   986  	return allErrs
   987  }
   988  
   989  func validatePullPolicy(ctr *api.Container) validation.ErrorList {
   990  	allErrors := validation.ErrorList{}
   991  
   992  	switch ctr.ImagePullPolicy {
   993  	case api.PullAlways, api.PullIfNotPresent, api.PullNever:
   994  		break
   995  	case "":
   996  		allErrors = append(allErrors, validation.NewRequiredError(""))
   997  	default:
   998  		validValues := []string{string(api.PullAlways), string(api.PullIfNotPresent), string(api.PullNever)}
   999  		allErrors = append(allErrors, validation.NewNotSupportedError("", ctr.ImagePullPolicy, validValues))
  1000  	}
  1001  
  1002  	return allErrors
  1003  }
  1004  
  1005  func validateContainers(containers []api.Container, volumes sets.String) validation.ErrorList {
  1006  	allErrs := validation.ErrorList{}
  1007  
  1008  	if len(containers) == 0 {
  1009  		return append(allErrs, validation.NewRequiredError(""))
  1010  	}
  1011  
  1012  	allNames := sets.String{}
  1013  	for i, ctr := range containers {
  1014  		cErrs := validation.ErrorList{}
  1015  		if len(ctr.Name) == 0 {
  1016  			cErrs = append(cErrs, validation.NewRequiredError("name"))
  1017  		} else if !validation.IsDNS1123Label(ctr.Name) {
  1018  			cErrs = append(cErrs, validation.NewInvalidError("name", ctr.Name, DNS1123LabelErrorMsg))
  1019  		} else if allNames.Has(ctr.Name) {
  1020  			cErrs = append(cErrs, validation.NewDuplicateError("name", ctr.Name))
  1021  		} else {
  1022  			allNames.Insert(ctr.Name)
  1023  		}
  1024  		if len(ctr.Image) == 0 {
  1025  			cErrs = append(cErrs, validation.NewRequiredError("image"))
  1026  		}
  1027  		if ctr.Lifecycle != nil {
  1028  			cErrs = append(cErrs, validateLifecycle(ctr.Lifecycle).Prefix("lifecycle")...)
  1029  		}
  1030  		cErrs = append(cErrs, validateProbe(ctr.LivenessProbe).Prefix("livenessProbe")...)
  1031  		// Liveness-specific validation
  1032  		if ctr.LivenessProbe != nil && ctr.LivenessProbe.SuccessThreshold != 1 {
  1033  			allErrs = append(allErrs, validation.NewForbiddenError("livenessProbe.successThreshold", "must be 1"))
  1034  		}
  1035  
  1036  		cErrs = append(cErrs, validateProbe(ctr.ReadinessProbe).Prefix("readinessProbe")...)
  1037  		cErrs = append(cErrs, validatePorts(ctr.Ports).Prefix("ports")...)
  1038  		cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...)
  1039  		cErrs = append(cErrs, validateVolumeMounts(ctr.VolumeMounts, volumes).Prefix("volumeMounts")...)
  1040  		cErrs = append(cErrs, validatePullPolicy(&ctr).Prefix("imagePullPolicy")...)
  1041  		cErrs = append(cErrs, ValidateResourceRequirements(&ctr.Resources).Prefix("resources")...)
  1042  		cErrs = append(cErrs, ValidateSecurityContext(ctr.SecurityContext).Prefix("securityContext")...)
  1043  		allErrs = append(allErrs, cErrs.PrefixIndex(i)...)
  1044  	}
  1045  	// Check for colliding ports across all containers.
  1046  	allErrs = append(allErrs, checkHostPortConflicts(containers)...)
  1047  
  1048  	return allErrs
  1049  }
  1050  
  1051  func validateRestartPolicy(restartPolicy *api.RestartPolicy) validation.ErrorList {
  1052  	allErrors := validation.ErrorList{}
  1053  	switch *restartPolicy {
  1054  	case api.RestartPolicyAlways, api.RestartPolicyOnFailure, api.RestartPolicyNever:
  1055  		break
  1056  	case "":
  1057  		allErrors = append(allErrors, validation.NewRequiredError(""))
  1058  	default:
  1059  		validValues := []string{string(api.RestartPolicyAlways), string(api.RestartPolicyOnFailure), string(api.RestartPolicyNever)}
  1060  		allErrors = append(allErrors, validation.NewNotSupportedError("", *restartPolicy, validValues))
  1061  	}
  1062  
  1063  	return allErrors
  1064  }
  1065  
  1066  func validateDNSPolicy(dnsPolicy *api.DNSPolicy) validation.ErrorList {
  1067  	allErrors := validation.ErrorList{}
  1068  	switch *dnsPolicy {
  1069  	case api.DNSClusterFirst, api.DNSDefault:
  1070  		break
  1071  	case "":
  1072  		allErrors = append(allErrors, validation.NewRequiredError(""))
  1073  	default:
  1074  		validValues := []string{string(api.DNSClusterFirst), string(api.DNSDefault)}
  1075  		allErrors = append(allErrors, validation.NewNotSupportedError("", dnsPolicy, validValues))
  1076  	}
  1077  	return allErrors
  1078  }
  1079  
  1080  func validateHostNetwork(hostNetwork bool, containers []api.Container) validation.ErrorList {
  1081  	allErrors := validation.ErrorList{}
  1082  	if hostNetwork {
  1083  		for _, container := range containers {
  1084  			for _, port := range container.Ports {
  1085  				if port.HostPort != port.ContainerPort {
  1086  					allErrors = append(allErrors, validation.NewInvalidError("containerPort", port.ContainerPort, "containerPort must match hostPort if hostNetwork is set to true"))
  1087  				}
  1088  			}
  1089  		}
  1090  	}
  1091  	return allErrors
  1092  }
  1093  
  1094  // validateImagePullSecrets checks to make sure the pull secrets are well formed.  Right now, we only expect name to be set (it's the only field).  If this ever changes
  1095  // and someone decides to set those fields, we'd like to know.
  1096  func validateImagePullSecrets(imagePullSecrets []api.LocalObjectReference) validation.ErrorList {
  1097  	allErrors := validation.ErrorList{}
  1098  	for i, currPullSecret := range imagePullSecrets {
  1099  		strippedRef := api.LocalObjectReference{Name: currPullSecret.Name}
  1100  
  1101  		if !reflect.DeepEqual(strippedRef, currPullSecret) {
  1102  			allErrors = append(allErrors, validation.NewInvalidError(fmt.Sprintf("[%d]", i), currPullSecret, "only name may be set"))
  1103  		}
  1104  	}
  1105  	return allErrors
  1106  }
  1107  
  1108  // ValidatePod tests if required fields in the pod are set.
  1109  func ValidatePod(pod *api.Pod) validation.ErrorList {
  1110  	allErrs := validation.ErrorList{}
  1111  	allErrs = append(allErrs, ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName).Prefix("metadata")...)
  1112  	allErrs = append(allErrs, ValidatePodSpec(&pod.Spec).Prefix("spec")...)
  1113  
  1114  	return allErrs
  1115  }
  1116  
  1117  // ValidatePodSpec tests that the specified PodSpec has valid data.
  1118  // This includes checking formatting and uniqueness.  It also canonicalizes the
  1119  // structure by setting default values and implementing any backwards-compatibility
  1120  // tricks.
  1121  func ValidatePodSpec(spec *api.PodSpec) validation.ErrorList {
  1122  	allErrs := validation.ErrorList{}
  1123  
  1124  	allVolumes, vErrs := validateVolumes(spec.Volumes)
  1125  	allErrs = append(allErrs, vErrs.Prefix("volumes")...)
  1126  	allErrs = append(allErrs, validateContainers(spec.Containers, allVolumes).Prefix("containers")...)
  1127  	allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy).Prefix("restartPolicy")...)
  1128  	allErrs = append(allErrs, validateDNSPolicy(&spec.DNSPolicy).Prefix("dnsPolicy")...)
  1129  	allErrs = append(allErrs, ValidateLabels(spec.NodeSelector, "nodeSelector")...)
  1130  	allErrs = append(allErrs, ValidatePodSecurityContext(spec.SecurityContext, spec).Prefix("securityContext")...)
  1131  	allErrs = append(allErrs, validateImagePullSecrets(spec.ImagePullSecrets).Prefix("imagePullSecrets")...)
  1132  	if len(spec.ServiceAccountName) > 0 {
  1133  		if ok, msg := ValidateServiceAccountName(spec.ServiceAccountName, false); !ok {
  1134  			allErrs = append(allErrs, validation.NewInvalidError("serviceAccountName", spec.ServiceAccountName, msg))
  1135  		}
  1136  	}
  1137  
  1138  	if spec.ActiveDeadlineSeconds != nil {
  1139  		if *spec.ActiveDeadlineSeconds <= 0 {
  1140  			allErrs = append(allErrs, validation.NewInvalidError("activeDeadlineSeconds", spec.ActiveDeadlineSeconds, "activeDeadlineSeconds must be a positive integer greater than 0"))
  1141  		}
  1142  	}
  1143  	return allErrs
  1144  }
  1145  
  1146  // ValidatePodSecurityContext test that the specified PodSecurityContext has valid data.
  1147  func ValidatePodSecurityContext(securityContext *api.PodSecurityContext, spec *api.PodSpec) validation.ErrorList {
  1148  	allErrs := validation.ErrorList{}
  1149  
  1150  	if securityContext != nil {
  1151  		allErrs = append(allErrs, validateHostNetwork(securityContext.HostNetwork, spec.Containers).Prefix("hostNetwork")...)
  1152  	}
  1153  
  1154  	return allErrs
  1155  }
  1156  
  1157  // ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  1158  // that cannot be changed.
  1159  func ValidatePodUpdate(newPod, oldPod *api.Pod) validation.ErrorList {
  1160  	allErrs := validation.ErrorList{}
  1161  
  1162  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta).Prefix("metadata")...)
  1163  
  1164  	if len(newPod.Spec.Containers) != len(oldPod.Spec.Containers) {
  1165  		//TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff
  1166  		allErrs = append(allErrs, validation.NewInvalidError("spec.containers", "content of spec.containers is not printed out, please refer to the \"details\"", "may not add or remove containers"))
  1167  		return allErrs
  1168  	}
  1169  	pod := *newPod
  1170  	// Tricky, we need to copy the container list so that we don't overwrite the update
  1171  	var newContainers []api.Container
  1172  	for ix, container := range pod.Spec.Containers {
  1173  		container.Image = oldPod.Spec.Containers[ix].Image
  1174  		newContainers = append(newContainers, container)
  1175  	}
  1176  	pod.Spec.Containers = newContainers
  1177  	if !api.Semantic.DeepEqual(pod.Spec, oldPod.Spec) {
  1178  		//TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
  1179  		allErrs = append(allErrs, validation.NewInvalidError("spec", "content of spec is not printed out, please refer to the \"details\"", "may not update fields other than container.image"))
  1180  	}
  1181  
  1182  	newPod.Status = oldPod.Status
  1183  	return allErrs
  1184  }
  1185  
  1186  // ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  1187  // that cannot be changed.
  1188  func ValidatePodStatusUpdate(newPod, oldPod *api.Pod) validation.ErrorList {
  1189  	allErrs := validation.ErrorList{}
  1190  
  1191  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newPod.ObjectMeta, &oldPod.ObjectMeta).Prefix("metadata")...)
  1192  
  1193  	// TODO: allow change when bindings are properly decoupled from pods
  1194  	if newPod.Spec.NodeName != oldPod.Spec.NodeName {
  1195  		allErrs = append(allErrs, validation.NewInvalidError("status.nodeName", newPod.Spec.NodeName, "pod nodename cannot be changed directly"))
  1196  	}
  1197  
  1198  	// For status update we ignore changes to pod spec.
  1199  	newPod.Spec = oldPod.Spec
  1200  
  1201  	return allErrs
  1202  }
  1203  
  1204  // ValidatePodTemplate tests if required fields in the pod template are set.
  1205  func ValidatePodTemplate(pod *api.PodTemplate) validation.ErrorList {
  1206  	allErrs := validation.ErrorList{}
  1207  	allErrs = append(allErrs, ValidateObjectMeta(&pod.ObjectMeta, true, ValidatePodName).Prefix("metadata")...)
  1208  	allErrs = append(allErrs, ValidatePodTemplateSpec(&pod.Template).Prefix("template")...)
  1209  	return allErrs
  1210  }
  1211  
  1212  // ValidatePodTemplateUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
  1213  // that cannot be changed.
  1214  func ValidatePodTemplateUpdate(newPod, oldPod *api.PodTemplate) validation.ErrorList {
  1215  	allErrs := validation.ErrorList{}
  1216  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&oldPod.ObjectMeta, &newPod.ObjectMeta).Prefix("metadata")...)
  1217  	allErrs = append(allErrs, ValidatePodTemplateSpec(&newPod.Template).Prefix("template")...)
  1218  	return allErrs
  1219  }
  1220  
  1221  var supportedSessionAffinityType = sets.NewString(string(api.ServiceAffinityClientIP), string(api.ServiceAffinityNone))
  1222  var supportedServiceType = sets.NewString(string(api.ServiceTypeClusterIP), string(api.ServiceTypeNodePort),
  1223  	string(api.ServiceTypeLoadBalancer))
  1224  
  1225  // ValidateService tests if required fields in the service are set.
  1226  func ValidateService(service *api.Service) validation.ErrorList {
  1227  	allErrs := validation.ErrorList{}
  1228  	allErrs = append(allErrs, ValidateObjectMeta(&service.ObjectMeta, true, ValidateServiceName).Prefix("metadata")...)
  1229  
  1230  	if len(service.Spec.Ports) == 0 && service.Spec.ClusterIP != api.ClusterIPNone {
  1231  		allErrs = append(allErrs, validation.NewRequiredError("spec.ports"))
  1232  	}
  1233  	if service.Spec.Type == api.ServiceTypeLoadBalancer {
  1234  		for ix := range service.Spec.Ports {
  1235  			port := &service.Spec.Ports[ix]
  1236  			if port.Port == 10250 {
  1237  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.ports[%d].port", ix), port.Port, "can not expose port 10250 externally since it is used by kubelet"))
  1238  			}
  1239  		}
  1240  	}
  1241  	allPortNames := sets.String{}
  1242  	for i := range service.Spec.Ports {
  1243  		allErrs = append(allErrs, validateServicePort(&service.Spec.Ports[i], len(service.Spec.Ports) > 1, &allPortNames).PrefixIndex(i).Prefix("spec.ports")...)
  1244  	}
  1245  
  1246  	if service.Spec.Selector != nil {
  1247  		allErrs = append(allErrs, ValidateLabels(service.Spec.Selector, "spec.selector")...)
  1248  	}
  1249  
  1250  	if service.Spec.SessionAffinity == "" {
  1251  		allErrs = append(allErrs, validation.NewRequiredError("spec.sessionAffinity"))
  1252  	} else if !supportedSessionAffinityType.Has(string(service.Spec.SessionAffinity)) {
  1253  		allErrs = append(allErrs, validation.NewNotSupportedError("spec.sessionAffinity", service.Spec.SessionAffinity, supportedSessionAffinityType.List()))
  1254  	}
  1255  
  1256  	if api.IsServiceIPSet(service) {
  1257  		if ip := net.ParseIP(service.Spec.ClusterIP); ip == nil {
  1258  			allErrs = append(allErrs, validation.NewInvalidError("spec.clusterIP", service.Spec.ClusterIP, "clusterIP should be empty, 'None', or a valid IP address"))
  1259  		}
  1260  	}
  1261  
  1262  	for _, ip := range service.Spec.ExternalIPs {
  1263  		if ip == "0.0.0.0" {
  1264  			allErrs = append(allErrs, validation.NewInvalidError("spec.externalIPs", ip, "is not an IP address"))
  1265  		}
  1266  		allErrs = append(allErrs, validateIpIsNotLinkLocalOrLoopback(ip, "spec.externalIPs")...)
  1267  	}
  1268  
  1269  	if service.Spec.Type == "" {
  1270  		allErrs = append(allErrs, validation.NewRequiredError("spec.type"))
  1271  	} else if !supportedServiceType.Has(string(service.Spec.Type)) {
  1272  		allErrs = append(allErrs, validation.NewNotSupportedError("spec.type", service.Spec.Type, supportedServiceType.List()))
  1273  	}
  1274  
  1275  	if service.Spec.Type == api.ServiceTypeLoadBalancer {
  1276  		for i := range service.Spec.Ports {
  1277  			if service.Spec.Ports[i].Protocol != api.ProtocolTCP {
  1278  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.ports[%d].protocol", i), service.Spec.Ports[i].Protocol, "cannot create an external load balancer with non-TCP ports"))
  1279  			}
  1280  		}
  1281  	}
  1282  
  1283  	if service.Spec.Type == api.ServiceTypeClusterIP {
  1284  		for i := range service.Spec.Ports {
  1285  			if service.Spec.Ports[i].NodePort != 0 {
  1286  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.ports[%d].nodePort", i), service.Spec.Ports[i].NodePort, "cannot specify a node port with services of type ClusterIP"))
  1287  			}
  1288  		}
  1289  	}
  1290  
  1291  	// Check for duplicate NodePorts, considering (protocol,port) pairs
  1292  	nodePorts := make(map[api.ServicePort]bool)
  1293  	for i := range service.Spec.Ports {
  1294  		port := &service.Spec.Ports[i]
  1295  		if port.NodePort == 0 {
  1296  			continue
  1297  		}
  1298  		var key api.ServicePort
  1299  		key.Protocol = port.Protocol
  1300  		key.NodePort = port.NodePort
  1301  		_, found := nodePorts[key]
  1302  		if found {
  1303  			allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.ports[%d].nodePort", i), port.NodePort, "duplicate nodePort specified"))
  1304  		}
  1305  		nodePorts[key] = true
  1306  	}
  1307  
  1308  	return allErrs
  1309  }
  1310  
  1311  func validateServicePort(sp *api.ServicePort, requireName bool, allNames *sets.String) validation.ErrorList {
  1312  	allErrs := validation.ErrorList{}
  1313  
  1314  	if requireName && sp.Name == "" {
  1315  		allErrs = append(allErrs, validation.NewRequiredError("name"))
  1316  	} else if sp.Name != "" {
  1317  		if !validation.IsDNS1123Label(sp.Name) {
  1318  			allErrs = append(allErrs, validation.NewInvalidError("name", sp.Name, DNS1123LabelErrorMsg))
  1319  		} else if allNames.Has(sp.Name) {
  1320  			allErrs = append(allErrs, validation.NewDuplicateError("name", sp.Name))
  1321  		} else {
  1322  			allNames.Insert(sp.Name)
  1323  		}
  1324  	}
  1325  
  1326  	if !validation.IsValidPortNum(sp.Port) {
  1327  		allErrs = append(allErrs, validation.NewInvalidError("port", sp.Port, PortRangeErrorMsg))
  1328  	}
  1329  
  1330  	if len(sp.Protocol) == 0 {
  1331  		allErrs = append(allErrs, validation.NewRequiredError("protocol"))
  1332  	} else if !supportedPortProtocols.Has(string(sp.Protocol)) {
  1333  		allErrs = append(allErrs, validation.NewNotSupportedError("protocol", sp.Protocol, supportedPortProtocols.List()))
  1334  	}
  1335  
  1336  	if sp.TargetPort.Type == intstr.Int && !validation.IsValidPortNum(sp.TargetPort.IntVal) {
  1337  		allErrs = append(allErrs, validation.NewInvalidError("targetPort", sp.TargetPort, PortRangeErrorMsg))
  1338  	}
  1339  	if sp.TargetPort.Type == intstr.String && !validation.IsValidPortName(sp.TargetPort.StrVal) {
  1340  		allErrs = append(allErrs, validation.NewInvalidError("targetPort", sp.TargetPort, PortNameErrorMsg))
  1341  	}
  1342  
  1343  	return allErrs
  1344  }
  1345  
  1346  // ValidateServiceUpdate tests if required fields in the service are set during an update
  1347  func ValidateServiceUpdate(service, oldService *api.Service) validation.ErrorList {
  1348  	allErrs := validation.ErrorList{}
  1349  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&service.ObjectMeta, &oldService.ObjectMeta).Prefix("metadata")...)
  1350  
  1351  	if api.IsServiceIPSet(oldService) {
  1352  		allErrs = append(allErrs, ValidateImmutableField(service.Spec.ClusterIP, oldService.Spec.ClusterIP, "spec.clusterIP")...)
  1353  	}
  1354  
  1355  	allErrs = append(allErrs, ValidateService(service)...)
  1356  	return allErrs
  1357  }
  1358  
  1359  // ValidateReplicationController tests if required fields in the replication controller are set.
  1360  func ValidateReplicationController(controller *api.ReplicationController) validation.ErrorList {
  1361  	allErrs := validation.ErrorList{}
  1362  	allErrs = append(allErrs, ValidateObjectMeta(&controller.ObjectMeta, true, ValidateReplicationControllerName).Prefix("metadata")...)
  1363  	allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec).Prefix("spec")...)
  1364  	return allErrs
  1365  }
  1366  
  1367  // ValidateReplicationControllerUpdate tests if required fields in the replication controller are set.
  1368  func ValidateReplicationControllerUpdate(controller, oldController *api.ReplicationController) validation.ErrorList {
  1369  	allErrs := validation.ErrorList{}
  1370  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta).Prefix("metadata")...)
  1371  	allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec).Prefix("spec")...)
  1372  	return allErrs
  1373  }
  1374  
  1375  // ValidateReplicationControllerStatusUpdate tests if required fields in the replication controller are set.
  1376  func ValidateReplicationControllerStatusUpdate(controller, oldController *api.ReplicationController) validation.ErrorList {
  1377  	allErrs := validation.ErrorList{}
  1378  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta).Prefix("metadata")...)
  1379  	allErrs = append(allErrs, ValidatePositiveField(int64(controller.Status.Replicas), "status.replicas")...)
  1380  	allErrs = append(allErrs, ValidatePositiveField(int64(controller.Status.ObservedGeneration), "status.observedGeneration")...)
  1381  	return allErrs
  1382  }
  1383  
  1384  // Validates that the given selector is non-empty.
  1385  func ValidateNonEmptySelector(selectorMap map[string]string, fieldName string) validation.ErrorList {
  1386  	allErrs := validation.ErrorList{}
  1387  	selector := labels.Set(selectorMap).AsSelector()
  1388  	if selector.Empty() {
  1389  		allErrs = append(allErrs, validation.NewRequiredError(fieldName))
  1390  	}
  1391  	return allErrs
  1392  }
  1393  
  1394  // Validates the given template and ensures that it is in accordance with the desrired selector and replicas.
  1395  func ValidatePodTemplateSpecForRC(template *api.PodTemplateSpec, selectorMap map[string]string, replicas int, fieldName string) validation.ErrorList {
  1396  	allErrs := validation.ErrorList{}
  1397  	if template == nil {
  1398  		allErrs = append(allErrs, validation.NewRequiredError(fieldName))
  1399  	} else {
  1400  		selector := labels.Set(selectorMap).AsSelector()
  1401  		if !selector.Empty() {
  1402  			// Verify that the RC selector matches the labels in template.
  1403  			labels := labels.Set(template.Labels)
  1404  			if !selector.Matches(labels) {
  1405  				allErrs = append(allErrs, validation.NewInvalidError(fieldName+".metadata.labels", template.Labels, "selector does not match labels in "+fieldName))
  1406  			}
  1407  		}
  1408  		allErrs = append(allErrs, ValidatePodTemplateSpec(template).Prefix(fieldName)...)
  1409  		if replicas > 1 {
  1410  			allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(template.Spec.Volumes).Prefix(fieldName+".spec.volumes")...)
  1411  		}
  1412  		// RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
  1413  		if template.Spec.RestartPolicy != api.RestartPolicyAlways {
  1414  			allErrs = append(allErrs, validation.NewNotSupportedError(fieldName+".spec.restartPolicy", template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
  1415  		}
  1416  	}
  1417  	return allErrs
  1418  }
  1419  
  1420  // ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set.
  1421  func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec) validation.ErrorList {
  1422  	allErrs := validation.ErrorList{}
  1423  
  1424  	allErrs = append(allErrs, ValidateNonEmptySelector(spec.Selector, "selector")...)
  1425  	allErrs = append(allErrs, ValidatePositiveField(int64(spec.Replicas), "replicas")...)
  1426  	allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, "template")...)
  1427  	return allErrs
  1428  }
  1429  
  1430  // ValidatePodTemplateSpec validates the spec of a pod template
  1431  func ValidatePodTemplateSpec(spec *api.PodTemplateSpec) validation.ErrorList {
  1432  	allErrs := validation.ErrorList{}
  1433  	allErrs = append(allErrs, ValidateLabels(spec.Labels, "labels")...)
  1434  	allErrs = append(allErrs, ValidateAnnotations(spec.Annotations, "annotations")...)
  1435  	allErrs = append(allErrs, ValidatePodSpec(&spec.Spec).Prefix("spec")...)
  1436  	return allErrs
  1437  }
  1438  
  1439  func ValidateReadOnlyPersistentDisks(volumes []api.Volume) validation.ErrorList {
  1440  	allErrs := validation.ErrorList{}
  1441  	for _, vol := range volumes {
  1442  		if vol.GCEPersistentDisk != nil {
  1443  			if vol.GCEPersistentDisk.ReadOnly == false {
  1444  				allErrs = append(allErrs, validation.NewInvalidError("GCEPersistentDisk.ReadOnly", false, "ReadOnly must be true for replicated pods > 1, as GCE PD can only be mounted on multiple machines if it is read-only."))
  1445  			}
  1446  		}
  1447  		// TODO: What to do for AWS?  It doesn't support replicas
  1448  	}
  1449  	return allErrs
  1450  }
  1451  
  1452  // ValidateNode tests if required fields in the node are set.
  1453  func ValidateNode(node *api.Node) validation.ErrorList {
  1454  	allErrs := validation.ErrorList{}
  1455  	allErrs = append(allErrs, ValidateObjectMeta(&node.ObjectMeta, false, ValidateNodeName).Prefix("metadata")...)
  1456  
  1457  	// Only validate spec. All status fields are optional and can be updated later.
  1458  
  1459  	// external ID is required.
  1460  	if len(node.Spec.ExternalID) == 0 {
  1461  		allErrs = append(allErrs, validation.NewRequiredError("spec.ExternalID"))
  1462  	}
  1463  
  1464  	// TODO(rjnagal): Ignore PodCIDR till its completely implemented.
  1465  	return allErrs
  1466  }
  1467  
  1468  // ValidateNodeUpdate tests to make sure a node update can be applied.  Modifies oldNode.
  1469  func ValidateNodeUpdate(node, oldNode *api.Node) validation.ErrorList {
  1470  	allErrs := validation.ErrorList{}
  1471  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&node.ObjectMeta, &oldNode.ObjectMeta).Prefix("metadata")...)
  1472  
  1473  	// TODO: Enable the code once we have better api object.status update model. Currently,
  1474  	// anyone can update node status.
  1475  	// if !api.Semantic.DeepEqual(node.Status, api.NodeStatus{}) {
  1476  	// 	allErrs = append(allErrs, validation.NewInvalidError("status", node.Status, "status must be empty"))
  1477  	// }
  1478  
  1479  	// Validte no duplicate addresses in node status.
  1480  	addresses := make(map[api.NodeAddress]bool)
  1481  	for _, address := range node.Status.Addresses {
  1482  		if _, ok := addresses[address]; ok {
  1483  			allErrs = append(allErrs, validation.NewDuplicateError("addresses", address))
  1484  		}
  1485  		addresses[address] = true
  1486  	}
  1487  
  1488  	// TODO: move reset function to its own location
  1489  	// Ignore metadata changes now that they have been tested
  1490  	oldNode.ObjectMeta = node.ObjectMeta
  1491  	// Allow users to update capacity
  1492  	oldNode.Status.Capacity = node.Status.Capacity
  1493  	// Allow the controller manager to assign a CIDR to a node.
  1494  	oldNode.Spec.PodCIDR = node.Spec.PodCIDR
  1495  	// Allow users to unschedule node
  1496  	oldNode.Spec.Unschedulable = node.Spec.Unschedulable
  1497  	// Clear status
  1498  	oldNode.Status = node.Status
  1499  
  1500  	// TODO: Add a 'real' error type for this error and provide print actual diffs.
  1501  	if !api.Semantic.DeepEqual(oldNode, node) {
  1502  		glog.V(4).Infof("Update failed validation %#v vs %#v", oldNode, node)
  1503  		allErrs = append(allErrs, validation.NewForbiddenError("", "update contains more than labels or capacity changes"))
  1504  	}
  1505  
  1506  	return allErrs
  1507  }
  1508  
  1509  // Validate compute resource typename.
  1510  // Refer to docs/design/resources.md for more details.
  1511  func validateResourceName(value string, field string) validation.ErrorList {
  1512  	allErrs := validation.ErrorList{}
  1513  	if !validation.IsQualifiedName(value) {
  1514  		return append(allErrs, validation.NewInvalidError(field, value, "resource typename: "+qualifiedNameErrorMsg))
  1515  	}
  1516  
  1517  	if len(strings.Split(value, "/")) == 1 {
  1518  		if !api.IsStandardResourceName(value) {
  1519  			return append(allErrs, validation.NewInvalidError(field, value, "is neither a standard resource type nor is fully qualified"))
  1520  		}
  1521  	}
  1522  
  1523  	return validation.ErrorList{}
  1524  }
  1525  
  1526  // ValidateLimitRange tests if required fields in the LimitRange are set.
  1527  func ValidateLimitRange(limitRange *api.LimitRange) validation.ErrorList {
  1528  	allErrs := validation.ErrorList{}
  1529  	allErrs = append(allErrs, ValidateObjectMeta(&limitRange.ObjectMeta, true, ValidateLimitRangeName).Prefix("metadata")...)
  1530  
  1531  	// ensure resource names are properly qualified per docs/design/resources.md
  1532  	limitTypeSet := map[api.LimitType]bool{}
  1533  	for i := range limitRange.Spec.Limits {
  1534  		limit := limitRange.Spec.Limits[i]
  1535  		_, found := limitTypeSet[limit.Type]
  1536  		if found {
  1537  			allErrs = append(allErrs, validation.NewDuplicateError(fmt.Sprintf("spec.limits[%d].type", i), limit.Type))
  1538  		}
  1539  		limitTypeSet[limit.Type] = true
  1540  
  1541  		keys := sets.String{}
  1542  		min := map[string]resource.Quantity{}
  1543  		max := map[string]resource.Quantity{}
  1544  		defaults := map[string]resource.Quantity{}
  1545  		defaultRequests := map[string]resource.Quantity{}
  1546  		maxLimitRequestRatios := map[string]resource.Quantity{}
  1547  
  1548  		for k, q := range limit.Max {
  1549  			allErrs = append(allErrs, validateResourceName(string(k), fmt.Sprintf("spec.limits[%d].max[%s]", i, k))...)
  1550  			keys.Insert(string(k))
  1551  			max[string(k)] = q
  1552  		}
  1553  		for k, q := range limit.Min {
  1554  			allErrs = append(allErrs, validateResourceName(string(k), fmt.Sprintf("spec.limits[%d].min[%s]", i, k))...)
  1555  			keys.Insert(string(k))
  1556  			min[string(k)] = q
  1557  		}
  1558  
  1559  		if limit.Type == api.LimitTypePod {
  1560  			if len(limit.Default) > 0 {
  1561  				allErrs = append(allErrs, validation.NewInvalidError("spec.limits[%d].default", limit.Default, "Default is not supported when limit type is Pod"))
  1562  			}
  1563  			if len(limit.DefaultRequest) > 0 {
  1564  				allErrs = append(allErrs, validation.NewInvalidError("spec.limits[%d].defaultRequest", limit.DefaultRequest, "DefaultRequest is not supported when limit type is Pod"))
  1565  			}
  1566  		} else {
  1567  			for k, q := range limit.Default {
  1568  				allErrs = append(allErrs, validateResourceName(string(k), fmt.Sprintf("spec.limits[%d].default[%s]", i, k))...)
  1569  				keys.Insert(string(k))
  1570  				defaults[string(k)] = q
  1571  			}
  1572  			for k, q := range limit.DefaultRequest {
  1573  				allErrs = append(allErrs, validateResourceName(string(k), fmt.Sprintf("spec.limits[%d].defaultRequest[%s]", i, k))...)
  1574  				keys.Insert(string(k))
  1575  				defaultRequests[string(k)] = q
  1576  			}
  1577  		}
  1578  
  1579  		for k, q := range limit.MaxLimitRequestRatio {
  1580  			allErrs = append(allErrs, validateResourceName(string(k), fmt.Sprintf("spec.limits[%d].maxLimitRequestRatio[%s]", i, k))...)
  1581  			keys.Insert(string(k))
  1582  			maxLimitRequestRatios[string(k)] = q
  1583  		}
  1584  
  1585  		for k := range keys {
  1586  			minQuantity, minQuantityFound := min[k]
  1587  			maxQuantity, maxQuantityFound := max[k]
  1588  			defaultQuantity, defaultQuantityFound := defaults[k]
  1589  			defaultRequestQuantity, defaultRequestQuantityFound := defaultRequests[k]
  1590  			maxRatio, maxRatioFound := maxLimitRequestRatios[k]
  1591  
  1592  			if minQuantityFound && maxQuantityFound && minQuantity.Cmp(maxQuantity) > 0 {
  1593  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].min[%s]", i, k), minQuantity, fmt.Sprintf("min value %s is greater than max value %s", minQuantity.String(), maxQuantity.String())))
  1594  			}
  1595  
  1596  			if defaultRequestQuantityFound && minQuantityFound && minQuantity.Cmp(defaultRequestQuantity) > 0 {
  1597  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].defaultRequest[%s]", i, k), defaultRequestQuantity, fmt.Sprintf("min value %s is greater than default request value %s", minQuantity.String(), defaultRequestQuantity.String())))
  1598  			}
  1599  
  1600  			if defaultRequestQuantityFound && maxQuantityFound && defaultRequestQuantity.Cmp(maxQuantity) > 0 {
  1601  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].defaultRequest[%s]", i, k), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than max value %s", defaultRequestQuantity.String(), maxQuantity.String())))
  1602  			}
  1603  
  1604  			if defaultRequestQuantityFound && defaultQuantityFound && defaultRequestQuantity.Cmp(defaultQuantity) > 0 {
  1605  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].defaultRequest[%s]", i, k), defaultRequestQuantity, fmt.Sprintf("default request value %s is greater than default limit value %s", defaultRequestQuantity.String(), defaultQuantity.String())))
  1606  			}
  1607  
  1608  			if defaultQuantityFound && minQuantityFound && minQuantity.Cmp(defaultQuantity) > 0 {
  1609  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].default[%s]", i, k), minQuantity, fmt.Sprintf("min value %s is greater than default value %s", minQuantity.String(), defaultQuantity.String())))
  1610  			}
  1611  
  1612  			if defaultQuantityFound && maxQuantityFound && defaultQuantity.Cmp(maxQuantity) > 0 {
  1613  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].default[%s]", i, k), maxQuantity, fmt.Sprintf("default value %s is greater than max value %s", defaultQuantity.String(), maxQuantity.String())))
  1614  			}
  1615  			if maxRatioFound && maxRatio.Cmp(*resource.NewQuantity(1, resource.DecimalSI)) < 0 {
  1616  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].maxLimitRequestRatio[%s]", i, k), maxRatio, fmt.Sprintf("maxLimitRequestRatio %s is less than 1", maxRatio.String())))
  1617  			}
  1618  			if maxRatioFound && minQuantityFound && maxQuantityFound {
  1619  				maxRatioValue := float64(maxRatio.Value())
  1620  				minQuantityValue := minQuantity.Value()
  1621  				maxQuantityValue := maxQuantity.Value()
  1622  				if maxRatio.Value() < resource.MaxMilliValue && minQuantityValue < resource.MaxMilliValue && maxQuantityValue < resource.MaxMilliValue {
  1623  					maxRatioValue = float64(maxRatio.MilliValue()) / 1000
  1624  					minQuantityValue = minQuantity.MilliValue()
  1625  					maxQuantityValue = maxQuantity.MilliValue()
  1626  				}
  1627  				maxRatioLimit := float64(maxQuantityValue) / float64(minQuantityValue)
  1628  				if maxRatioValue > maxRatioLimit {
  1629  					allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("spec.limits[%d].maxLimitRequestRatio[%s]", i, k), maxRatio, fmt.Sprintf("maxLimitRequestRatio %s is greater than max/min = %f", maxRatio.String(), maxRatioLimit)))
  1630  				}
  1631  			}
  1632  		}
  1633  	}
  1634  
  1635  	return allErrs
  1636  }
  1637  
  1638  // ValidateServiceAccount tests if required fields in the ServiceAccount are set.
  1639  func ValidateServiceAccount(serviceAccount *api.ServiceAccount) validation.ErrorList {
  1640  	allErrs := validation.ErrorList{}
  1641  	allErrs = append(allErrs, ValidateObjectMeta(&serviceAccount.ObjectMeta, true, ValidateServiceAccountName).Prefix("metadata")...)
  1642  	return allErrs
  1643  }
  1644  
  1645  // ValidateServiceAccountUpdate tests if required fields in the ServiceAccount are set.
  1646  func ValidateServiceAccountUpdate(newServiceAccount, oldServiceAccount *api.ServiceAccount) validation.ErrorList {
  1647  	allErrs := validation.ErrorList{}
  1648  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newServiceAccount.ObjectMeta, &oldServiceAccount.ObjectMeta).Prefix("metadata")...)
  1649  	allErrs = append(allErrs, ValidateServiceAccount(newServiceAccount)...)
  1650  	return allErrs
  1651  }
  1652  
  1653  const SecretKeyFmt string = "\\.?" + validation.DNS1123LabelFmt + "(\\." + validation.DNS1123LabelFmt + ")*"
  1654  
  1655  var secretKeyRegexp = regexp.MustCompile("^" + SecretKeyFmt + "$")
  1656  
  1657  // IsSecretKey tests for a string that conforms to the definition of a
  1658  // subdomain in DNS (RFC 1123), except that a leading dot is allowed
  1659  func IsSecretKey(value string) bool {
  1660  	return len(value) <= validation.DNS1123SubdomainMaxLength && secretKeyRegexp.MatchString(value)
  1661  }
  1662  
  1663  // ValidateSecret tests if required fields in the Secret are set.
  1664  func ValidateSecret(secret *api.Secret) validation.ErrorList {
  1665  	allErrs := validation.ErrorList{}
  1666  	allErrs = append(allErrs, ValidateObjectMeta(&secret.ObjectMeta, true, ValidateSecretName).Prefix("metadata")...)
  1667  
  1668  	totalSize := 0
  1669  	for key, value := range secret.Data {
  1670  		if !IsSecretKey(key) {
  1671  			allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("data[%s]", key), key, fmt.Sprintf("must have at most %d characters and match regex %s", validation.DNS1123SubdomainMaxLength, SecretKeyFmt)))
  1672  		}
  1673  
  1674  		totalSize += len(value)
  1675  	}
  1676  
  1677  	if totalSize > api.MaxSecretSize {
  1678  		allErrs = append(allErrs, validation.NewForbiddenError("data", "Maximum secret size exceeded"))
  1679  	}
  1680  
  1681  	switch secret.Type {
  1682  	case api.SecretTypeServiceAccountToken:
  1683  		// Only require Annotations[kubernetes.io/service-account.name]
  1684  		// Additional fields (like Annotations[kubernetes.io/service-account.uid] and Data[token]) might be contributed later by a controller loop
  1685  		if value := secret.Annotations[api.ServiceAccountNameKey]; len(value) == 0 {
  1686  			allErrs = append(allErrs, validation.NewRequiredError(fmt.Sprintf("metadata.annotations[%s]", api.ServiceAccountNameKey)))
  1687  		}
  1688  	case api.SecretTypeOpaque, "":
  1689  	// no-op
  1690  	case api.SecretTypeDockercfg:
  1691  		dockercfgBytes, exists := secret.Data[api.DockerConfigKey]
  1692  		if !exists {
  1693  			allErrs = append(allErrs, validation.NewRequiredError(fmt.Sprintf("data[%s]", api.DockerConfigKey)))
  1694  			break
  1695  		}
  1696  
  1697  		// make sure that the content is well-formed json.
  1698  		if err := json.Unmarshal(dockercfgBytes, &map[string]interface{}{}); err != nil {
  1699  			allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("data[%s]", api.DockerConfigKey), "<secret contents redacted>", err.Error()))
  1700  		}
  1701  
  1702  	default:
  1703  		// no-op
  1704  	}
  1705  
  1706  	return allErrs
  1707  }
  1708  
  1709  // ValidateSecretUpdate tests if required fields in the Secret are set.
  1710  func ValidateSecretUpdate(newSecret, oldSecret *api.Secret) validation.ErrorList {
  1711  	allErrs := validation.ErrorList{}
  1712  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newSecret.ObjectMeta, &oldSecret.ObjectMeta).Prefix("metadata")...)
  1713  
  1714  	if len(newSecret.Type) == 0 {
  1715  		newSecret.Type = oldSecret.Type
  1716  	}
  1717  
  1718  	allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, oldSecret.Type, "type")...)
  1719  
  1720  	allErrs = append(allErrs, ValidateSecret(newSecret)...)
  1721  	return allErrs
  1722  }
  1723  
  1724  func validateBasicResource(quantity resource.Quantity) validation.ErrorList {
  1725  	if quantity.Value() < 0 {
  1726  		return validation.ErrorList{validation.NewInvalidError("", quantity.Value(), "must be a valid resource quantity")}
  1727  	}
  1728  	return validation.ErrorList{}
  1729  }
  1730  
  1731  // Validates resource requirement spec.
  1732  func ValidateResourceRequirements(requirements *api.ResourceRequirements) validation.ErrorList {
  1733  	allErrs := validation.ErrorList{}
  1734  	for resourceName, quantity := range requirements.Limits {
  1735  		// Validate resource name.
  1736  		allErrs = append(allErrs, validateResourceName(resourceName.String(), fmt.Sprintf("resources.limits[%s]", resourceName))...)
  1737  		if api.IsStandardResourceName(resourceName.String()) {
  1738  			allErrs = append(allErrs, validateBasicResource(quantity).Prefix(fmt.Sprintf("Resource %s: ", resourceName))...)
  1739  		}
  1740  		// Check that request <= limit.
  1741  		requestQuantity, exists := requirements.Requests[resourceName]
  1742  		if exists {
  1743  			var requestValue, limitValue int64
  1744  			requestValue = requestQuantity.Value()
  1745  			limitValue = quantity.Value()
  1746  			// Do a more precise comparison if possible (if the value won't overflow).
  1747  			if requestValue <= resource.MaxMilliValue && limitValue <= resource.MaxMilliValue {
  1748  				requestValue = requestQuantity.MilliValue()
  1749  				limitValue = quantity.MilliValue()
  1750  			}
  1751  			if limitValue < requestValue {
  1752  				allErrs = append(allErrs, validation.NewInvalidError(fmt.Sprintf("resources.limits[%s]", resourceName), quantity.String(), "limit cannot be smaller than request"))
  1753  			}
  1754  		}
  1755  	}
  1756  	for resourceName, quantity := range requirements.Requests {
  1757  		// Validate resource name.
  1758  		allErrs = append(allErrs, validateResourceName(resourceName.String(), fmt.Sprintf("resources.requests[%s]", resourceName))...)
  1759  		if api.IsStandardResourceName(resourceName.String()) {
  1760  			allErrs = append(allErrs, validateBasicResource(quantity).Prefix(fmt.Sprintf("Resource %s: ", resourceName))...)
  1761  		}
  1762  	}
  1763  	return allErrs
  1764  }
  1765  
  1766  // ValidateResourceQuota tests if required fields in the ResourceQuota are set.
  1767  func ValidateResourceQuota(resourceQuota *api.ResourceQuota) validation.ErrorList {
  1768  	allErrs := validation.ErrorList{}
  1769  	allErrs = append(allErrs, ValidateObjectMeta(&resourceQuota.ObjectMeta, true, ValidateResourceQuotaName).Prefix("metadata")...)
  1770  
  1771  	for k, v := range resourceQuota.Spec.Hard {
  1772  		allErrs = append(allErrs, validateResourceName(string(k), string(resourceQuota.TypeMeta.Kind))...)
  1773  		allErrs = append(allErrs, validateResourceQuantityValue(string(k), v)...)
  1774  	}
  1775  	for k, v := range resourceQuota.Status.Hard {
  1776  		allErrs = append(allErrs, validateResourceName(string(k), string(resourceQuota.TypeMeta.Kind))...)
  1777  		allErrs = append(allErrs, validateResourceQuantityValue(string(k), v)...)
  1778  	}
  1779  	for k, v := range resourceQuota.Status.Used {
  1780  		allErrs = append(allErrs, validateResourceName(string(k), string(resourceQuota.TypeMeta.Kind))...)
  1781  		allErrs = append(allErrs, validateResourceQuantityValue(string(k), v)...)
  1782  	}
  1783  	return allErrs
  1784  }
  1785  
  1786  // validateResourceQuantityValue enforces that specified quantity is valid for specified resource
  1787  func validateResourceQuantityValue(resource string, value resource.Quantity) validation.ErrorList {
  1788  	allErrs := validation.ErrorList{}
  1789  	allErrs = append(allErrs, ValidatePositiveQuantity(value, resource)...)
  1790  	if api.IsIntegerResourceName(resource) {
  1791  		if value.MilliValue()%int64(1000) != int64(0) {
  1792  			allErrs = append(allErrs, validation.NewInvalidError(resource, value, isNotIntegerErrorMsg))
  1793  		}
  1794  	}
  1795  	return allErrs
  1796  }
  1797  
  1798  // ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make.
  1799  // newResourceQuota is updated with fields that cannot be changed.
  1800  func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) validation.ErrorList {
  1801  	allErrs := validation.ErrorList{}
  1802  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta).Prefix("metadata")...)
  1803  	for k, v := range newResourceQuota.Spec.Hard {
  1804  		allErrs = append(allErrs, validateResourceName(string(k), string(newResourceQuota.TypeMeta.Kind))...)
  1805  		allErrs = append(allErrs, validateResourceQuantityValue(string(k), v)...)
  1806  	}
  1807  	newResourceQuota.Status = oldResourceQuota.Status
  1808  	return allErrs
  1809  }
  1810  
  1811  // ValidateResourceQuotaStatusUpdate tests to see if the status update is legal for an end user to make.
  1812  // newResourceQuota is updated with fields that cannot be changed.
  1813  func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota *api.ResourceQuota) validation.ErrorList {
  1814  	allErrs := validation.ErrorList{}
  1815  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, &oldResourceQuota.ObjectMeta).Prefix("metadata")...)
  1816  	if newResourceQuota.ResourceVersion == "" {
  1817  		allErrs = append(allErrs, validation.NewRequiredError("resourceVersion"))
  1818  	}
  1819  	for k, v := range newResourceQuota.Status.Hard {
  1820  		allErrs = append(allErrs, validateResourceName(string(k), string(newResourceQuota.TypeMeta.Kind))...)
  1821  		allErrs = append(allErrs, validateResourceQuantityValue(string(k), v)...)
  1822  	}
  1823  	for k, v := range newResourceQuota.Status.Used {
  1824  		allErrs = append(allErrs, validateResourceName(string(k), string(newResourceQuota.TypeMeta.Kind))...)
  1825  		allErrs = append(allErrs, validateResourceQuantityValue(string(k), v)...)
  1826  	}
  1827  	newResourceQuota.Spec = oldResourceQuota.Spec
  1828  	return allErrs
  1829  }
  1830  
  1831  // ValidateNamespace tests if required fields are set.
  1832  func ValidateNamespace(namespace *api.Namespace) validation.ErrorList {
  1833  	allErrs := validation.ErrorList{}
  1834  	allErrs = append(allErrs, ValidateObjectMeta(&namespace.ObjectMeta, false, ValidateNamespaceName).Prefix("metadata")...)
  1835  	for i := range namespace.Spec.Finalizers {
  1836  		allErrs = append(allErrs, validateFinalizerName(string(namespace.Spec.Finalizers[i]))...)
  1837  	}
  1838  	return allErrs
  1839  }
  1840  
  1841  // Validate finalizer names
  1842  func validateFinalizerName(stringValue string) validation.ErrorList {
  1843  	allErrs := validation.ErrorList{}
  1844  	if !validation.IsQualifiedName(stringValue) {
  1845  		return append(allErrs, validation.NewInvalidError("spec.finalizers", stringValue, qualifiedNameErrorMsg))
  1846  	}
  1847  
  1848  	if len(strings.Split(stringValue, "/")) == 1 {
  1849  		if !api.IsStandardFinalizerName(stringValue) {
  1850  			return append(allErrs, validation.NewInvalidError("spec.finalizers", stringValue, fmt.Sprintf("finalizer name is neither a standard finalizer name nor is it fully qualified")))
  1851  		}
  1852  	}
  1853  
  1854  	return validation.ErrorList{}
  1855  }
  1856  
  1857  // ValidateNamespaceUpdate tests to make sure a namespace update can be applied.
  1858  // newNamespace is updated with fields that cannot be changed
  1859  func ValidateNamespaceUpdate(newNamespace *api.Namespace, oldNamespace *api.Namespace) validation.ErrorList {
  1860  	allErrs := validation.ErrorList{}
  1861  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta).Prefix("metadata")...)
  1862  	newNamespace.Spec.Finalizers = oldNamespace.Spec.Finalizers
  1863  	newNamespace.Status = oldNamespace.Status
  1864  	return allErrs
  1865  }
  1866  
  1867  // ValidateNamespaceStatusUpdate tests to see if the update is legal for an end user to make. newNamespace is updated with fields
  1868  // that cannot be changed.
  1869  func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace *api.Namespace) validation.ErrorList {
  1870  	allErrs := validation.ErrorList{}
  1871  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta).Prefix("metadata")...)
  1872  	newNamespace.Spec = oldNamespace.Spec
  1873  	if newNamespace.DeletionTimestamp.IsZero() {
  1874  		if newNamespace.Status.Phase != api.NamespaceActive {
  1875  			allErrs = append(allErrs, validation.NewInvalidError("Status.Phase", newNamespace.Status.Phase, "A namespace may only be in active status if it does not have a deletion timestamp."))
  1876  		}
  1877  	} else {
  1878  		if newNamespace.Status.Phase != api.NamespaceTerminating {
  1879  			allErrs = append(allErrs, validation.NewInvalidError("Status.Phase", newNamespace.Status.Phase, "A namespace may only be in terminating status if it has a deletion timestamp."))
  1880  		}
  1881  	}
  1882  	return allErrs
  1883  }
  1884  
  1885  // ValidateNamespaceFinalizeUpdate tests to see if the update is legal for an end user to make.
  1886  // newNamespace is updated with fields that cannot be changed.
  1887  func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace *api.Namespace) validation.ErrorList {
  1888  	allErrs := validation.ErrorList{}
  1889  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, &oldNamespace.ObjectMeta).Prefix("metadata")...)
  1890  	for i := range newNamespace.Spec.Finalizers {
  1891  		allErrs = append(allErrs, validateFinalizerName(string(newNamespace.Spec.Finalizers[i]))...)
  1892  	}
  1893  	newNamespace.Status = oldNamespace.Status
  1894  	return allErrs
  1895  }
  1896  
  1897  // ValidateEndpoints tests if required fields are set.
  1898  func ValidateEndpoints(endpoints *api.Endpoints) validation.ErrorList {
  1899  	allErrs := validation.ErrorList{}
  1900  	allErrs = append(allErrs, ValidateObjectMeta(&endpoints.ObjectMeta, true, ValidateEndpointsName).Prefix("metadata")...)
  1901  	allErrs = append(allErrs, validateEndpointSubsets(endpoints.Subsets).Prefix("subsets")...)
  1902  	return allErrs
  1903  }
  1904  
  1905  func validateEndpointSubsets(subsets []api.EndpointSubset) validation.ErrorList {
  1906  	allErrs := validation.ErrorList{}
  1907  
  1908  	for i := range subsets {
  1909  		ss := &subsets[i]
  1910  
  1911  		ssErrs := validation.ErrorList{}
  1912  
  1913  		if len(ss.Addresses) == 0 && len(ss.NotReadyAddresses) == 0 {
  1914  			ssErrs = append(ssErrs, validation.NewRequiredError("addresses or notReadyAddresses"))
  1915  		}
  1916  		if len(ss.Ports) == 0 {
  1917  			ssErrs = append(ssErrs, validation.NewRequiredError("ports"))
  1918  		}
  1919  		for addr := range ss.Addresses {
  1920  			ssErrs = append(ssErrs, validateEndpointAddress(&ss.Addresses[addr]).PrefixIndex(addr).Prefix("addresses")...)
  1921  		}
  1922  		for port := range ss.Ports {
  1923  			ssErrs = append(ssErrs, validateEndpointPort(&ss.Ports[port], len(ss.Ports) > 1).PrefixIndex(port).Prefix("ports")...)
  1924  		}
  1925  
  1926  		allErrs = append(allErrs, ssErrs.PrefixIndex(i)...)
  1927  	}
  1928  
  1929  	return allErrs
  1930  }
  1931  
  1932  func validateEndpointAddress(address *api.EndpointAddress) validation.ErrorList {
  1933  	allErrs := validation.ErrorList{}
  1934  	if !validation.IsValidIPv4(address.IP) {
  1935  		allErrs = append(allErrs, validation.NewInvalidError("ip", address.IP, "invalid IPv4 address"))
  1936  		return allErrs
  1937  	}
  1938  	return validateIpIsNotLinkLocalOrLoopback(address.IP, "ip")
  1939  }
  1940  
  1941  func validateIpIsNotLinkLocalOrLoopback(ipAddress, fieldName string) validation.ErrorList {
  1942  	// We disallow some IPs as endpoints or external-ips.  Specifically, loopback addresses are
  1943  	// nonsensical and link-local addresses tend to be used for node-centric purposes (e.g. metadata service).
  1944  	allErrs := validation.ErrorList{}
  1945  	ip := net.ParseIP(ipAddress)
  1946  	if ip == nil {
  1947  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, ipAddress, "not a valid IP address"))
  1948  		return allErrs
  1949  	}
  1950  	if ip.IsLoopback() {
  1951  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, ipAddress, "may not be in the loopback range (127.0.0.0/8)"))
  1952  	}
  1953  	if ip.IsLinkLocalUnicast() {
  1954  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, ipAddress, "may not be in the link-local range (169.254.0.0/16)"))
  1955  	}
  1956  	if ip.IsLinkLocalMulticast() {
  1957  		allErrs = append(allErrs, validation.NewInvalidError(fieldName, ipAddress, "may not be in the link-local multicast range (224.0.0.0/24)"))
  1958  	}
  1959  	return allErrs
  1960  }
  1961  
  1962  func validateEndpointPort(port *api.EndpointPort, requireName bool) validation.ErrorList {
  1963  	allErrs := validation.ErrorList{}
  1964  	if requireName && port.Name == "" {
  1965  		allErrs = append(allErrs, validation.NewRequiredError("name"))
  1966  	} else if port.Name != "" {
  1967  		if !validation.IsDNS1123Label(port.Name) {
  1968  			allErrs = append(allErrs, validation.NewInvalidError("name", port.Name, DNS1123LabelErrorMsg))
  1969  		}
  1970  	}
  1971  	if !validation.IsValidPortNum(port.Port) {
  1972  		allErrs = append(allErrs, validation.NewInvalidError("port", port.Port, PortRangeErrorMsg))
  1973  	}
  1974  	if len(port.Protocol) == 0 {
  1975  		allErrs = append(allErrs, validation.NewRequiredError("protocol"))
  1976  	} else if !supportedPortProtocols.Has(string(port.Protocol)) {
  1977  		allErrs = append(allErrs, validation.NewNotSupportedError("protocol", port.Protocol, supportedPortProtocols.List()))
  1978  	}
  1979  	return allErrs
  1980  }
  1981  
  1982  // ValidateEndpointsUpdate tests to make sure an endpoints update can be applied.
  1983  func ValidateEndpointsUpdate(newEndpoints, oldEndpoints *api.Endpoints) validation.ErrorList {
  1984  	allErrs := validation.ErrorList{}
  1985  	allErrs = append(allErrs, ValidateObjectMetaUpdate(&newEndpoints.ObjectMeta, &oldEndpoints.ObjectMeta).Prefix("metadata")...)
  1986  	allErrs = append(allErrs, validateEndpointSubsets(newEndpoints.Subsets).Prefix("subsets")...)
  1987  	return allErrs
  1988  }
  1989  
  1990  // ValidateSecurityContext ensure the security context contains valid settings
  1991  func ValidateSecurityContext(sc *api.SecurityContext) validation.ErrorList {
  1992  	allErrs := validation.ErrorList{}
  1993  	//this should only be true for testing since SecurityContext is defaulted by the api
  1994  	if sc == nil {
  1995  		return allErrs
  1996  	}
  1997  
  1998  	if sc.Privileged != nil {
  1999  		if *sc.Privileged && !capabilities.Get().AllowPrivileged {
  2000  			allErrs = append(allErrs, validation.NewForbiddenError("privileged", sc.Privileged))
  2001  		}
  2002  	}
  2003  
  2004  	if sc.RunAsUser != nil {
  2005  		if *sc.RunAsUser < 0 {
  2006  			allErrs = append(allErrs, validation.NewInvalidError("runAsUser", *sc.RunAsUser, "runAsUser cannot be negative"))
  2007  		}
  2008  	}
  2009  	return allErrs
  2010  }
  2011  
  2012  func ValidatePodLogOptions(opts *api.PodLogOptions) validation.ErrorList {
  2013  	allErrs := validation.ErrorList{}
  2014  	if opts.TailLines != nil && *opts.TailLines < 0 {
  2015  		allErrs = append(allErrs, validation.NewInvalidError("tailLines", *opts.TailLines, "tailLines must be a non-negative integer or nil"))
  2016  	}
  2017  	if opts.LimitBytes != nil && *opts.LimitBytes < 1 {
  2018  		allErrs = append(allErrs, validation.NewInvalidError("limitBytes", *opts.LimitBytes, "limitBytes must be a positive integer or nil"))
  2019  	}
  2020  	switch {
  2021  	case opts.SinceSeconds != nil && opts.SinceTime != nil:
  2022  		allErrs = append(allErrs, validation.NewInvalidError("sinceSeconds", *opts.SinceSeconds, "only one of sinceTime or sinceSeconds can be provided"))
  2023  		allErrs = append(allErrs, validation.NewInvalidError("sinceTime", *opts.SinceTime, "only one of sinceTime or sinceSeconds can be provided"))
  2024  	case opts.SinceSeconds != nil:
  2025  		if *opts.SinceSeconds < 1 {
  2026  			allErrs = append(allErrs, validation.NewInvalidError("sinceSeconds", *opts.SinceSeconds, "sinceSeconds must be a positive integer"))
  2027  		}
  2028  	}
  2029  	return allErrs
  2030  }
  2031  
  2032  // ValidateLoadBalancerStatus validates required fields on a LoadBalancerStatus
  2033  func ValidateLoadBalancerStatus(status *api.LoadBalancerStatus) validation.ErrorList {
  2034  	allErrs := validation.ErrorList{}
  2035  	for _, ingress := range status.Ingress {
  2036  		if len(ingress.IP) > 0 {
  2037  			if isIP := (net.ParseIP(ingress.IP) != nil); !isIP {
  2038  				allErrs = append(allErrs, validation.NewInvalidError("ingress.ip", ingress.IP, "must be an IP address"))
  2039  			}
  2040  		}
  2041  		if len(ingress.Hostname) > 0 {
  2042  			if valid, errMsg := NameIsDNSSubdomain(ingress.Hostname, false); !valid {
  2043  				allErrs = append(allErrs, validation.NewInvalidError("ingress.hostname", ingress.Hostname, errMsg))
  2044  			}
  2045  			if isIP := (net.ParseIP(ingress.Hostname) != nil); isIP {
  2046  				allErrs = append(allErrs, validation.NewInvalidError("ingress.hostname", ingress.Hostname, "must be a DNS name, not an IP address"))
  2047  			}
  2048  		}
  2049  	}
  2050  	return allErrs
  2051  }