2014-07-01 20:01:39 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
2014-07-01 20:01:39 +00:00
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2014-08-29 22:48:41 +00:00
package validation
2014-07-01 20:01:39 +00:00
import (
2015-05-06 14:09:18 +00:00
"encoding/json"
2014-10-31 06:03:52 +00:00
"fmt"
2015-03-16 21:36:30 +00:00
"net"
2015-02-20 05:36:23 +00:00
"os"
2015-02-10 19:00:11 +00:00
"path"
2015-05-08 17:53:00 +00:00
"reflect"
2015-05-11 19:03:10 +00:00
"regexp"
2014-07-08 04:32:56 +00:00
"strings"
2014-07-01 20:01:39 +00:00
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/labels"
2015-11-10 06:28:45 +00:00
"k8s.io/kubernetes/pkg/util/intstr"
2015-09-09 17:45:01 +00:00
"k8s.io/kubernetes/pkg/util/sets"
2015-09-10 22:48:28 +00:00
"k8s.io/kubernetes/pkg/util/validation"
2014-12-12 05:39:56 +00:00
"github.com/golang/glog"
2014-07-01 20:01:39 +00:00
)
2015-10-06 22:58:46 +00:00
// TODO: delete this global variable when we enable the validation of common
// fields by default.
var RepairMalformedUpdates bool = true
2015-05-13 04:24:41 +00:00
const isNegativeErrorMsg string = ` must be non-negative `
2015-10-12 03:26:17 +00:00
const fieldImmutableErrorMsg string = ` field is immutable `
const cIdentifierErrorMsg string = ` must be a C identifier (matching regex ` + validation . CIdentifierFmt + ` ): e.g. "my_name" or "MyName" `
2015-10-13 21:27:56 +00:00
const isNotIntegerErrorMsg string = ` must be an integer `
2015-02-05 00:36:27 +00:00
2015-10-12 03:26:17 +00:00
func IntervalErrorMsg ( lo , hi int ) string {
2015-05-13 04:24:41 +00:00
return fmt . Sprintf ( ` must be greater than %d and less than %d ` , lo , hi )
2015-02-05 00:36:27 +00:00
}
2015-09-10 22:48:28 +00:00
var labelValueErrorMsg string = fmt . Sprintf ( ` must have at most %d characters, matching regex %s: e.g. "MyValue" or "" ` , validation . LabelValueMaxLength , validation . LabelValueFmt )
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 )
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 )
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 )
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 )
2015-10-12 03:26:17 +00:00
var pdPartitionErrorMsg string = IntervalErrorMsg ( 0 , 255 )
var PortRangeErrorMsg string = IntervalErrorMsg ( 0 , 65536 )
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 )
2015-02-05 00:36:27 +00:00
2015-10-21 22:22:47 +00:00
const totalAnnotationSizeLimitB int = 256 * ( 1 << 10 ) // 256 kB
2015-03-02 13:41:13 +00:00
2015-11-03 21:38:40 +00:00
func ValidateLabelName ( labelName , fieldName string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-10 22:48:28 +00:00
if ! validation . IsQualifiedName ( labelName ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , labelName , qualifiedNameErrorMsg ) )
2015-08-25 19:07:03 +00:00
}
return allErrs
}
2015-02-02 00:03:04 +00:00
// ValidateLabels validates that a set of labels are correctly defined.
2015-11-03 21:38:40 +00:00
func ValidateLabels ( labels map [ string ] string , field string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-27 15:08:02 +00:00
for k , v := range labels {
2015-08-25 19:07:03 +00:00
allErrs = append ( allErrs , ValidateLabelName ( k , field ) ... )
2015-09-10 22:48:28 +00:00
if ! validation . IsValidLabelValue ( v ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( field , v , labelValueErrorMsg ) )
2015-02-27 15:08:02 +00:00
}
2015-02-02 00:03:04 +00:00
}
return allErrs
}
// ValidateAnnotations validates that a set of annotations are correctly defined.
2015-11-03 21:38:40 +00:00
func ValidateAnnotations ( annotations map [ string ] string , field string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-27 15:08:02 +00:00
var totalSize int64
for k , v := range annotations {
2015-09-10 22:48:28 +00:00
if ! validation . IsQualifiedName ( strings . ToLower ( k ) ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( field , k , qualifiedNameErrorMsg ) )
2015-02-02 00:03:04 +00:00
}
2015-02-27 15:08:02 +00:00
totalSize += ( int64 ) ( len ( k ) ) + ( int64 ) ( len ( v ) )
}
2015-03-02 13:41:13 +00:00
if totalSize > ( int64 ) ( totalAnnotationSizeLimitB ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldTooLong ( field , "" , totalAnnotationSizeLimitB ) )
2015-02-02 00:03:04 +00:00
}
return allErrs
}
2015-01-27 23:55:54 +00:00
// ValidateNameFunc validates that the provided name is valid for a given resource type.
2015-01-27 23:56:38 +00:00
// Not all resources have the same validation rules for names. Prefix is true if the
// name will have a value appended to it.
type ValidateNameFunc func ( name string , prefix bool ) ( bool , string )
// maskTrailingDash replaces the final character of a string with a subdomain safe
// value if is a dash.
func maskTrailingDash ( name string ) string {
if strings . HasSuffix ( name , "-" ) {
return name [ : len ( name ) - 2 ] + "a"
}
return name
}
2015-01-27 23:55:54 +00:00
2015-01-28 04:50:01 +00:00
// ValidatePodName can be used to check whether the given pod name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidatePodName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-01-28 04:50:01 +00:00
}
// ValidateReplicationControllerName can be used to check whether the given replication
// controller name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateReplicationControllerName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-01-28 04:50:01 +00:00
}
// ValidateServiceName can be used to check whether the given service name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateServiceName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNS952Label ( name , prefix )
2015-01-28 04:50:01 +00:00
}
// ValidateNodeName can be used to check whether the given node name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateNodeName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-01-28 04:50:01 +00:00
}
2015-01-19 21:50:00 +00:00
// ValidateNamespaceName can be used to check whether the given namespace name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateNamespaceName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSLabel ( name , prefix )
2015-01-19 21:50:00 +00:00
}
2015-02-20 06:03:36 +00:00
// ValidateLimitRangeName can be used to check whether the given limit range name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateLimitRangeName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-02-20 06:03:36 +00:00
}
// ValidateResourceQuotaName can be used to check whether the given
// resource quota name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateResourceQuotaName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-02-20 06:03:36 +00:00
}
// ValidateSecretName can be used to check whether the given secret name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateSecretName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-02-20 06:03:36 +00:00
}
2015-04-27 22:53:28 +00:00
// ValidateServiceAccountName can be used to check whether the given service account name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateServiceAccountName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-04-27 22:53:28 +00:00
}
2015-03-15 06:03:46 +00:00
// ValidateEndpointsName can be used to check whether the given endpoints name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateEndpointsName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-03-15 06:03:46 +00:00
}
2015-06-09 12:53:30 +00:00
// NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain.
func NameIsDNSSubdomain ( name string , prefix bool ) ( bool , string ) {
2015-01-27 23:56:38 +00:00
if prefix {
name = maskTrailingDash ( name )
}
2015-09-10 22:48:28 +00:00
if validation . IsDNS1123Subdomain ( name ) {
2015-01-27 23:55:54 +00:00
return true , ""
}
2015-06-09 12:53:30 +00:00
return false , DNSSubdomainErrorMsg
2015-01-27 23:55:54 +00:00
}
2015-06-09 12:53:30 +00:00
// NameIsDNSLabel is a ValidateNameFunc for names that must be a DNS 1123 label.
func NameIsDNSLabel ( name string , prefix bool ) ( bool , string ) {
2015-05-12 22:13:03 +00:00
if prefix {
name = maskTrailingDash ( name )
}
2015-09-10 22:48:28 +00:00
if validation . IsDNS1123Label ( name ) {
2015-05-12 22:13:03 +00:00
return true , ""
}
2015-06-09 12:53:30 +00:00
return false , DNS1123LabelErrorMsg
2015-05-12 22:13:03 +00:00
}
2015-06-09 12:53:30 +00:00
// NameIsDNS952Label is a ValidateNameFunc for names that must be a DNS 952 label.
func NameIsDNS952Label ( name string , prefix bool ) ( bool , string ) {
2015-01-27 23:56:38 +00:00
if prefix {
name = maskTrailingDash ( name )
}
2015-09-10 22:48:28 +00:00
if validation . IsDNS952Label ( name ) {
2015-01-27 23:55:54 +00:00
return true , ""
}
2015-06-09 12:53:30 +00:00
return false , DNS952LabelErrorMsg
2015-01-27 23:55:54 +00:00
}
2015-08-25 19:07:03 +00:00
// Validates that given value is not negative.
2015-11-03 21:38:40 +00:00
func ValidatePositiveField ( value int64 , fieldName string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-08-25 19:07:03 +00:00
if value < 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , value , isNegativeErrorMsg ) )
2015-08-25 19:07:03 +00:00
}
return allErrs
}
2015-09-24 14:15:40 +00:00
// Validates that a Quantity is not negative
2015-11-03 21:38:40 +00:00
func ValidatePositiveQuantity ( value resource . Quantity , fieldName string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-24 14:15:40 +00:00
if value . Cmp ( resource . Quantity { } ) < 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , value . String ( ) , isNegativeErrorMsg ) )
2015-09-24 14:15:40 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func ValidateImmutableField ( new , old interface { } , fieldName string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-10-12 03:26:17 +00:00
if ! api . Semantic . DeepEqual ( old , new ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , new , fieldImmutableErrorMsg ) )
2015-10-12 03:26:17 +00:00
}
return allErrs
}
2015-01-27 23:56:38 +00:00
// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already
// been performed.
2015-11-03 03:00:01 +00:00
// It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before.
2015-10-06 22:58:46 +00:00
// TODO: Remove calls to this method scattered in validations of specific resources, e.g., ValidatePodUpdate.
2015-11-03 21:38:40 +00:00
func ValidateObjectMeta ( meta * api . ObjectMeta , requiresNamespace bool , nameFn ValidateNameFunc ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-27 23:56:38 +00:00
if len ( meta . GenerateName ) != 0 {
if ok , qualifier := nameFn ( meta . GenerateName , true ) ; ! ok {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "generateName" , meta . GenerateName , qualifier ) )
2015-01-27 23:56:38 +00:00
}
}
2015-06-09 22:19:04 +00:00
// If the generated name validates, but the calculated value does not, it's a problem with generation, and we
2015-01-27 23:56:38 +00:00
// report it here. This may confuse users, but indicates a programming bug and still must be validated.
2015-08-08 21:29:57 +00:00
// If there are multiple fields out of which one is required then add a or as a separator
2015-01-27 23:55:54 +00:00
if len ( meta . Name ) == 0 {
2015-11-03 21:17:51 +00:00
requiredErr := validation . NewFieldRequired ( "name" )
2015-08-12 15:26:23 +00:00
requiredErr . Detail = "name or generateName is required"
allErrs = append ( allErrs , requiredErr )
2015-01-27 23:55:54 +00:00
} else {
2015-01-27 23:56:38 +00:00
if ok , qualifier := nameFn ( meta . Name , false ) ; ! ok {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "name" , meta . Name , qualifier ) )
2015-01-27 23:55:54 +00:00
}
}
2015-08-25 19:07:03 +00:00
allErrs = append ( allErrs , ValidatePositiveField ( meta . Generation , "generation" ) ... )
2015-01-27 23:55:54 +00:00
if requiresNamespace {
if len ( meta . Namespace ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "namespace" ) )
2015-05-12 22:13:03 +00:00
} else if ok , _ := ValidateNamespaceName ( meta . Namespace , false ) ; ! ok {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "namespace" , meta . Namespace , DNS1123LabelErrorMsg ) )
2015-01-27 23:55:54 +00:00
}
} else {
if len ( meta . Namespace ) != 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "namespace" , meta . Namespace , "namespace is not allowed on this type" ) )
2015-01-27 23:55:54 +00:00
}
}
allErrs = append ( allErrs , ValidateLabels ( meta . Labels , "labels" ) ... )
2015-02-02 00:03:04 +00:00
allErrs = append ( allErrs , ValidateAnnotations ( meta . Annotations , "annotations" ) ... )
2015-01-27 23:55:54 +00:00
return allErrs
}
// ValidateObjectMetaUpdate validates an object's metadata when updated
2015-11-03 21:38:40 +00:00
func ValidateObjectMetaUpdate ( new , old * api . ObjectMeta ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-27 23:55:54 +00:00
2015-10-06 22:58:46 +00:00
if ! RepairMalformedUpdates && new . UID != old . UID {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "uid" , new . UID , "field is immutable" ) )
2015-08-19 23:59:43 +00:00
}
2015-10-06 22:58:46 +00:00
// in the event it is left empty, set it, to allow clients more flexibility
// TODO: remove the following code that repairs the update request when we retire the clients that modify the immutable fields.
// Please do not copy this pattern elsewhere; validation functions should not be modifying the objects they are passed!
if RepairMalformedUpdates {
if len ( new . UID ) == 0 {
new . UID = old . UID
}
// ignore changes to timestamp
if old . CreationTimestamp . IsZero ( ) {
old . CreationTimestamp = new . CreationTimestamp
} else {
new . CreationTimestamp = old . CreationTimestamp
}
// an object can never remove a deletion timestamp or clear/change grace period seconds
if ! old . DeletionTimestamp . IsZero ( ) {
new . DeletionTimestamp = old . DeletionTimestamp
}
if old . DeletionGracePeriodSeconds != nil && new . DeletionGracePeriodSeconds == nil {
new . DeletionGracePeriodSeconds = old . DeletionGracePeriodSeconds
}
2015-08-19 23:59:43 +00:00
}
2015-10-06 22:58:46 +00:00
// TODO: needs to check if new==nil && old !=nil after the repair logic is removed.
2015-08-19 23:59:43 +00:00
if new . DeletionGracePeriodSeconds != nil && old . DeletionGracePeriodSeconds != nil && * new . DeletionGracePeriodSeconds != * old . DeletionGracePeriodSeconds {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "deletionGracePeriodSeconds" , new . DeletionGracePeriodSeconds , "field is immutable; may only be changed via deletion" ) )
2015-08-19 23:59:43 +00:00
}
2015-01-27 23:55:54 +00:00
2015-03-20 00:51:07 +00:00
// Reject updates that don't specify a resource version
2015-06-08 22:06:50 +00:00
if new . ResourceVersion == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "resourceVersion" , new . ResourceVersion , "resourceVersion must be specified for an update" ) )
2015-03-20 00:51:07 +00:00
}
2015-11-04 07:47:11 +00:00
allErrs = append ( allErrs , ValidateImmutableField ( new . Name , old . Name , "name" ) ... )
allErrs = append ( allErrs , ValidateImmutableField ( new . Namespace , old . Namespace , "namespace" ) ... )
allErrs = append ( allErrs , ValidateImmutableField ( new . UID , old . UID , "uid" ) ... )
allErrs = append ( allErrs , ValidateImmutableField ( new . CreationTimestamp , old . CreationTimestamp , "creationTimestamp" ) ... )
2015-01-27 23:55:54 +00:00
2015-06-08 22:06:50 +00:00
allErrs = append ( allErrs , ValidateLabels ( new . Labels , "labels" ) ... )
allErrs = append ( allErrs , ValidateAnnotations ( new . Annotations , "annotations" ) ... )
2015-01-27 23:55:54 +00:00
return allErrs
2014-10-31 06:03:52 +00:00
}
2015-11-03 21:38:40 +00:00
func validateVolumes ( volumes [ ] api . Volume ) ( sets . String , validation . ErrorList ) {
allErrs := validation . ErrorList { }
2014-07-08 06:20:30 +00:00
2015-09-09 17:45:01 +00:00
allNames := sets . String { }
2015-01-26 17:52:50 +00:00
for i , vol := range volumes {
2015-03-03 22:48:55 +00:00
el := validateSource ( & vol . VolumeSource ) . Prefix ( "source" )
2014-08-20 02:57:48 +00:00
if len ( vol . Name ) == 0 {
2015-11-03 21:17:51 +00:00
el = append ( el , validation . NewFieldRequired ( "name" ) )
2015-09-10 22:48:28 +00:00
} else if ! validation . IsDNS1123Label ( vol . Name ) {
2015-11-03 21:17:51 +00:00
el = append ( el , validation . NewFieldInvalid ( "name" , vol . Name , DNS1123LabelErrorMsg ) )
2014-07-08 06:20:30 +00:00
} else if allNames . Has ( vol . Name ) {
2015-11-03 21:17:51 +00:00
el = append ( el , validation . NewFieldDuplicate ( "name" , vol . Name ) )
2014-07-16 19:32:59 +00:00
}
2014-08-14 20:46:22 +00:00
if len ( el ) == 0 {
2014-07-08 06:20:30 +00:00
allNames . Insert ( vol . Name )
2014-07-16 19:32:59 +00:00
} else {
2014-08-20 03:54:20 +00:00
allErrs = append ( allErrs , el . PrefixIndex ( i ) ... )
2014-07-01 21:40:36 +00:00
}
}
2014-07-08 06:20:30 +00:00
return allNames , allErrs
2014-07-01 21:40:36 +00:00
}
2015-11-03 21:38:40 +00:00
func validateSource ( source * api . VolumeSource ) validation . ErrorList {
2014-07-16 19:32:59 +00:00
numVolumes := 0
2015-11-03 21:38:40 +00:00
allErrs := validation . ErrorList { }
2015-01-20 23:56:44 +00:00
if source . HostPath != nil {
2014-07-16 19:32:59 +00:00
numVolumes ++
2015-02-20 06:27:27 +00:00
allErrs = append ( allErrs , validateHostPathVolumeSource ( source . HostPath ) . Prefix ( "hostPath" ) ... )
2014-07-16 19:32:59 +00:00
}
2014-10-01 20:35:21 +00:00
if source . EmptyDir != nil {
2014-07-16 19:32:59 +00:00
numVolumes ++
2014-11-24 04:03:11 +00:00
// EmptyDirs have nothing to validate
}
if source . GitRepo != nil {
numVolumes ++
2015-02-20 06:27:27 +00:00
allErrs = append ( allErrs , validateGitRepoVolumeSource ( source . GitRepo ) . Prefix ( "gitRepo" ) ... )
2014-07-16 19:32:59 +00:00
}
2014-08-05 17:58:43 +00:00
if source . GCEPersistentDisk != nil {
numVolumes ++
2015-02-20 06:27:27 +00:00
allErrs = append ( allErrs , validateGCEPersistentDiskVolumeSource ( source . GCEPersistentDisk ) . Prefix ( "persistentDisk" ) ... )
2014-08-05 17:58:43 +00:00
}
2015-04-07 21:16:36 +00:00
if source . AWSElasticBlockStore != nil {
2015-03-06 14:26:39 +00:00
numVolumes ++
2015-04-07 21:16:36 +00:00
allErrs = append ( allErrs , validateAWSElasticBlockStoreVolumeSource ( source . AWSElasticBlockStore ) . Prefix ( "awsElasticBlockStore" ) ... )
2015-03-06 14:26:39 +00:00
}
2015-02-18 01:24:50 +00:00
if source . Secret != nil {
numVolumes ++
2015-02-20 06:27:27 +00:00
allErrs = append ( allErrs , validateSecretVolumeSource ( source . Secret ) . Prefix ( "secret" ) ... )
2015-02-18 01:24:50 +00:00
}
2015-02-10 19:00:11 +00:00
if source . NFS != nil {
numVolumes ++
allErrs = append ( allErrs , validateNFS ( source . NFS ) . Prefix ( "nfs" ) ... )
}
2015-03-13 21:31:13 +00:00
if source . ISCSI != nil {
numVolumes ++
allErrs = append ( allErrs , validateISCSIVolumeSource ( source . ISCSI ) . Prefix ( "iscsi" ) ... )
}
2015-03-26 18:53:21 +00:00
if source . Glusterfs != nil {
numVolumes ++
allErrs = append ( allErrs , validateGlusterfs ( source . Glusterfs ) . Prefix ( "glusterfs" ) ... )
}
2015-09-25 19:22:23 +00:00
if source . Flocker != nil {
numVolumes ++
allErrs = append ( allErrs , validateFlocker ( source . Flocker ) . Prefix ( "flocker" ) ... )
}
2015-06-10 20:57:33 +00:00
if source . PersistentVolumeClaim != nil {
2015-04-18 11:16:07 +00:00
numVolumes ++
2015-06-10 20:57:33 +00:00
allErrs = append ( allErrs , validatePersistentClaimVolumeSource ( source . PersistentVolumeClaim ) . Prefix ( "persistentVolumeClaim" ) ... )
2015-04-18 11:16:07 +00:00
}
2015-04-07 17:22:23 +00:00
if source . RBD != nil {
numVolumes ++
allErrs = append ( allErrs , validateRBD ( source . RBD ) . Prefix ( "rbd" ) ... )
}
2015-04-10 16:54:01 +00:00
if source . Cinder != nil {
numVolumes ++
allErrs = append ( allErrs , validateCinderVolumeSource ( source . Cinder ) . Prefix ( "cinder" ) ... )
}
2015-04-09 18:05:24 +00:00
if source . CephFS != nil {
numVolumes ++
allErrs = append ( allErrs , validateCephFS ( source . CephFS ) . Prefix ( "cephfs" ) ... )
}
2015-02-20 05:36:23 +00:00
if source . DownwardAPI != nil {
numVolumes ++
allErrs = append ( allErrs , validateDownwardAPIVolumeSource ( source . DownwardAPI ) . Prefix ( "downwardApi" ) ... )
}
2015-08-11 15:19:29 +00:00
if source . FC != nil {
numVolumes ++
allErrs = append ( allErrs , validateFCVolumeSource ( source . FC ) . Prefix ( "fc" ) ... )
}
2015-01-26 17:52:50 +00:00
if numVolumes != 1 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "" , source , "exactly 1 volume type is required" ) )
2014-07-16 19:32:59 +00:00
}
2015-04-07 17:22:23 +00:00
2014-07-16 19:32:59 +00:00
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateHostPathVolumeSource ( hostPath * api . HostPathVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-16 14:31:17 +00:00
if hostPath . Path == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "path" ) )
2014-07-15 01:39:30 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateGitRepoVolumeSource ( gitRepo * api . GitRepoVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-11-24 04:03:11 +00:00
if gitRepo . Repository == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "repository" ) )
2014-11-24 04:03:11 +00:00
}
return allErrs
}
2014-07-08 04:32:56 +00:00
2015-11-03 21:38:40 +00:00
func validateISCSIVolumeSource ( iscsi * api . ISCSIVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-13 21:31:13 +00:00
if iscsi . TargetPortal == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "targetPortal" ) )
2015-03-13 21:31:13 +00:00
}
if iscsi . IQN == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "iqn" ) )
2015-03-13 21:31:13 +00:00
}
if iscsi . FSType == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "fsType" ) )
2015-03-13 21:31:13 +00:00
}
if iscsi . Lun < 0 || iscsi . Lun > 255 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "lun" , iscsi . Lun , "" ) )
2015-03-13 21:31:13 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateFCVolumeSource ( fc * api . FCVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-08-11 15:19:29 +00:00
if len ( fc . TargetWWNs ) < 1 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "targetWWNs" ) )
2015-08-11 15:19:29 +00:00
}
if fc . FSType == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "fsType" ) )
2015-08-11 15:19:29 +00:00
}
if fc . Lun == nil {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "lun" ) )
2015-08-11 15:19:29 +00:00
} else {
if * fc . Lun < 0 || * fc . Lun > 255 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "lun" , fc . Lun , "" ) )
2015-08-11 15:19:29 +00:00
}
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateGCEPersistentDiskVolumeSource ( PD * api . GCEPersistentDiskVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-08-05 17:58:43 +00:00
if PD . PDName == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "pdName" ) )
2014-08-05 17:58:43 +00:00
}
if PD . FSType == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "fsType" ) )
2014-08-05 17:58:43 +00:00
}
if PD . Partition < 0 || PD . Partition > 255 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "partition" , PD . Partition , pdPartitionErrorMsg ) )
2014-08-05 17:58:43 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateAWSElasticBlockStoreVolumeSource ( PD * api . AWSElasticBlockStoreVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-09 13:34:16 +00:00
if PD . VolumeID == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "volumeID" ) )
2015-03-06 14:26:39 +00:00
}
if PD . FSType == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "fsType" ) )
2015-03-06 14:26:39 +00:00
}
if PD . Partition < 0 || PD . Partition > 255 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "partition" , PD . Partition , pdPartitionErrorMsg ) )
2015-03-06 14:26:39 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateSecretVolumeSource ( secretSource * api . SecretVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-24 17:17:14 +00:00
if secretSource . SecretName == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "secretName" ) )
2015-02-18 01:24:50 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validatePersistentClaimVolumeSource ( claim * api . PersistentVolumeClaimVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-18 11:16:07 +00:00
if claim . ClaimName == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "claimName" ) )
2015-04-18 11:16:07 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateNFS ( nfs * api . NFSVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-10 19:00:11 +00:00
if nfs . Server == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "server" ) )
2015-02-10 19:00:11 +00:00
}
if nfs . Path == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "path" ) )
2015-02-10 19:00:11 +00:00
}
if ! path . IsAbs ( nfs . Path ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "path" , nfs . Path , "must be an absolute path" ) )
2015-02-10 19:00:11 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateGlusterfs ( glusterfs * api . GlusterfsVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-26 18:53:21 +00:00
if glusterfs . EndpointsName == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "endpoints" ) )
2015-03-26 18:53:21 +00:00
}
if glusterfs . Path == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "path" ) )
2015-03-26 18:53:21 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateFlocker ( flocker * api . FlockerVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-25 19:22:23 +00:00
if flocker . DatasetName == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "datasetName" ) )
2015-09-25 19:22:23 +00:00
}
if strings . Contains ( flocker . DatasetName , "/" ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "datasetName" , flocker . DatasetName , "must not contain '/'" ) )
2015-09-25 19:22:23 +00:00
}
return allErrs
}
2015-09-09 17:45:01 +00:00
var validDownwardAPIFieldPathExpressions = sets . NewString ( "metadata.name" , "metadata.namespace" , "metadata.labels" , "metadata.annotations" )
2015-02-20 05:36:23 +00:00
2015-11-03 21:38:40 +00:00
func validateDownwardAPIVolumeSource ( downwardAPIVolume * api . DownwardAPIVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-20 05:36:23 +00:00
for _ , downwardAPIVolumeFile := range downwardAPIVolume . Items {
if len ( downwardAPIVolumeFile . Path ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "path" ) )
2015-02-20 05:36:23 +00:00
}
if path . IsAbs ( downwardAPIVolumeFile . Path ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldForbidden ( "path" , "must not be an absolute path" ) )
2015-02-20 05:36:23 +00:00
}
items := strings . Split ( downwardAPIVolumeFile . Path , string ( os . PathSeparator ) )
for _ , item := range items {
if item == ".." {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "path" , downwardAPIVolumeFile . Path , "must not contain \"..\"." ) )
2015-02-20 05:36:23 +00:00
}
}
if strings . HasPrefix ( items [ 0 ] , ".." ) && len ( items [ 0 ] ) > 2 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "path" , downwardAPIVolumeFile . Path , "must not start with \"..\"." ) )
2015-02-20 05:36:23 +00:00
}
allErrs = append ( allErrs , validateObjectFieldSelector ( & downwardAPIVolumeFile . FieldRef , & validDownwardAPIFieldPathExpressions ) . Prefix ( "FieldRef" ) ... )
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateRBD ( rbd * api . RBDVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-07 17:22:23 +00:00
if len ( rbd . CephMonitors ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "monitors" ) )
2015-04-07 17:22:23 +00:00
}
if rbd . RBDImage == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "image" ) )
2015-04-07 17:22:23 +00:00
}
if rbd . FSType == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "fsType" ) )
2015-04-07 17:22:23 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateCinderVolumeSource ( cd * api . CinderVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-10 16:54:01 +00:00
if cd . VolumeID == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "volumeID" ) )
2015-04-10 16:54:01 +00:00
}
if cd . FSType == "" || ( cd . FSType != "ext3" && cd . FSType != "ext4" ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "fsType required and should be of type ext3 or ext4" ) )
2015-04-10 16:54:01 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateCephFS ( cephfs * api . CephFSVolumeSource ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-09 18:05:24 +00:00
if len ( cephfs . Monitors ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "monitors" ) )
2015-04-09 18:05:24 +00:00
}
return allErrs
}
2015-03-23 18:18:11 +00:00
func ValidatePersistentVolumeName ( name string , prefix bool ) ( bool , string ) {
2015-06-09 12:53:30 +00:00
return NameIsDNSSubdomain ( name , prefix )
2015-03-23 18:18:11 +00:00
}
2015-11-03 21:38:40 +00:00
func ValidatePersistentVolume ( pv * api . PersistentVolume ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-26 19:50:36 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & pv . ObjectMeta , false , ValidatePersistentVolumeName ) . Prefix ( "metadata" ) ... )
2015-03-23 18:18:11 +00:00
2015-05-13 00:44:29 +00:00
if len ( pv . Spec . AccessModes ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "persistentVolume.AccessModes" ) )
2015-05-13 00:44:29 +00:00
}
2015-07-24 19:55:54 +00:00
for _ , mode := range pv . Spec . AccessModes {
if mode != api . ReadWriteOnce && mode != api . ReadOnlyMany && mode != api . ReadWriteMany {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "persistentVolume.Spec.AccessModes" , mode , fmt . Sprintf ( "only %s, %s, and %s are valid" , api . ReadWriteOnce , api . ReadOnlyMany , api . ReadWriteMany ) ) )
2015-07-24 19:55:54 +00:00
}
}
2015-03-23 18:18:11 +00:00
if len ( pv . Spec . Capacity ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "persistentVolume.Capacity" ) )
2015-03-23 18:18:11 +00:00
}
if _ , ok := pv . Spec . Capacity [ api . ResourceStorage ] ; ! ok || len ( pv . Spec . Capacity ) > 1 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "" , pv . Spec . Capacity , fmt . Sprintf ( "only %s is expected" , api . ResourceStorage ) ) )
2015-03-23 18:18:11 +00:00
}
2015-05-13 00:44:29 +00:00
for _ , qty := range pv . Spec . Capacity {
allErrs = append ( allErrs , validateBasicResource ( qty ) ... )
}
2015-03-23 18:18:11 +00:00
numVolumes := 0
if pv . Spec . HostPath != nil {
numVolumes ++
allErrs = append ( allErrs , validateHostPathVolumeSource ( pv . Spec . HostPath ) . Prefix ( "hostPath" ) ... )
}
if pv . Spec . GCEPersistentDisk != nil {
numVolumes ++
allErrs = append ( allErrs , validateGCEPersistentDiskVolumeSource ( pv . Spec . GCEPersistentDisk ) . Prefix ( "persistentDisk" ) ... )
}
2015-04-07 21:16:36 +00:00
if pv . Spec . AWSElasticBlockStore != nil {
2015-03-06 14:26:39 +00:00
numVolumes ++
2015-04-07 21:16:36 +00:00
allErrs = append ( allErrs , validateAWSElasticBlockStoreVolumeSource ( pv . Spec . AWSElasticBlockStore ) . Prefix ( "awsElasticBlockStore" ) ... )
2015-03-06 14:26:39 +00:00
}
2015-04-18 13:31:24 +00:00
if pv . Spec . Glusterfs != nil {
numVolumes ++
allErrs = append ( allErrs , validateGlusterfs ( pv . Spec . Glusterfs ) . Prefix ( "glusterfs" ) ... )
}
2015-09-25 19:22:23 +00:00
if pv . Spec . Flocker != nil {
numVolumes ++
allErrs = append ( allErrs , validateFlocker ( pv . Spec . Flocker ) . Prefix ( "flocker" ) ... )
}
2015-04-30 16:16:51 +00:00
if pv . Spec . NFS != nil {
numVolumes ++
allErrs = append ( allErrs , validateNFS ( pv . Spec . NFS ) . Prefix ( "nfs" ) ... )
}
2015-04-07 17:22:23 +00:00
if pv . Spec . RBD != nil {
numVolumes ++
allErrs = append ( allErrs , validateRBD ( pv . Spec . RBD ) . Prefix ( "rbd" ) ... )
}
2015-04-09 18:05:24 +00:00
if pv . Spec . CephFS != nil {
numVolumes ++
allErrs = append ( allErrs , validateCephFS ( pv . Spec . CephFS ) . Prefix ( "cephfs" ) ... )
}
2015-05-12 20:40:31 +00:00
if pv . Spec . ISCSI != nil {
numVolumes ++
allErrs = append ( allErrs , validateISCSIVolumeSource ( pv . Spec . ISCSI ) . Prefix ( "iscsi" ) ... )
}
2015-04-10 16:54:01 +00:00
if pv . Spec . Cinder != nil {
numVolumes ++
allErrs = append ( allErrs , validateCinderVolumeSource ( pv . Spec . Cinder ) . Prefix ( "cinder" ) ... )
}
2015-08-11 15:19:29 +00:00
if pv . Spec . FC != nil {
numVolumes ++
allErrs = append ( allErrs , validateFCVolumeSource ( pv . Spec . FC ) . Prefix ( "fc" ) ... )
}
2015-03-23 18:18:11 +00:00
if numVolumes != 1 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "" , pv . Spec . PersistentVolumeSource , "exactly 1 volume type is required" ) )
2015-03-23 18:18:11 +00:00
}
return allErrs
}
2015-03-26 19:50:36 +00:00
// ValidatePersistentVolumeUpdate tests to see if the update is legal for an end user to make.
// newPv is updated with fields that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidatePersistentVolumeUpdate ( newPv , oldPv * api . PersistentVolume ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-26 19:50:36 +00:00
allErrs = ValidatePersistentVolume ( newPv )
newPv . Status = oldPv . Status
return allErrs
}
// ValidatePersistentVolumeStatusUpdate tests to see if the status update is legal for an end user to make.
// newPv is updated with fields that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidatePersistentVolumeStatusUpdate ( newPv , oldPv * api . PersistentVolume ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newPv . ObjectMeta , & oldPv . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-03-26 19:50:36 +00:00
if newPv . ResourceVersion == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "resourceVersion" ) )
2015-03-26 19:50:36 +00:00
}
newPv . Spec = oldPv . Spec
return allErrs
}
2015-11-03 21:38:40 +00:00
func ValidatePersistentVolumeClaim ( pvc * api . PersistentVolumeClaim ) validation . ErrorList {
2015-03-23 18:18:11 +00:00
allErrs := ValidateObjectMeta ( & pvc . ObjectMeta , true , ValidatePersistentVolumeName )
if len ( pvc . Spec . AccessModes ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "persistentVolumeClaim.Spec.AccessModes" , pvc . Spec . AccessModes , "at least 1 PersistentVolumeAccessMode is required" ) )
2015-03-23 18:18:11 +00:00
}
2015-07-24 19:55:54 +00:00
for _ , mode := range pvc . Spec . AccessModes {
if mode != api . ReadWriteOnce && mode != api . ReadOnlyMany && mode != api . ReadWriteMany {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "persistentVolumeClaim.Spec.AccessModes" , mode , fmt . Sprintf ( "only %s, %s, and %s are valid" , api . ReadWriteOnce , api . ReadOnlyMany , api . ReadWriteMany ) ) )
2015-07-24 19:55:54 +00:00
}
}
2015-03-31 15:37:09 +00:00
if _ , ok := pvc . Spec . Resources . Requests [ api . ResourceStorage ] ; ! ok {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "persistentVolumeClaim.Spec.Resources.Requests" , pvc . Spec . Resources . Requests , "No Storage size specified" ) )
2015-03-23 18:18:11 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func ValidatePersistentVolumeClaimUpdate ( newPvc , oldPvc * api . PersistentVolumeClaim ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-26 19:50:36 +00:00
allErrs = ValidatePersistentVolumeClaim ( newPvc )
newPvc . Status = oldPvc . Status
return allErrs
}
2015-11-03 21:38:40 +00:00
func ValidatePersistentVolumeClaimStatusUpdate ( newPvc , oldPvc * api . PersistentVolumeClaim ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newPvc . ObjectMeta , & oldPvc . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-03-26 19:50:36 +00:00
if newPvc . ResourceVersion == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "resourceVersion" ) )
2015-03-26 19:50:36 +00:00
}
2015-05-13 00:44:29 +00:00
if len ( newPvc . Spec . AccessModes ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "persistentVolume.AccessModes" ) )
2015-05-13 00:44:29 +00:00
}
for _ , qty := range newPvc . Status . Capacity {
allErrs = append ( allErrs , validateBasicResource ( qty ) ... )
}
2015-03-26 19:50:36 +00:00
newPvc . Spec = oldPvc . Spec
return allErrs
}
2015-09-09 17:45:01 +00:00
var supportedPortProtocols = sets . NewString ( string ( api . ProtocolTCP ) , string ( api . ProtocolUDP ) )
2014-11-24 04:03:11 +00:00
2015-11-03 21:38:40 +00:00
func validatePorts ( ports [ ] api . ContainerPort ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-07-08 06:20:30 +00:00
2015-09-09 17:45:01 +00:00
allNames := sets . String { }
2015-01-26 17:52:50 +00:00
for i , port := range ports {
2015-11-03 21:38:40 +00:00
pErrs := validation . ErrorList { }
2014-07-08 04:32:56 +00:00
if len ( port . Name ) > 0 {
2015-09-10 22:48:28 +00:00
if ! validation . IsValidPortName ( port . Name ) {
2015-11-03 21:17:51 +00:00
pErrs = append ( pErrs , validation . NewFieldInvalid ( "name" , port . Name , PortNameErrorMsg ) )
2014-07-08 06:20:30 +00:00
} else if allNames . Has ( port . Name ) {
2015-11-03 21:17:51 +00:00
pErrs = append ( pErrs , validation . NewFieldDuplicate ( "name" , port . Name ) )
2014-07-08 06:20:30 +00:00
} else {
allNames . Insert ( port . Name )
2014-07-08 04:32:56 +00:00
}
}
2014-08-20 02:57:48 +00:00
if port . ContainerPort == 0 {
2015-11-03 21:17:51 +00:00
pErrs = append ( pErrs , validation . NewFieldInvalid ( "containerPort" , port . ContainerPort , PortRangeErrorMsg ) )
2015-09-10 22:48:28 +00:00
} else if ! validation . IsValidPortNum ( port . ContainerPort ) {
2015-11-03 21:17:51 +00:00
pErrs = append ( pErrs , validation . NewFieldInvalid ( "containerPort" , port . ContainerPort , PortRangeErrorMsg ) )
2014-07-08 04:32:56 +00:00
}
2015-09-10 22:48:28 +00:00
if port . HostPort != 0 && ! validation . IsValidPortNum ( port . HostPort ) {
2015-11-03 21:17:51 +00:00
pErrs = append ( pErrs , validation . NewFieldInvalid ( "hostPort" , port . HostPort , PortRangeErrorMsg ) )
2014-07-08 04:32:56 +00:00
}
if len ( port . Protocol ) == 0 {
2015-11-03 21:17:51 +00:00
pErrs = append ( pErrs , validation . NewFieldRequired ( "protocol" ) )
2015-06-17 00:28:11 +00:00
} else if ! supportedPortProtocols . Has ( string ( port . Protocol ) ) {
2015-11-03 21:17:51 +00:00
pErrs = append ( pErrs , validation . NewFieldValueNotSupported ( "protocol" , port . Protocol , supportedPortProtocols . List ( ) ) )
2014-07-08 04:32:56 +00:00
}
2014-08-20 03:54:20 +00:00
allErrs = append ( allErrs , pErrs . PrefixIndex ( i ) ... )
2014-07-08 04:32:56 +00:00
}
2014-07-08 06:20:30 +00:00
return allErrs
2014-07-08 04:32:56 +00:00
}
2015-11-03 21:38:40 +00:00
func validateEnv ( vars [ ] api . EnvVar ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-07-08 06:20:30 +00:00
2015-01-26 17:52:50 +00:00
for i , ev := range vars {
2015-11-03 21:38:40 +00:00
vErrs := validation . ErrorList { }
2014-07-01 22:56:30 +00:00
if len ( ev . Name ) == 0 {
2015-11-03 21:17:51 +00:00
vErrs = append ( vErrs , validation . NewFieldRequired ( "name" ) )
2015-09-10 22:48:28 +00:00
} else if ! validation . IsCIdentifier ( ev . Name ) {
2015-11-03 21:17:51 +00:00
vErrs = append ( vErrs , validation . NewFieldInvalid ( "name" , ev . Name , cIdentifierErrorMsg ) )
2014-07-01 22:56:30 +00:00
}
2015-04-23 20:57:30 +00:00
vErrs = append ( vErrs , validateEnvVarValueFrom ( ev ) . Prefix ( "valueFrom" ) ... )
2014-08-20 03:54:20 +00:00
allErrs = append ( allErrs , vErrs . PrefixIndex ( i ) ... )
2014-07-01 22:56:30 +00:00
}
2014-07-08 06:20:30 +00:00
return allErrs
2014-07-01 22:56:30 +00:00
}
2015-09-09 17:45:01 +00:00
var validFieldPathExpressionsEnv = sets . NewString ( "metadata.name" , "metadata.namespace" , "status.podIP" )
2015-02-20 05:36:23 +00:00
2015-11-03 21:38:40 +00:00
func validateEnvVarValueFrom ( ev api . EnvVar ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-23 20:57:30 +00:00
if ev . ValueFrom == nil {
return allErrs
}
numSources := 0
switch {
2015-05-04 17:31:36 +00:00
case ev . ValueFrom . FieldRef != nil :
2015-04-23 20:57:30 +00:00
numSources ++
2015-02-20 05:36:23 +00:00
allErrs = append ( allErrs , validateObjectFieldSelector ( ev . ValueFrom . FieldRef , & validFieldPathExpressionsEnv ) . Prefix ( "fieldRef" ) ... )
2015-04-23 20:57:30 +00:00
}
if ev . Value != "" && numSources != 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "" , "" , "sources cannot be specified when value is not empty" ) )
2015-04-23 20:57:30 +00:00
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateObjectFieldSelector ( fs * api . ObjectFieldSelector , expressions * sets . String ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-23 20:57:30 +00:00
if fs . APIVersion == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "apiVersion" ) )
2015-04-23 20:57:30 +00:00
} else if fs . FieldPath == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "fieldPath" ) )
2015-04-23 20:57:30 +00:00
} else {
internalFieldPath , _ , err := api . Scheme . ConvertFieldLabel ( fs . APIVersion , "Pod" , fs . FieldPath , "" )
if err != nil {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "fieldPath" , fs . FieldPath , "error converting fieldPath" ) )
2015-02-20 05:36:23 +00:00
} else if ! expressions . Has ( internalFieldPath ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldValueNotSupported ( "fieldPath" , internalFieldPath , expressions . List ( ) ) )
2015-04-23 20:57:30 +00:00
}
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateVolumeMounts ( mounts [ ] api . VolumeMount , volumes sets . String ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-07-08 06:20:30 +00:00
2015-01-26 17:52:50 +00:00
for i , mnt := range mounts {
2015-11-03 21:38:40 +00:00
mErrs := validation . ErrorList { }
2014-07-05 02:46:56 +00:00
if len ( mnt . Name ) == 0 {
2015-11-03 21:17:51 +00:00
mErrs = append ( mErrs , validation . NewFieldRequired ( "name" ) )
2014-07-08 06:20:30 +00:00
} else if ! volumes . Has ( mnt . Name ) {
2015-11-03 21:17:51 +00:00
mErrs = append ( mErrs , validation . NewFieldNotFound ( "name" , mnt . Name ) )
2014-07-05 02:46:56 +00:00
}
if len ( mnt . MountPath ) == 0 {
2015-11-03 21:17:51 +00:00
mErrs = append ( mErrs , validation . NewFieldRequired ( "mountPath" ) )
2014-07-15 01:39:30 +00:00
}
2014-08-20 03:54:20 +00:00
allErrs = append ( allErrs , mErrs . PrefixIndex ( i ) ... )
2014-07-05 02:46:56 +00:00
}
2014-07-08 06:20:30 +00:00
return allErrs
2014-07-05 02:46:56 +00:00
}
2015-11-03 21:38:40 +00:00
func validateProbe ( probe * api . Probe ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-15 07:02:07 +00:00
if probe == nil {
return allErrs
}
allErrs = append ( allErrs , validateHandler ( & probe . Handler ) ... )
2015-11-05 23:38:46 +00:00
allErrs = append ( allErrs , ValidatePositiveField ( probe . InitialDelaySeconds , "initialDelaySeconds" ) ... )
allErrs = append ( allErrs , ValidatePositiveField ( probe . TimeoutSeconds , "timeoutSeconds" ) ... )
allErrs = append ( allErrs , ValidatePositiveField ( int64 ( probe . PeriodSeconds ) , "periodSeconds" ) ... )
allErrs = append ( allErrs , ValidatePositiveField ( int64 ( probe . SuccessThreshold ) , "successThreshold" ) ... )
allErrs = append ( allErrs , ValidatePositiveField ( int64 ( probe . FailureThreshold ) , "failureThreshold" ) ... )
2015-02-15 07:02:07 +00:00
return allErrs
}
2015-05-19 17:17:53 +00:00
// AccumulateUniqueHostPorts extracts each HostPort of each Container,
2014-07-08 04:32:56 +00:00
// accumulating the results and returning an error if any ports conflict.
2015-11-03 21:38:40 +00:00
func AccumulateUniqueHostPorts ( containers [ ] api . Container , accumulator * sets . String ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-07-08 06:20:30 +00:00
2015-01-26 17:52:50 +00:00
for ci , ctr := range containers {
2015-11-03 21:38:40 +00:00
cErrs := validation . ErrorList { }
2014-07-08 04:32:56 +00:00
for pi := range ctr . Ports {
2015-05-19 05:18:40 +00:00
port := ctr . Ports [ pi ] . HostPort
2014-08-19 22:18:49 +00:00
if port == 0 {
continue
}
2015-05-19 05:18:40 +00:00
str := fmt . Sprintf ( "%d/%s" , port , ctr . Ports [ pi ] . Protocol )
2015-05-19 17:17:53 +00:00
if accumulator . Has ( str ) {
2015-11-03 21:17:51 +00:00
cErrs = append ( cErrs , validation . NewFieldDuplicate ( "port" , str ) )
2014-07-08 06:20:30 +00:00
} else {
2015-05-19 17:17:53 +00:00
accumulator . Insert ( str )
2014-07-08 04:32:56 +00:00
}
}
2014-08-20 03:54:20 +00:00
allErrs = append ( allErrs , cErrs . PrefixIndex ( ci ) ... )
2014-07-08 04:32:56 +00:00
}
2014-07-08 06:20:30 +00:00
return allErrs
2014-07-08 04:32:56 +00:00
}
2014-09-02 10:00:28 +00:00
// checkHostPortConflicts checks for colliding Port.HostPort values across
// a slice of containers.
2015-11-03 21:38:40 +00:00
func checkHostPortConflicts ( containers [ ] api . Container ) validation . ErrorList {
2015-09-09 17:45:01 +00:00
allPorts := sets . String { }
2015-05-19 17:17:53 +00:00
return AccumulateUniqueHostPorts ( containers , & allPorts )
2014-07-08 04:32:56 +00:00
}
2015-11-03 21:38:40 +00:00
func validateExecAction ( exec * api . ExecAction ) validation . ErrorList {
allErrors := validation . ErrorList { }
2014-09-12 23:04:10 +00:00
if len ( exec . Command ) == 0 {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldRequired ( "command" ) )
2014-09-12 23:04:10 +00:00
}
return allErrors
}
2015-11-03 21:38:40 +00:00
func validateHTTPGetAction ( http * api . HTTPGetAction ) validation . ErrorList {
allErrors := validation . ErrorList { }
2014-09-12 23:04:10 +00:00
if len ( http . Path ) == 0 {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldRequired ( "path" ) )
2014-09-12 23:04:10 +00:00
}
2015-11-10 06:28:45 +00:00
if http . Port . Type == intstr . Int && ! validation . IsValidPortNum ( http . Port . IntVal ) {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( "port" , http . Port , PortRangeErrorMsg ) )
2015-11-10 06:28:45 +00:00
} else if http . Port . Type == intstr . String && ! validation . IsValidPortName ( http . Port . StrVal ) {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( "port" , http . Port . StrVal , PortNameErrorMsg ) )
2015-02-28 01:33:58 +00:00
}
2015-09-09 17:45:01 +00:00
supportedSchemes := sets . NewString ( string ( api . URISchemeHTTP ) , string ( api . URISchemeHTTPS ) )
2015-06-25 17:53:41 +00:00
if ! supportedSchemes . Has ( string ( http . Scheme ) ) {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( "scheme" , http . Scheme , fmt . Sprintf ( "must be one of %v" , supportedSchemes . List ( ) ) ) )
2015-06-25 17:53:41 +00:00
}
2015-02-28 01:33:58 +00:00
return allErrors
}
2015-11-03 21:38:40 +00:00
func validateTCPSocketAction ( tcp * api . TCPSocketAction ) validation . ErrorList {
allErrors := validation . ErrorList { }
2015-11-10 06:28:45 +00:00
if tcp . Port . Type == intstr . Int && ! validation . IsValidPortNum ( tcp . Port . IntVal ) {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( "port" , tcp . Port , PortRangeErrorMsg ) )
2015-11-10 06:28:45 +00:00
} else if tcp . Port . Type == intstr . String && ! validation . IsValidPortName ( tcp . Port . StrVal ) {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( "port" , tcp . Port . StrVal , PortNameErrorMsg ) )
2015-02-28 01:33:58 +00:00
}
2014-09-12 23:04:10 +00:00
return allErrors
}
2015-11-03 21:38:40 +00:00
func validateHandler ( handler * api . Handler ) validation . ErrorList {
2014-11-20 22:24:10 +00:00
numHandlers := 0
2015-11-03 21:38:40 +00:00
allErrors := validation . ErrorList { }
2014-09-12 23:04:10 +00:00
if handler . Exec != nil {
2014-11-20 22:24:10 +00:00
numHandlers ++
2014-09-12 23:04:10 +00:00
allErrors = append ( allErrors , validateExecAction ( handler . Exec ) . Prefix ( "exec" ) ... )
2014-11-20 22:24:10 +00:00
}
if handler . HTTPGet != nil {
numHandlers ++
2014-09-12 23:04:10 +00:00
allErrors = append ( allErrors , validateHTTPGetAction ( handler . HTTPGet ) . Prefix ( "httpGet" ) ... )
2014-11-20 22:24:10 +00:00
}
2015-02-28 01:33:58 +00:00
if handler . TCPSocket != nil {
numHandlers ++
allErrors = append ( allErrors , validateTCPSocketAction ( handler . TCPSocket ) . Prefix ( "tcpSocket" ) ... )
}
2014-11-20 22:24:10 +00:00
if numHandlers != 1 {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( "" , handler , "exactly 1 handler type is required" ) )
2014-09-12 23:04:10 +00:00
}
return allErrors
}
2015-11-03 21:38:40 +00:00
func validateLifecycle ( lifecycle * api . Lifecycle ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-09-12 23:04:10 +00:00
if lifecycle . PostStart != nil {
allErrs = append ( allErrs , validateHandler ( lifecycle . PostStart ) . Prefix ( "postStart" ) ... )
}
if lifecycle . PreStop != nil {
allErrs = append ( allErrs , validateHandler ( lifecycle . PreStop ) . Prefix ( "preStop" ) ... )
}
return allErrs
}
2015-11-03 21:38:40 +00:00
func validatePullPolicy ( ctr * api . Container ) validation . ErrorList {
allErrors := validation . ErrorList { }
2015-01-16 23:02:36 +00:00
2015-01-16 23:02:36 +00:00
switch ctr . ImagePullPolicy {
case api . PullAlways , api . PullIfNotPresent , api . PullNever :
break
2015-01-26 17:52:50 +00:00
case "" :
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldRequired ( "" ) )
2015-01-16 23:02:36 +00:00
default :
2015-06-24 22:09:43 +00:00
validValues := [ ] string { string ( api . PullAlways ) , string ( api . PullIfNotPresent ) , string ( api . PullNever ) }
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldValueNotSupported ( "" , ctr . ImagePullPolicy , validValues ) )
2015-01-16 23:02:36 +00:00
}
return allErrors
}
2015-11-03 21:38:40 +00:00
func validateContainers ( containers [ ] api . Container , volumes sets . String ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-07-08 06:20:30 +00:00
2015-03-18 15:00:18 +00:00
if len ( containers ) == 0 {
2015-11-03 21:17:51 +00:00
return append ( allErrs , validation . NewFieldRequired ( "" ) )
2015-03-18 15:00:18 +00:00
}
2015-09-09 17:45:01 +00:00
allNames := sets . String { }
2015-01-26 17:52:50 +00:00
for i , ctr := range containers {
2015-11-03 21:38:40 +00:00
cErrs := validation . ErrorList { }
2014-08-20 02:57:48 +00:00
if len ( ctr . Name ) == 0 {
2015-11-03 21:17:51 +00:00
cErrs = append ( cErrs , validation . NewFieldRequired ( "name" ) )
2015-09-10 22:48:28 +00:00
} else if ! validation . IsDNS1123Label ( ctr . Name ) {
2015-11-03 21:17:51 +00:00
cErrs = append ( cErrs , validation . NewFieldInvalid ( "name" , ctr . Name , DNS1123LabelErrorMsg ) )
2014-07-08 06:20:30 +00:00
} else if allNames . Has ( ctr . Name ) {
2015-11-03 21:17:51 +00:00
cErrs = append ( cErrs , validation . NewFieldDuplicate ( "name" , ctr . Name ) )
2014-07-08 06:20:30 +00:00
} else {
allNames . Insert ( ctr . Name )
2014-07-01 22:14:25 +00:00
}
if len ( ctr . Image ) == 0 {
2015-11-03 21:17:51 +00:00
cErrs = append ( cErrs , validation . NewFieldRequired ( "image" ) )
2014-07-05 02:46:56 +00:00
}
2014-09-12 23:04:10 +00:00
if ctr . Lifecycle != nil {
cErrs = append ( cErrs , validateLifecycle ( ctr . Lifecycle ) . Prefix ( "lifecycle" ) ... )
}
2015-02-15 07:02:07 +00:00
cErrs = append ( cErrs , validateProbe ( ctr . LivenessProbe ) . Prefix ( "livenessProbe" ) ... )
2015-11-05 23:38:46 +00:00
// Liveness-specific validation
if ctr . LivenessProbe != nil && ctr . LivenessProbe . SuccessThreshold != 1 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldForbidden ( "livenessProbe.successThreshold" , "must be 1" ) )
2015-11-05 23:38:46 +00:00
}
2015-02-15 07:02:07 +00:00
cErrs = append ( cErrs , validateProbe ( ctr . ReadinessProbe ) . Prefix ( "readinessProbe" ) ... )
2014-08-20 03:54:20 +00:00
cErrs = append ( cErrs , validatePorts ( ctr . Ports ) . Prefix ( "ports" ) ... )
cErrs = append ( cErrs , validateEnv ( ctr . Env ) . Prefix ( "env" ) ... )
cErrs = append ( cErrs , validateVolumeMounts ( ctr . VolumeMounts , volumes ) . Prefix ( "volumeMounts" ) ... )
2015-06-15 14:02:32 +00:00
cErrs = append ( cErrs , validatePullPolicy ( & ctr ) . Prefix ( "imagePullPolicy" ) ... )
2015-04-20 18:56:15 +00:00
cErrs = append ( cErrs , ValidateResourceRequirements ( & ctr . Resources ) . Prefix ( "resources" ) ... )
2015-05-05 23:02:13 +00:00
cErrs = append ( cErrs , ValidateSecurityContext ( ctr . SecurityContext ) . Prefix ( "securityContext" ) ... )
2014-08-20 03:54:20 +00:00
allErrs = append ( allErrs , cErrs . PrefixIndex ( i ) ... )
2014-07-01 22:14:25 +00:00
}
2014-07-08 04:32:56 +00:00
// Check for colliding ports across all containers.
2014-08-16 20:34:06 +00:00
allErrs = append ( allErrs , checkHostPortConflicts ( containers ) ... )
2014-07-09 00:33:15 +00:00
2014-07-10 11:46:35 +00:00
return allErrs
2014-07-01 22:14:25 +00:00
}
2015-11-03 21:38:40 +00:00
func validateRestartPolicy ( restartPolicy * api . RestartPolicy ) validation . ErrorList {
allErrors := validation . ErrorList { }
2015-03-14 01:38:07 +00:00
switch * restartPolicy {
case api . RestartPolicyAlways , api . RestartPolicyOnFailure , api . RestartPolicyNever :
break
case "" :
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldRequired ( "" ) )
2015-03-14 01:38:07 +00:00
default :
2015-06-24 22:09:43 +00:00
validValues := [ ] string { string ( api . RestartPolicyAlways ) , string ( api . RestartPolicyOnFailure ) , string ( api . RestartPolicyNever ) }
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldValueNotSupported ( "" , * restartPolicy , validValues ) )
2014-08-26 18:25:17 +00:00
}
2015-03-14 01:38:07 +00:00
2014-08-26 18:25:17 +00:00
return allErrors
}
2014-07-22 18:45:12 +00:00
2015-11-03 21:38:40 +00:00
func validateDNSPolicy ( dnsPolicy * api . DNSPolicy ) validation . ErrorList {
allErrors := validation . ErrorList { }
2014-11-12 05:21:40 +00:00
switch * dnsPolicy {
case api . DNSClusterFirst , api . DNSDefault :
break
2015-01-26 17:52:50 +00:00
case "" :
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldRequired ( "" ) )
2014-11-12 05:21:40 +00:00
default :
2015-06-24 22:09:43 +00:00
validValues := [ ] string { string ( api . DNSClusterFirst ) , string ( api . DNSDefault ) }
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldValueNotSupported ( "" , dnsPolicy , validValues ) )
2014-11-12 05:21:40 +00:00
}
return allErrors
}
2015-11-03 21:38:40 +00:00
func validateHostNetwork ( hostNetwork bool , containers [ ] api . Container ) validation . ErrorList {
allErrors := validation . ErrorList { }
2015-03-23 23:34:35 +00:00
if hostNetwork {
for _ , container := range containers {
for _ , port := range container . Ports {
if port . HostPort != port . ContainerPort {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( "containerPort" , port . ContainerPort , "containerPort must match hostPort if hostNetwork is set to true" ) )
2015-03-23 23:34:35 +00:00
}
}
}
}
return allErrors
}
2015-05-19 12:39:46 +00:00
// 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
// and someone decides to set those fields, we'd like to know.
2015-11-03 21:38:40 +00:00
func validateImagePullSecrets ( imagePullSecrets [ ] api . LocalObjectReference ) validation . ErrorList {
allErrors := validation . ErrorList { }
2015-05-08 17:53:00 +00:00
for i , currPullSecret := range imagePullSecrets {
2015-05-19 12:39:46 +00:00
strippedRef := api . LocalObjectReference { Name : currPullSecret . Name }
2015-05-08 17:53:00 +00:00
if ! reflect . DeepEqual ( strippedRef , currPullSecret ) {
2015-11-03 21:17:51 +00:00
allErrors = append ( allErrors , validation . NewFieldInvalid ( fmt . Sprintf ( "[%d]" , i ) , currPullSecret , "only name may be set" ) )
2015-05-08 17:53:00 +00:00
}
}
return allErrors
}
2014-09-02 10:00:28 +00:00
// ValidatePod tests if required fields in the pod are set.
2015-11-03 21:38:40 +00:00
func ValidatePod ( pod * api . Pod ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-28 04:50:01 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & pod . ObjectMeta , true , ValidatePodName ) . Prefix ( "metadata" ) ... )
2014-11-13 15:52:13 +00:00
allErrs = append ( allErrs , ValidatePodSpec ( & pod . Spec ) . Prefix ( "spec" ) ... )
2015-01-27 23:55:54 +00:00
2014-10-23 20:14:13 +00:00
return allErrs
}
2014-11-07 02:08:46 +00:00
// ValidatePodSpec tests that the specified PodSpec has valid data.
// This includes checking formatting and uniqueness. It also canonicalizes the
// structure by setting default values and implementing any backwards-compatibility
// tricks.
2015-11-03 21:38:40 +00:00
func ValidatePodSpec ( spec * api . PodSpec ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-11-07 02:08:46 +00:00
allVolumes , vErrs := validateVolumes ( spec . Volumes )
allErrs = append ( allErrs , vErrs . Prefix ( "volumes" ) ... )
allErrs = append ( allErrs , validateContainers ( spec . Containers , allVolumes ) . Prefix ( "containers" ) ... )
allErrs = append ( allErrs , validateRestartPolicy ( & spec . RestartPolicy ) . Prefix ( "restartPolicy" ) ... )
2014-11-12 05:21:40 +00:00
allErrs = append ( allErrs , validateDNSPolicy ( & spec . DNSPolicy ) . Prefix ( "dnsPolicy" ) ... )
2015-01-20 03:32:39 +00:00
allErrs = append ( allErrs , ValidateLabels ( spec . NodeSelector , "nodeSelector" ) ... )
2015-09-14 21:56:51 +00:00
allErrs = append ( allErrs , ValidatePodSecurityContext ( spec . SecurityContext , spec ) . Prefix ( "securityContext" ) ... )
2015-05-08 17:53:00 +00:00
allErrs = append ( allErrs , validateImagePullSecrets ( spec . ImagePullSecrets ) . Prefix ( "imagePullSecrets" ) ... )
2015-06-19 02:35:42 +00:00
if len ( spec . ServiceAccountName ) > 0 {
if ok , msg := ValidateServiceAccountName ( spec . ServiceAccountName , false ) ; ! ok {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "serviceAccountName" , spec . ServiceAccountName , msg ) )
2015-06-11 21:16:58 +00:00
}
}
2015-05-09 05:01:43 +00:00
if spec . ActiveDeadlineSeconds != nil {
if * spec . ActiveDeadlineSeconds <= 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "activeDeadlineSeconds" , spec . ActiveDeadlineSeconds , "activeDeadlineSeconds must be a positive integer greater than 0" ) )
2015-05-09 05:01:43 +00:00
}
}
2014-11-07 02:08:46 +00:00
return allErrs
}
2015-09-14 21:56:51 +00:00
// ValidatePodSecurityContext test that the specified PodSecurityContext has valid data.
2015-11-03 21:38:40 +00:00
func ValidatePodSecurityContext ( securityContext * api . PodSecurityContext , spec * api . PodSpec ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-14 21:56:51 +00:00
if securityContext != nil {
allErrs = append ( allErrs , validateHostNetwork ( securityContext . HostNetwork , spec . Containers ) . Prefix ( "hostNetwork" ) ... )
}
return allErrs
}
2015-02-11 23:32:54 +00:00
// ValidatePodUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
// that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidatePodUpdate ( newPod , oldPod * api . Pod ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-10-10 03:30:34 +00:00
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newPod . ObjectMeta , & oldPod . ObjectMeta ) . Prefix ( "metadata" ) ... )
2014-10-14 19:28:45 +00:00
2014-11-13 15:52:13 +00:00
if len ( newPod . Spec . Containers ) != len ( oldPod . Spec . Containers ) {
2015-07-31 23:43:39 +00:00
//TODO: Pinpoint the specific container that causes the invalid error after we have strategic merge diff
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "spec.containers" , "content of spec.containers is not printed out, please refer to the \"details\"" , "may not add or remove containers" ) )
2014-10-10 03:30:34 +00:00
return allErrs
}
pod := * newPod
// Tricky, we need to copy the container list so that we don't overwrite the update
var newContainers [ ] api . Container
2014-11-13 15:52:13 +00:00
for ix , container := range pod . Spec . Containers {
container . Image = oldPod . Spec . Containers [ ix ] . Image
2014-10-10 03:30:34 +00:00
newContainers = append ( newContainers , container )
}
2014-11-13 15:52:13 +00:00
pod . Spec . Containers = newContainers
2015-01-05 21:38:39 +00:00
if ! api . Semantic . DeepEqual ( pod . Spec , oldPod . Spec ) {
2015-07-31 23:43:39 +00:00
//TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "spec" , "content of spec is not printed out, please refer to the \"details\"" , "may not update fields other than container.image" ) )
2014-10-10 03:30:34 +00:00
}
2015-01-27 23:55:54 +00:00
2015-02-11 23:32:54 +00:00
newPod . Status = oldPod . Status
2014-10-10 03:30:34 +00:00
return allErrs
}
2015-02-24 05:42:27 +00:00
// ValidatePodStatusUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
// that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidatePodStatusUpdate ( newPod , oldPod * api . Pod ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-24 05:42:27 +00:00
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newPod . ObjectMeta , & oldPod . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-02-24 05:42:27 +00:00
// TODO: allow change when bindings are properly decoupled from pods
2015-05-22 23:40:57 +00:00
if newPod . Spec . NodeName != oldPod . Spec . NodeName {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "status.nodeName" , newPod . Spec . NodeName , "pod nodename cannot be changed directly" ) )
2015-02-24 05:42:27 +00:00
}
2015-03-09 14:23:52 +00:00
// For status update we ignore changes to pod spec.
2015-02-24 05:42:27 +00:00
newPod . Spec = oldPod . Spec
return allErrs
}
2015-03-04 00:54:17 +00:00
// ValidatePodTemplate tests if required fields in the pod template are set.
2015-11-03 21:38:40 +00:00
func ValidatePodTemplate ( pod * api . PodTemplate ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-04 00:54:17 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & pod . ObjectMeta , true , ValidatePodName ) . Prefix ( "metadata" ) ... )
2015-07-25 19:08:34 +00:00
allErrs = append ( allErrs , ValidatePodTemplateSpec ( & pod . Template ) . Prefix ( "template" ) ... )
2015-03-04 00:54:17 +00:00
return allErrs
}
// ValidatePodTemplateUpdate tests to see if the update is legal for an end user to make. newPod is updated with fields
// that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidatePodTemplateUpdate ( newPod , oldPod * api . PodTemplate ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-07-25 19:08:34 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & oldPod . ObjectMeta , & newPod . ObjectMeta ) . Prefix ( "metadata" ) ... )
allErrs = append ( allErrs , ValidatePodTemplateSpec ( & newPod . Template ) . Prefix ( "template" ) ... )
2015-03-04 00:54:17 +00:00
return allErrs
}
2015-09-09 17:45:01 +00:00
var supportedSessionAffinityType = sets . NewString ( string ( api . ServiceAffinityClientIP ) , string ( api . ServiceAffinityNone ) )
var supportedServiceType = sets . NewString ( string ( api . ServiceTypeClusterIP ) , string ( api . ServiceTypeNodePort ) ,
2015-05-22 21:49:26 +00:00
string ( api . ServiceTypeLoadBalancer ) )
2014-12-17 12:52:11 +00:00
2014-07-15 13:53:39 +00:00
// ValidateService tests if required fields in the service are set.
2015-11-03 21:38:40 +00:00
func ValidateService ( service * api . Service ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-28 04:50:01 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & service . ObjectMeta , true , ValidateServiceName ) . Prefix ( "metadata" ) ... )
2015-01-27 23:55:54 +00:00
2015-11-06 17:53:57 +00:00
if len ( service . Spec . Ports ) == 0 && service . Spec . ClusterIP != api . ClusterIPNone {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "spec.ports" ) )
2014-08-22 21:44:21 +00:00
}
2015-07-09 05:02:10 +00:00
if service . Spec . Type == api . ServiceTypeLoadBalancer {
for ix := range service . Spec . Ports {
port := & service . Spec . Ports [ ix ]
if port . Port == 10250 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "spec.ports[%d].port" , ix ) , port . Port , "can not expose port 10250 externally since it is used by kubelet" ) )
2015-07-09 05:02:10 +00:00
}
}
}
2015-09-09 17:45:01 +00:00
allPortNames := sets . String { }
2015-03-13 15:16:41 +00:00
for i := range service . Spec . Ports {
2015-05-05 18:51:51 +00:00
allErrs = append ( allErrs , validateServicePort ( & service . Spec . Ports [ i ] , len ( service . Spec . Ports ) > 1 , & allPortNames ) . PrefixIndex ( i ) . Prefix ( "spec.ports" ) ... )
2015-02-28 01:33:58 +00:00
}
2014-11-18 17:49:00 +00:00
if service . Spec . Selector != nil {
2015-01-20 03:32:39 +00:00
allErrs = append ( allErrs , ValidateLabels ( service . Spec . Selector , "spec.selector" ) ... )
2014-07-10 19:45:01 +00:00
}
2014-11-18 17:49:00 +00:00
2014-12-29 22:39:09 +00:00
if service . Spec . SessionAffinity == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "spec.sessionAffinity" ) )
2014-12-29 22:39:09 +00:00
} else if ! supportedSessionAffinityType . Has ( string ( service . Spec . SessionAffinity ) ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldValueNotSupported ( "spec.sessionAffinity" , service . Spec . SessionAffinity , supportedSessionAffinityType . List ( ) ) )
2014-12-17 12:52:11 +00:00
}
2015-03-16 21:36:30 +00:00
if api . IsServiceIPSet ( service ) {
2015-05-23 20:41:11 +00:00
if ip := net . ParseIP ( service . Spec . ClusterIP ) ; ip == nil {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "spec.clusterIP" , service . Spec . ClusterIP , "clusterIP should be empty, 'None', or a valid IP address" ) )
2015-03-16 21:36:30 +00:00
}
}
2015-08-12 00:18:21 +00:00
for _ , ip := range service . Spec . ExternalIPs {
2015-03-16 14:03:05 +00:00
if ip == "0.0.0.0" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "spec.externalIPs" , ip , "is not an IP address" ) )
2015-03-16 14:03:05 +00:00
}
2015-08-12 00:18:21 +00:00
allErrs = append ( allErrs , validateIpIsNotLinkLocalOrLoopback ( ip , "spec.externalIPs" ) ... )
2015-03-16 14:03:05 +00:00
}
2015-05-22 21:49:26 +00:00
if service . Spec . Type == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "spec.type" ) )
2015-05-22 21:49:26 +00:00
} else if ! supportedServiceType . Has ( string ( service . Spec . Type ) ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldValueNotSupported ( "spec.type" , service . Spec . Type , supportedServiceType . List ( ) ) )
2015-05-22 21:49:26 +00:00
}
if service . Spec . Type == api . ServiceTypeLoadBalancer {
2015-04-03 19:06:25 +00:00
for i := range service . Spec . Ports {
if service . Spec . Ports [ i ] . Protocol != api . ProtocolTCP {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "spec.ports[%d].protocol" , i ) , service . Spec . Ports [ i ] . Protocol , "cannot create an external load balancer with non-TCP ports" ) )
2015-04-03 19:06:25 +00:00
}
}
}
2015-05-20 15:59:34 +00:00
if service . Spec . Type == api . ServiceTypeClusterIP {
for i := range service . Spec . Ports {
if service . Spec . Ports [ i ] . NodePort != 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "spec.ports[%d].nodePort" , i ) , service . Spec . Ports [ i ] . NodePort , "cannot specify a node port with services of type ClusterIP" ) )
2015-05-20 15:59:34 +00:00
}
}
}
2015-05-22 21:54:19 +00:00
// Check for duplicate NodePorts, considering (protocol,port) pairs
nodePorts := make ( map [ api . ServicePort ] bool )
for i := range service . Spec . Ports {
port := & service . Spec . Ports [ i ]
if port . NodePort == 0 {
continue
}
var key api . ServicePort
key . Protocol = port . Protocol
key . NodePort = port . NodePort
_ , found := nodePorts [ key ]
if found {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "spec.ports[%d].nodePort" , i ) , port . NodePort , "duplicate nodePort specified" ) )
2015-05-22 21:54:19 +00:00
}
nodePorts [ key ] = true
}
2014-08-16 20:48:48 +00:00
return allErrs
2014-07-10 19:45:01 +00:00
}
2014-07-25 16:15:17 +00:00
2015-11-03 21:38:40 +00:00
func validateServicePort ( sp * api . ServicePort , requireName bool , allNames * sets . String ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-13 15:16:41 +00:00
2015-05-05 18:51:51 +00:00
if requireName && sp . Name == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "name" ) )
2015-05-05 18:51:51 +00:00
} else if sp . Name != "" {
2015-09-10 22:48:28 +00:00
if ! validation . IsDNS1123Label ( sp . Name ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "name" , sp . Name , DNS1123LabelErrorMsg ) )
2015-05-05 18:51:51 +00:00
} else if allNames . Has ( sp . Name ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldDuplicate ( "name" , sp . Name ) )
2015-04-29 02:08:42 +00:00
} else {
allNames . Insert ( sp . Name )
2015-03-13 15:16:41 +00:00
}
}
2015-09-10 22:48:28 +00:00
if ! validation . IsValidPortNum ( sp . Port ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "port" , sp . Port , PortRangeErrorMsg ) )
2015-03-13 15:16:41 +00:00
}
if len ( sp . Protocol ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "protocol" ) )
2015-06-17 00:28:11 +00:00
} else if ! supportedPortProtocols . Has ( string ( sp . Protocol ) ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldValueNotSupported ( "protocol" , sp . Protocol , supportedPortProtocols . List ( ) ) )
2015-03-13 15:16:41 +00:00
}
2015-11-10 06:28:45 +00:00
if sp . TargetPort . Type == intstr . Int && ! validation . IsValidPortNum ( sp . TargetPort . IntVal ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "targetPort" , sp . TargetPort , PortRangeErrorMsg ) )
2015-06-12 16:33:11 +00:00
}
2015-11-10 06:28:45 +00:00
if sp . TargetPort . Type == intstr . String && ! validation . IsValidPortName ( sp . TargetPort . StrVal ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "targetPort" , sp . TargetPort , PortNameErrorMsg ) )
2015-03-13 15:16:41 +00:00
}
return allErrs
}
2015-01-27 23:55:54 +00:00
// ValidateServiceUpdate tests if required fields in the service are set during an update
2015-11-03 21:38:40 +00:00
func ValidateServiceUpdate ( service , oldService * api . Service ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & service . ObjectMeta , & oldService . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-01-27 23:55:54 +00:00
2015-10-12 03:26:17 +00:00
if api . IsServiceIPSet ( oldService ) {
2015-11-04 07:47:11 +00:00
allErrs = append ( allErrs , ValidateImmutableField ( service . Spec . ClusterIP , oldService . Spec . ClusterIP , "spec.clusterIP" ) ... )
2015-01-27 23:55:54 +00:00
}
2015-03-31 16:30:56 +00:00
allErrs = append ( allErrs , ValidateService ( service ) ... )
2015-01-27 23:55:54 +00:00
return allErrs
}
2014-07-25 16:15:17 +00:00
// ValidateReplicationController tests if required fields in the replication controller are set.
2015-11-03 21:38:40 +00:00
func ValidateReplicationController ( controller * api . ReplicationController ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-28 04:50:01 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & controller . ObjectMeta , true , ValidateReplicationControllerName ) . Prefix ( "metadata" ) ... )
2014-11-07 02:08:46 +00:00
allErrs = append ( allErrs , ValidateReplicationControllerSpec ( & controller . Spec ) . Prefix ( "spec" ) ... )
2015-01-27 23:55:54 +00:00
return allErrs
}
// ValidateReplicationControllerUpdate tests if required fields in the replication controller are set.
2015-11-03 21:38:40 +00:00
func ValidateReplicationControllerUpdate ( controller , oldController * api . ReplicationController ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & controller . ObjectMeta , & oldController . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-01-27 23:55:54 +00:00
allErrs = append ( allErrs , ValidateReplicationControllerSpec ( & controller . Spec ) . Prefix ( "spec" ) ... )
2014-09-16 16:54:38 +00:00
return allErrs
}
2015-09-28 19:39:57 +00:00
// ValidateReplicationControllerStatusUpdate tests if required fields in the replication controller are set.
2015-11-03 21:38:40 +00:00
func ValidateReplicationControllerStatusUpdate ( controller , oldController * api . ReplicationController ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-28 19:39:57 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & controller . ObjectMeta , & oldController . ObjectMeta ) . Prefix ( "metadata" ) ... )
allErrs = append ( allErrs , ValidatePositiveField ( int64 ( controller . Status . Replicas ) , "status.replicas" ) ... )
allErrs = append ( allErrs , ValidatePositiveField ( int64 ( controller . Status . ObservedGeneration ) , "status.observedGeneration" ) ... )
return allErrs
}
2015-08-25 19:07:03 +00:00
// Validates that the given selector is non-empty.
2015-11-03 21:38:40 +00:00
func ValidateNonEmptySelector ( selectorMap map [ string ] string , fieldName string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-08-25 19:07:03 +00:00
selector := labels . Set ( selectorMap ) . AsSelector ( )
2014-11-07 02:08:46 +00:00
if selector . Empty ( ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( fieldName ) )
2014-08-22 00:02:39 +00:00
}
2015-08-25 19:07:03 +00:00
return allErrs
}
2014-11-07 02:08:46 +00:00
2015-08-25 19:07:03 +00:00
// Validates the given template and ensures that it is in accordance with the desrired selector and replicas.
2015-11-03 21:38:40 +00:00
func ValidatePodTemplateSpecForRC ( template * api . PodTemplateSpec , selectorMap map [ string ] string , replicas int , fieldName string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-08-25 19:07:03 +00:00
if template == nil {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( fieldName ) )
2014-11-07 02:08:46 +00:00
} else {
2015-08-25 19:07:03 +00:00
selector := labels . Set ( selectorMap ) . AsSelector ( )
if ! selector . Empty ( ) {
// Verify that the RC selector matches the labels in template.
labels := labels . Set ( template . Labels )
if ! selector . Matches ( labels ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName + ".metadata.labels" , template . Labels , "selector does not match labels in " + fieldName ) )
2015-08-25 19:07:03 +00:00
}
2015-07-25 19:08:34 +00:00
}
2015-08-25 19:07:03 +00:00
allErrs = append ( allErrs , ValidatePodTemplateSpec ( template ) . Prefix ( fieldName ) ... )
if replicas > 1 {
allErrs = append ( allErrs , ValidateReadOnlyPersistentDisks ( template . Spec . Volumes ) . Prefix ( fieldName + ".spec.volumes" ) ... )
2015-07-25 19:08:34 +00:00
}
// RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
2015-08-25 19:07:03 +00:00
if template . Spec . RestartPolicy != api . RestartPolicyAlways {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldValueNotSupported ( fieldName + ".spec.restartPolicy" , template . Spec . RestartPolicy , [ ] string { string ( api . RestartPolicyAlways ) } ) )
2014-11-18 04:08:23 +00:00
}
2014-08-04 19:02:51 +00:00
}
2014-08-05 17:58:43 +00:00
return allErrs
}
2014-11-07 02:08:46 +00:00
2015-08-25 19:07:03 +00:00
// ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set.
2015-11-03 21:38:40 +00:00
func ValidateReplicationControllerSpec ( spec * api . ReplicationControllerSpec ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-08-25 19:07:03 +00:00
allErrs = append ( allErrs , ValidateNonEmptySelector ( spec . Selector , "selector" ) ... )
allErrs = append ( allErrs , ValidatePositiveField ( int64 ( spec . Replicas ) , "replicas" ) ... )
allErrs = append ( allErrs , ValidatePodTemplateSpecForRC ( spec . Template , spec . Selector , spec . Replicas , "template" ) ... )
return allErrs
}
2014-11-07 02:08:46 +00:00
// ValidatePodTemplateSpec validates the spec of a pod template
2015-11-03 21:38:40 +00:00
func ValidatePodTemplateSpec ( spec * api . PodTemplateSpec ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-20 03:32:39 +00:00
allErrs = append ( allErrs , ValidateLabels ( spec . Labels , "labels" ) ... )
2015-02-02 00:03:04 +00:00
allErrs = append ( allErrs , ValidateAnnotations ( spec . Annotations , "annotations" ) ... )
2014-11-07 02:08:46 +00:00
allErrs = append ( allErrs , ValidatePodSpec ( & spec . Spec ) . Prefix ( "spec" ) ... )
return allErrs
}
2015-11-03 21:38:40 +00:00
func ValidateReadOnlyPersistentDisks ( volumes [ ] api . Volume ) validation . ErrorList {
allErrs := validation . ErrorList { }
2014-08-05 17:58:43 +00:00
for _ , vol := range volumes {
2015-03-03 22:48:55 +00:00
if vol . GCEPersistentDisk != nil {
if vol . GCEPersistentDisk . ReadOnly == false {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "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." ) )
2014-08-05 17:58:43 +00:00
}
}
2015-03-06 14:26:39 +00:00
// TODO: What to do for AWS? It doesn't support replicas
2014-08-05 17:58:43 +00:00
}
2014-08-16 20:48:48 +00:00
return allErrs
2014-07-25 16:15:17 +00:00
}
2014-10-08 19:56:02 +00:00
2015-04-22 17:55:05 +00:00
// ValidateNode tests if required fields in the node are set.
2015-11-03 21:38:40 +00:00
func ValidateNode ( node * api . Node ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-28 04:50:01 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & node . ObjectMeta , false , ValidateNodeName ) . Prefix ( "metadata" ) ... )
2015-04-01 23:11:33 +00:00
// Only validate spec. All status fields are optional and can be updated later.
2015-03-24 17:24:07 +00:00
// external ID is required.
if len ( node . Spec . ExternalID ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "spec.ExternalID" ) )
2015-03-24 17:24:07 +00:00
}
// TODO(rjnagal): Ignore PodCIDR till its completely implemented.
2014-11-12 17:38:15 +00:00
return allErrs
}
2014-11-17 18:22:27 +00:00
2015-04-22 17:55:05 +00:00
// ValidateNodeUpdate tests to make sure a node update can be applied. Modifies oldNode.
2015-11-03 21:38:40 +00:00
func ValidateNodeUpdate ( node , oldNode * api . Node ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & node . ObjectMeta , & oldNode . ObjectMeta ) . Prefix ( "metadata" ) ... )
2014-12-12 05:39:56 +00:00
2015-01-16 22:28:20 +00:00
// TODO: Enable the code once we have better api object.status update model. Currently,
// anyone can update node status.
2015-04-22 17:55:05 +00:00
// if !api.Semantic.DeepEqual(node.Status, api.NodeStatus{}) {
2015-11-03 21:17:51 +00:00
// allErrs = append(allErrs, validation.NewFieldInvalid("status", node.Status, "status must be empty"))
2015-01-16 22:28:20 +00:00
// }
2014-12-12 05:39:56 +00:00
2015-04-22 17:55:05 +00:00
// Validte no duplicate addresses in node status.
addresses := make ( map [ api . NodeAddress ] bool )
for _ , address := range node . Status . Addresses {
if _ , ok := addresses [ address ] ; ok {
allErrs = append ( allErrs , fmt . Errorf ( "duplicate node addresses found" ) )
}
addresses [ address ] = true
}
2015-01-27 23:55:54 +00:00
// TODO: move reset function to its own location
// Ignore metadata changes now that they have been tested
2015-04-22 17:55:05 +00:00
oldNode . ObjectMeta = node . ObjectMeta
2015-01-27 23:55:54 +00:00
// Allow users to update capacity
2015-04-22 17:55:05 +00:00
oldNode . Status . Capacity = node . Status . Capacity
2015-05-20 21:21:03 +00:00
// Allow the controller manager to assign a CIDR to a node.
oldNode . Spec . PodCIDR = node . Spec . PodCIDR
2015-02-17 20:03:14 +00:00
// Allow users to unschedule node
2015-04-22 17:55:05 +00:00
oldNode . Spec . Unschedulable = node . Spec . Unschedulable
2014-12-22 19:04:57 +00:00
// Clear status
2015-04-22 17:55:05 +00:00
oldNode . Status = node . Status
2014-12-12 05:39:56 +00:00
2015-11-03 21:35:11 +00:00
// TODO: Add a 'real' error type for this error and provide print actual diffs.
2015-04-22 17:55:05 +00:00
if ! api . Semantic . DeepEqual ( oldNode , node ) {
glog . V ( 4 ) . Infof ( "Update failed validation %#v vs %#v" , oldNode , node )
2014-12-12 05:39:56 +00:00
allErrs = append ( allErrs , fmt . Errorf ( "update contains more than labels or capacity changes" ) )
2014-11-17 18:22:27 +00:00
}
2015-01-27 23:55:54 +00:00
2014-11-17 18:22:27 +00:00
return allErrs
}
2015-01-17 00:34:47 +00:00
2015-01-25 04:19:36 +00:00
// Validate compute resource typename.
2015-09-17 10:26:01 +00:00
// Refer to docs/design/resources.md for more details.
2015-11-03 21:38:40 +00:00
func validateResourceName ( value string , field string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-10 22:48:28 +00:00
if ! validation . IsQualifiedName ( value ) {
2015-11-03 21:17:51 +00:00
return append ( allErrs , validation . NewFieldInvalid ( field , value , "resource typename: " + qualifiedNameErrorMsg ) )
2015-01-17 00:34:47 +00:00
}
2015-02-05 00:36:27 +00:00
if len ( strings . Split ( value , "/" ) ) == 1 {
if ! api . IsStandardResourceName ( value ) {
2015-11-03 21:17:51 +00:00
return append ( allErrs , validation . NewFieldInvalid ( field , value , "is neither a standard resource type nor is fully qualified" ) )
2015-01-17 00:34:47 +00:00
}
}
2015-11-03 21:38:40 +00:00
return validation . ErrorList { }
2015-01-17 00:34:47 +00:00
}
2015-01-22 21:52:40 +00:00
// ValidateLimitRange tests if required fields in the LimitRange are set.
2015-11-03 21:38:40 +00:00
func ValidateLimitRange ( limitRange * api . LimitRange ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-20 06:03:36 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & limitRange . ObjectMeta , true , ValidateLimitRangeName ) . Prefix ( "metadata" ) ... )
2015-09-17 10:26:01 +00:00
// ensure resource names are properly qualified per docs/design/resources.md
2015-06-16 20:16:34 +00:00
limitTypeSet := map [ api . LimitType ] bool { }
2015-01-22 21:52:40 +00:00
for i := range limitRange . Spec . Limits {
limit := limitRange . Spec . Limits [ i ]
2015-06-16 20:16:34 +00:00
_ , found := limitTypeSet [ limit . Type ]
if found {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldDuplicate ( fmt . Sprintf ( "spec.limits[%d].type" , i ) , limit . Type ) )
2015-06-16 20:16:34 +00:00
}
limitTypeSet [ limit . Type ] = true
2015-09-09 17:45:01 +00:00
keys := sets . String { }
2015-09-08 18:49:54 +00:00
min := map [ string ] resource . Quantity { }
max := map [ string ] resource . Quantity { }
defaults := map [ string ] resource . Quantity { }
defaultRequests := map [ string ] resource . Quantity { }
2015-09-11 07:38:38 +00:00
maxLimitRequestRatios := map [ string ] resource . Quantity { }
2015-06-16 20:16:34 +00:00
2015-09-08 18:49:54 +00:00
for k , q := range limit . Max {
2015-02-05 00:36:27 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , fmt . Sprintf ( "spec.limits[%d].max[%s]" , i , k ) ) ... )
2015-06-16 20:16:34 +00:00
keys . Insert ( string ( k ) )
2015-09-08 18:49:54 +00:00
max [ string ( k ) ] = q
2015-01-22 21:52:40 +00:00
}
2015-09-08 18:49:54 +00:00
for k , q := range limit . Min {
2015-02-05 00:36:27 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , fmt . Sprintf ( "spec.limits[%d].min[%s]" , i , k ) ) ... )
2015-06-16 20:16:34 +00:00
keys . Insert ( string ( k ) )
2015-09-08 18:49:54 +00:00
min [ string ( k ) ] = q
2015-06-16 20:16:34 +00:00
}
2015-09-10 20:39:59 +00:00
if limit . Type == api . LimitTypePod {
if len ( limit . Default ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "spec.limits[%d].default" , limit . Default , "Default is not supported when limit type is Pod" ) )
2015-09-10 20:39:59 +00:00
}
if len ( limit . DefaultRequest ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "spec.limits[%d].defaultRequest" , limit . DefaultRequest , "DefaultRequest is not supported when limit type is Pod" ) )
2015-09-10 20:39:59 +00:00
}
} else {
for k , q := range limit . Default {
allErrs = append ( allErrs , validateResourceName ( string ( k ) , fmt . Sprintf ( "spec.limits[%d].default[%s]" , i , k ) ) ... )
keys . Insert ( string ( k ) )
defaults [ string ( k ) ] = q
}
for k , q := range limit . DefaultRequest {
allErrs = append ( allErrs , validateResourceName ( string ( k ) , fmt . Sprintf ( "spec.limits[%d].defaultRequest[%s]" , i , k ) ) ... )
keys . Insert ( string ( k ) )
defaultRequests [ string ( k ) ] = q
}
2015-08-28 16:26:36 +00:00
}
2015-09-10 20:39:59 +00:00
2015-09-11 07:38:38 +00:00
for k , q := range limit . MaxLimitRequestRatio {
2015-08-28 16:26:36 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , fmt . Sprintf ( "spec.limits[%d].maxLimitRequestRatio[%s]" , i , k ) ) ... )
2015-09-11 07:38:38 +00:00
keys . Insert ( string ( k ) )
maxLimitRequestRatios [ string ( k ) ] = q
2015-08-28 16:26:36 +00:00
}
2015-06-16 20:16:34 +00:00
for k := range keys {
2015-09-08 18:49:54 +00:00
minQuantity , minQuantityFound := min [ k ]
maxQuantity , maxQuantityFound := max [ k ]
defaultQuantity , defaultQuantityFound := defaults [ k ]
defaultRequestQuantity , defaultRequestQuantityFound := defaultRequests [ k ]
2015-09-11 07:38:38 +00:00
maxRatio , maxRatioFound := maxLimitRequestRatios [ k ]
2015-06-16 20:16:34 +00:00
2015-09-08 18:49:54 +00:00
if minQuantityFound && maxQuantityFound && minQuantity . Cmp ( maxQuantity ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( 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 ( ) ) ) )
2015-08-28 16:26:36 +00:00
}
2015-09-08 18:49:54 +00:00
if defaultRequestQuantityFound && minQuantityFound && minQuantity . Cmp ( defaultRequestQuantity ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( 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 ( ) ) ) )
2015-08-28 16:26:36 +00:00
}
2015-09-08 18:49:54 +00:00
if defaultRequestQuantityFound && maxQuantityFound && defaultRequestQuantity . Cmp ( maxQuantity ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( 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 ( ) ) ) )
2015-08-28 16:26:36 +00:00
}
2015-09-08 18:49:54 +00:00
if defaultRequestQuantityFound && defaultQuantityFound && defaultRequestQuantity . Cmp ( defaultQuantity ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( 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 ( ) ) ) )
2015-06-16 20:16:34 +00:00
}
2015-09-08 18:49:54 +00:00
if defaultQuantityFound && minQuantityFound && minQuantity . Cmp ( defaultQuantity ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( 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 ( ) ) ) )
2015-06-16 20:16:34 +00:00
}
2015-09-08 18:49:54 +00:00
if defaultQuantityFound && maxQuantityFound && defaultQuantity . Cmp ( maxQuantity ) > 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( 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 ( ) ) ) )
2015-06-16 20:16:34 +00:00
}
2015-09-11 07:38:38 +00:00
if maxRatioFound && maxRatio . Cmp ( * resource . NewQuantity ( 1 , resource . DecimalSI ) ) < 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "spec.limits[%d].maxLimitRequestRatio[%s]" , i , k ) , maxRatio , fmt . Sprintf ( "maxLimitRequestRatio %s is less than 1" , maxRatio . String ( ) ) ) )
2015-09-11 07:38:38 +00:00
}
if maxRatioFound && minQuantityFound && maxQuantityFound {
maxRatioValue := float64 ( maxRatio . Value ( ) )
minQuantityValue := minQuantity . Value ( )
maxQuantityValue := maxQuantity . Value ( )
if maxRatio . Value ( ) < resource . MaxMilliValue && minQuantityValue < resource . MaxMilliValue && maxQuantityValue < resource . MaxMilliValue {
maxRatioValue = float64 ( maxRatio . MilliValue ( ) ) / 1000
minQuantityValue = minQuantity . MilliValue ( )
maxQuantityValue = maxQuantity . MilliValue ( )
}
maxRatioLimit := float64 ( maxQuantityValue ) / float64 ( minQuantityValue )
if maxRatioValue > maxRatioLimit {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "spec.limits[%d].maxLimitRequestRatio[%s]" , i , k ) , maxRatio , fmt . Sprintf ( "maxLimitRequestRatio %s is greater than max/min = %f" , maxRatio . String ( ) , maxRatioLimit ) ) )
2015-09-11 07:38:38 +00:00
}
}
2015-01-25 04:19:36 +00:00
}
}
2015-06-16 20:16:34 +00:00
2015-01-25 04:19:36 +00:00
return allErrs
}
2015-04-27 22:53:28 +00:00
// ValidateServiceAccount tests if required fields in the ServiceAccount are set.
2015-11-03 21:38:40 +00:00
func ValidateServiceAccount ( serviceAccount * api . ServiceAccount ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-27 22:53:28 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & serviceAccount . ObjectMeta , true , ValidateServiceAccountName ) . Prefix ( "metadata" ) ... )
return allErrs
}
// ValidateServiceAccountUpdate tests if required fields in the ServiceAccount are set.
2015-11-03 21:38:40 +00:00
func ValidateServiceAccountUpdate ( newServiceAccount , oldServiceAccount * api . ServiceAccount ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newServiceAccount . ObjectMeta , & oldServiceAccount . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-04-27 22:53:28 +00:00
allErrs = append ( allErrs , ValidateServiceAccount ( newServiceAccount ) ... )
return allErrs
}
2015-09-10 22:48:28 +00:00
const SecretKeyFmt string = "\\.?" + validation . DNS1123LabelFmt + "(\\." + validation . DNS1123LabelFmt + ")*"
2015-05-11 19:03:10 +00:00
var secretKeyRegexp = regexp . MustCompile ( "^" + SecretKeyFmt + "$" )
// IsSecretKey tests for a string that conforms to the definition of a
// subdomain in DNS (RFC 1123), except that a leading dot is allowed
func IsSecretKey ( value string ) bool {
2015-09-10 22:48:28 +00:00
return len ( value ) <= validation . DNS1123SubdomainMaxLength && secretKeyRegexp . MatchString ( value )
2015-05-11 19:03:10 +00:00
}
2015-02-18 01:24:50 +00:00
// ValidateSecret tests if required fields in the Secret are set.
2015-11-03 21:38:40 +00:00
func ValidateSecret ( secret * api . Secret ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-20 06:03:36 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & secret . ObjectMeta , true , ValidateSecretName ) . Prefix ( "metadata" ) ... )
2015-02-18 01:24:50 +00:00
totalSize := 0
2015-02-18 01:26:41 +00:00
for key , value := range secret . Data {
2015-05-11 19:03:10 +00:00
if ! IsSecretKey ( key ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "data[%s]" , key ) , key , fmt . Sprintf ( "must have at most %d characters and match regex %s" , validation . DNS1123SubdomainMaxLength , SecretKeyFmt ) ) )
2015-02-18 01:26:41 +00:00
}
2015-02-18 01:24:50 +00:00
totalSize += len ( value )
}
2015-02-18 01:26:41 +00:00
2015-02-18 01:24:50 +00:00
if totalSize > api . MaxSecretSize {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldForbidden ( "data" , "Maximum secret size exceeded" ) )
2015-02-18 01:24:50 +00:00
}
2015-04-28 03:50:56 +00:00
switch secret . Type {
2015-04-28 03:51:20 +00:00
case api . SecretTypeServiceAccountToken :
// Only require Annotations[kubernetes.io/service-account.name]
// Additional fields (like Annotations[kubernetes.io/service-account.uid] and Data[token]) might be contributed later by a controller loop
if value := secret . Annotations [ api . ServiceAccountNameKey ] ; len ( value ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( fmt . Sprintf ( "metadata.annotations[%s]" , api . ServiceAccountNameKey ) ) )
2015-04-28 03:51:20 +00:00
}
2015-04-28 03:50:56 +00:00
case api . SecretTypeOpaque , "" :
2015-05-20 15:59:34 +00:00
// no-op
2015-05-06 14:09:18 +00:00
case api . SecretTypeDockercfg :
dockercfgBytes , exists := secret . Data [ api . DockerConfigKey ]
if ! exists {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( fmt . Sprintf ( "data[%s]" , api . DockerConfigKey ) ) )
2015-05-06 14:09:18 +00:00
break
}
// make sure that the content is well-formed json.
if err := json . Unmarshal ( dockercfgBytes , & map [ string ] interface { } { } ) ; err != nil {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "data[%s]" , api . DockerConfigKey ) , "<secret contents redacted>" , err . Error ( ) ) )
2015-05-06 14:09:18 +00:00
}
2015-04-28 03:50:56 +00:00
default :
// no-op
}
return allErrs
}
// ValidateSecretUpdate tests if required fields in the Secret are set.
2015-11-03 21:38:40 +00:00
func ValidateSecretUpdate ( newSecret , oldSecret * api . Secret ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newSecret . ObjectMeta , & oldSecret . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-04-28 03:50:56 +00:00
if len ( newSecret . Type ) == 0 {
newSecret . Type = oldSecret . Type
}
2015-10-12 03:26:17 +00:00
2015-11-04 07:47:11 +00:00
allErrs = append ( allErrs , ValidateImmutableField ( newSecret . Type , oldSecret . Type , "type" ) ... )
2015-04-28 03:50:56 +00:00
allErrs = append ( allErrs , ValidateSecret ( newSecret ) ... )
2015-02-18 01:24:50 +00:00
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateBasicResource ( quantity resource . Quantity ) validation . ErrorList {
2015-01-25 04:19:36 +00:00
if quantity . Value ( ) < 0 {
2015-11-03 21:38:40 +00:00
return validation . ErrorList { validation . NewFieldInvalid ( "" , quantity . Value ( ) , "must be a valid resource quantity" ) }
2015-01-25 04:19:36 +00:00
}
2015-11-03 21:38:40 +00:00
return validation . ErrorList { }
2015-01-25 04:19:36 +00:00
}
// Validates resource requirement spec.
2015-11-03 21:38:40 +00:00
func ValidateResourceRequirements ( requirements * api . ResourceRequirements ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-04-20 18:56:15 +00:00
for resourceName , quantity := range requirements . Limits {
2015-01-25 04:19:36 +00:00
// Validate resource name.
2015-07-30 19:59:22 +00:00
allErrs = append ( allErrs , validateResourceName ( resourceName . String ( ) , fmt . Sprintf ( "resources.limits[%s]" , resourceName ) ) ... )
2015-01-25 04:19:36 +00:00
if api . IsStandardResourceName ( resourceName . String ( ) ) {
2015-07-30 19:59:22 +00:00
allErrs = append ( allErrs , validateBasicResource ( quantity ) . Prefix ( fmt . Sprintf ( "Resource %s: " , resourceName ) ) ... )
}
// Check that request <= limit.
requestQuantity , exists := requirements . Requests [ resourceName ]
if exists {
var requestValue , limitValue int64
requestValue = requestQuantity . Value ( )
limitValue = quantity . Value ( )
// Do a more precise comparison if possible (if the value won't overflow).
if requestValue <= resource . MaxMilliValue && limitValue <= resource . MaxMilliValue {
requestValue = requestQuantity . MilliValue ( )
limitValue = quantity . MilliValue ( )
}
if limitValue < requestValue {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fmt . Sprintf ( "resources.limits[%s]" , resourceName ) , quantity . String ( ) , "limit cannot be smaller than request" ) )
2015-07-30 19:59:22 +00:00
}
2015-01-22 21:52:40 +00:00
}
}
2015-04-20 18:56:15 +00:00
for resourceName , quantity := range requirements . Requests {
// Validate resource name.
2015-07-30 19:59:22 +00:00
allErrs = append ( allErrs , validateResourceName ( resourceName . String ( ) , fmt . Sprintf ( "resources.requests[%s]" , resourceName ) ) ... )
2015-04-20 18:56:15 +00:00
if api . IsStandardResourceName ( resourceName . String ( ) ) {
2015-07-30 19:59:22 +00:00
allErrs = append ( allErrs , validateBasicResource ( quantity ) . Prefix ( fmt . Sprintf ( "Resource %s: " , resourceName ) ) ... )
2015-04-20 18:56:15 +00:00
}
}
2015-01-22 21:52:40 +00:00
return allErrs
}
2015-01-23 17:38:30 +00:00
// ValidateResourceQuota tests if required fields in the ResourceQuota are set.
2015-11-03 21:38:40 +00:00
func ValidateResourceQuota ( resourceQuota * api . ResourceQuota ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-02-20 06:03:36 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & resourceQuota . ObjectMeta , true , ValidateResourceQuotaName ) . Prefix ( "metadata" ) ... )
2015-09-24 14:15:40 +00:00
for k , v := range resourceQuota . Spec . Hard {
2015-02-05 00:36:27 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , string ( resourceQuota . TypeMeta . Kind ) ) ... )
2015-10-13 21:27:56 +00:00
allErrs = append ( allErrs , validateResourceQuantityValue ( string ( k ) , v ) ... )
2015-01-23 17:38:30 +00:00
}
2015-09-24 14:15:40 +00:00
for k , v := range resourceQuota . Status . Hard {
2015-02-05 00:36:27 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , string ( resourceQuota . TypeMeta . Kind ) ) ... )
2015-10-13 21:27:56 +00:00
allErrs = append ( allErrs , validateResourceQuantityValue ( string ( k ) , v ) ... )
2015-01-23 17:38:30 +00:00
}
2015-09-24 14:15:40 +00:00
for k , v := range resourceQuota . Status . Used {
2015-02-05 00:36:27 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , string ( resourceQuota . TypeMeta . Kind ) ) ... )
2015-10-13 21:27:56 +00:00
allErrs = append ( allErrs , validateResourceQuantityValue ( string ( k ) , v ) ... )
}
return allErrs
}
// validateResourceQuantityValue enforces that specified quantity is valid for specified resource
2015-11-03 21:38:40 +00:00
func validateResourceQuantityValue ( resource string , value resource . Quantity ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-10-13 21:27:56 +00:00
allErrs = append ( allErrs , ValidatePositiveQuantity ( value , resource ) ... )
if api . IsIntegerResourceName ( resource ) {
if value . MilliValue ( ) % int64 ( 1000 ) != int64 ( 0 ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( resource , value , isNotIntegerErrorMsg ) )
2015-10-13 21:27:56 +00:00
}
2015-01-23 17:38:30 +00:00
}
return allErrs
}
2015-01-19 21:50:00 +00:00
2015-03-13 19:15:04 +00:00
// ValidateResourceQuotaUpdate tests to see if the update is legal for an end user to make.
// newResourceQuota is updated with fields that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidateResourceQuotaUpdate ( newResourceQuota , oldResourceQuota * api . ResourceQuota ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newResourceQuota . ObjectMeta , & oldResourceQuota . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-10-13 21:27:56 +00:00
for k , v := range newResourceQuota . Spec . Hard {
2015-03-13 19:15:04 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , string ( newResourceQuota . TypeMeta . Kind ) ) ... )
2015-10-13 21:27:56 +00:00
allErrs = append ( allErrs , validateResourceQuantityValue ( string ( k ) , v ) ... )
2015-03-13 19:15:04 +00:00
}
newResourceQuota . Status = oldResourceQuota . Status
return allErrs
}
// ValidateResourceQuotaStatusUpdate tests to see if the status update is legal for an end user to make.
// newResourceQuota is updated with fields that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidateResourceQuotaStatusUpdate ( newResourceQuota , oldResourceQuota * api . ResourceQuota ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newResourceQuota . ObjectMeta , & oldResourceQuota . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-03-13 19:15:04 +00:00
if newResourceQuota . ResourceVersion == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "resourceVersion" ) )
2015-03-13 19:15:04 +00:00
}
2015-10-13 21:27:56 +00:00
for k , v := range newResourceQuota . Status . Hard {
2015-03-13 19:15:04 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , string ( newResourceQuota . TypeMeta . Kind ) ) ... )
2015-10-13 21:27:56 +00:00
allErrs = append ( allErrs , validateResourceQuantityValue ( string ( k ) , v ) ... )
2015-03-13 19:15:04 +00:00
}
2015-10-13 21:27:56 +00:00
for k , v := range newResourceQuota . Status . Used {
2015-03-13 19:15:04 +00:00
allErrs = append ( allErrs , validateResourceName ( string ( k ) , string ( newResourceQuota . TypeMeta . Kind ) ) ... )
2015-10-13 21:27:56 +00:00
allErrs = append ( allErrs , validateResourceQuantityValue ( string ( k ) , v ) ... )
2015-03-13 19:15:04 +00:00
}
newResourceQuota . Spec = oldResourceQuota . Spec
return allErrs
}
2015-01-19 21:50:00 +00:00
// ValidateNamespace tests if required fields are set.
2015-11-03 21:38:40 +00:00
func ValidateNamespace ( namespace * api . Namespace ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-01-19 21:50:00 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & namespace . ObjectMeta , false , ValidateNamespaceName ) . Prefix ( "metadata" ) ... )
2015-03-20 16:48:12 +00:00
for i := range namespace . Spec . Finalizers {
allErrs = append ( allErrs , validateFinalizerName ( string ( namespace . Spec . Finalizers [ i ] ) ) ... )
}
2015-01-19 21:50:00 +00:00
return allErrs
}
2015-03-20 16:48:12 +00:00
// Validate finalizer names
2015-11-03 21:38:40 +00:00
func validateFinalizerName ( stringValue string ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-10 22:48:28 +00:00
if ! validation . IsQualifiedName ( stringValue ) {
2015-11-03 21:17:51 +00:00
return append ( allErrs , validation . NewFieldInvalid ( "spec.finalizers" , stringValue , qualifiedNameErrorMsg ) )
2015-03-20 16:48:12 +00:00
}
if len ( strings . Split ( stringValue , "/" ) ) == 1 {
if ! api . IsStandardFinalizerName ( stringValue ) {
2015-11-03 21:17:51 +00:00
return append ( allErrs , validation . NewFieldInvalid ( "spec.finalizers" , stringValue , fmt . Sprintf ( "finalizer name is neither a standard finalizer name nor is it fully qualified" ) ) )
2015-03-20 16:48:12 +00:00
}
}
2015-11-03 21:38:40 +00:00
return validation . ErrorList { }
2015-03-20 16:48:12 +00:00
}
2015-03-31 21:00:04 +00:00
// ValidateNamespaceUpdate tests to make sure a namespace update can be applied.
// newNamespace is updated with fields that cannot be changed
2015-11-03 21:38:40 +00:00
func ValidateNamespaceUpdate ( newNamespace * api . Namespace , oldNamespace * api . Namespace ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newNamespace . ObjectMeta , & oldNamespace . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-03-31 21:00:04 +00:00
newNamespace . Spec . Finalizers = oldNamespace . Spec . Finalizers
newNamespace . Status = oldNamespace . Status
2015-01-19 21:50:00 +00:00
return allErrs
}
2015-03-12 15:08:06 +00:00
// ValidateNamespaceStatusUpdate tests to see if the update is legal for an end user to make. newNamespace is updated with fields
// that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidateNamespaceStatusUpdate ( newNamespace , oldNamespace * api . Namespace ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newNamespace . ObjectMeta , & oldNamespace . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-03-12 15:08:06 +00:00
newNamespace . Spec = oldNamespace . Spec
2015-04-10 15:41:18 +00:00
if newNamespace . DeletionTimestamp . IsZero ( ) {
if newNamespace . Status . Phase != api . NamespaceActive {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "Status.Phase" , newNamespace . Status . Phase , "A namespace may only be in active status if it does not have a deletion timestamp." ) )
2015-04-10 15:41:18 +00:00
}
} else {
if newNamespace . Status . Phase != api . NamespaceTerminating {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "Status.Phase" , newNamespace . Status . Phase , "A namespace may only be in terminating status if it has a deletion timestamp." ) )
2015-04-10 15:41:18 +00:00
}
}
2015-03-12 15:08:06 +00:00
return allErrs
}
2015-03-20 16:48:12 +00:00
2015-03-31 21:00:04 +00:00
// ValidateNamespaceFinalizeUpdate tests to see if the update is legal for an end user to make.
// newNamespace is updated with fields that cannot be changed.
2015-11-03 21:38:40 +00:00
func ValidateNamespaceFinalizeUpdate ( newNamespace , oldNamespace * api . Namespace ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newNamespace . ObjectMeta , & oldNamespace . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-03-20 16:48:12 +00:00
for i := range newNamespace . Spec . Finalizers {
allErrs = append ( allErrs , validateFinalizerName ( string ( newNamespace . Spec . Finalizers [ i ] ) ) ... )
}
newNamespace . Status = oldNamespace . Status
return allErrs
}
2015-03-15 06:03:46 +00:00
// ValidateEndpoints tests if required fields are set.
2015-11-03 21:38:40 +00:00
func ValidateEndpoints ( endpoints * api . Endpoints ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-15 06:03:46 +00:00
allErrs = append ( allErrs , ValidateObjectMeta ( & endpoints . ObjectMeta , true , ValidateEndpointsName ) . Prefix ( "metadata" ) ... )
2015-03-20 21:24:43 +00:00
allErrs = append ( allErrs , validateEndpointSubsets ( endpoints . Subsets ) . Prefix ( "subsets" ) ... )
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateEndpointSubsets ( subsets [ ] api . EndpointSubset ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-20 21:24:43 +00:00
for i := range subsets {
ss := & subsets [ i ]
2015-11-03 21:38:40 +00:00
ssErrs := validation . ErrorList { }
2015-03-20 21:24:43 +00:00
2015-09-22 08:05:21 +00:00
if len ( ss . Addresses ) == 0 && len ( ss . NotReadyAddresses ) == 0 {
2015-11-03 21:17:51 +00:00
ssErrs = append ( ssErrs , validation . NewFieldRequired ( "addresses or notReadyAddresses" ) )
2015-03-20 21:24:43 +00:00
}
if len ( ss . Ports ) == 0 {
2015-11-03 21:17:51 +00:00
ssErrs = append ( ssErrs , validation . NewFieldRequired ( "ports" ) )
2015-03-20 21:24:43 +00:00
}
2015-03-20 14:40:20 +00:00
for addr := range ss . Addresses {
ssErrs = append ( ssErrs , validateEndpointAddress ( & ss . Addresses [ addr ] ) . PrefixIndex ( addr ) . Prefix ( "addresses" ) ... )
}
for port := range ss . Ports {
ssErrs = append ( ssErrs , validateEndpointPort ( & ss . Ports [ port ] , len ( ss . Ports ) > 1 ) . PrefixIndex ( port ) . Prefix ( "ports" ) ... )
}
2015-03-20 21:24:43 +00:00
allErrs = append ( allErrs , ssErrs . PrefixIndex ( i ) ... )
}
2015-03-15 06:03:46 +00:00
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateEndpointAddress ( address * api . EndpointAddress ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-10 22:48:28 +00:00
if ! validation . IsValidIPv4 ( address . IP ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "ip" , address . IP , "invalid IPv4 address" ) )
2015-07-04 04:05:15 +00:00
return allErrs
2015-03-20 14:40:20 +00:00
}
2015-08-12 00:18:21 +00:00
return validateIpIsNotLinkLocalOrLoopback ( address . IP , "ip" )
}
2015-11-03 21:38:40 +00:00
func validateIpIsNotLinkLocalOrLoopback ( ipAddress , fieldName string ) validation . ErrorList {
2015-08-12 00:18:21 +00:00
// We disallow some IPs as endpoints or external-ips. Specifically, loopback addresses are
// nonsensical and link-local addresses tend to be used for node-centric purposes (e.g. metadata service).
2015-11-03 21:38:40 +00:00
allErrs := validation . ErrorList { }
2015-08-12 00:18:21 +00:00
ip := net . ParseIP ( ipAddress )
if ip == nil {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , ipAddress , "not a valid IP address" ) )
2015-08-12 00:18:21 +00:00
return allErrs
}
2015-07-04 04:05:15 +00:00
if ip . IsLoopback ( ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , ipAddress , "may not be in the loopback range (127.0.0.0/8)" ) )
2015-07-04 04:05:15 +00:00
}
if ip . IsLinkLocalUnicast ( ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , ipAddress , "may not be in the link-local range (169.254.0.0/16)" ) )
2015-06-03 04:49:51 +00:00
}
2015-07-04 04:05:15 +00:00
if ip . IsLinkLocalMulticast ( ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( fieldName , ipAddress , "may not be in the link-local multicast range (224.0.0.0/24)" ) )
2015-07-04 04:05:15 +00:00
}
2015-03-20 14:40:20 +00:00
return allErrs
}
2015-11-03 21:38:40 +00:00
func validateEndpointPort ( port * api . EndpointPort , requireName bool ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-03-20 14:40:20 +00:00
if requireName && port . Name == "" {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "name" ) )
2015-03-20 14:40:20 +00:00
} else if port . Name != "" {
2015-09-10 22:48:28 +00:00
if ! validation . IsDNS1123Label ( port . Name ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "name" , port . Name , DNS1123LabelErrorMsg ) )
2015-03-20 14:40:20 +00:00
}
}
2015-09-10 22:48:28 +00:00
if ! validation . IsValidPortNum ( port . Port ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "port" , port . Port , PortRangeErrorMsg ) )
2015-03-20 14:40:20 +00:00
}
if len ( port . Protocol ) == 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldRequired ( "protocol" ) )
2015-06-17 00:28:11 +00:00
} else if ! supportedPortProtocols . Has ( string ( port . Protocol ) ) {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldValueNotSupported ( "protocol" , port . Protocol , supportedPortProtocols . List ( ) ) )
2015-03-20 14:40:20 +00:00
}
return allErrs
}
2015-03-15 06:03:46 +00:00
// ValidateEndpointsUpdate tests to make sure an endpoints update can be applied.
2015-11-03 21:38:40 +00:00
func ValidateEndpointsUpdate ( newEndpoints , oldEndpoints * api . Endpoints ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-06-08 07:56:22 +00:00
allErrs = append ( allErrs , ValidateObjectMetaUpdate ( & newEndpoints . ObjectMeta , & oldEndpoints . ObjectMeta ) . Prefix ( "metadata" ) ... )
2015-03-20 14:40:20 +00:00
allErrs = append ( allErrs , validateEndpointSubsets ( newEndpoints . Subsets ) . Prefix ( "subsets" ) ... )
2015-03-15 06:03:46 +00:00
return allErrs
}
2015-05-05 23:02:13 +00:00
// ValidateSecurityContext ensure the security context contains valid settings
2015-11-03 21:38:40 +00:00
func ValidateSecurityContext ( sc * api . SecurityContext ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-05-05 23:02:13 +00:00
//this should only be true for testing since SecurityContext is defaulted by the api
if sc == nil {
return allErrs
}
if sc . Privileged != nil {
if * sc . Privileged && ! capabilities . Get ( ) . AllowPrivileged {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldForbidden ( "privileged" , sc . Privileged ) )
2015-05-05 23:02:13 +00:00
}
}
if sc . RunAsUser != nil {
if * sc . RunAsUser < 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "runAsUser" , * sc . RunAsUser , "runAsUser cannot be negative" ) )
2015-05-05 23:02:13 +00:00
}
}
return allErrs
}
2015-07-27 19:49:06 +00:00
2015-11-03 21:38:40 +00:00
func ValidatePodLogOptions ( opts * api . PodLogOptions ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-09-10 03:46:11 +00:00
if opts . TailLines != nil && * opts . TailLines < 0 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "tailLines" , * opts . TailLines , "tailLines must be a non-negative integer or nil" ) )
2015-09-10 03:46:11 +00:00
}
if opts . LimitBytes != nil && * opts . LimitBytes < 1 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "limitBytes" , * opts . LimitBytes , "limitBytes must be a positive integer or nil" ) )
2015-09-10 03:46:11 +00:00
}
switch {
case opts . SinceSeconds != nil && opts . SinceTime != nil :
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "sinceSeconds" , * opts . SinceSeconds , "only one of sinceTime or sinceSeconds can be provided" ) )
allErrs = append ( allErrs , validation . NewFieldInvalid ( "sinceTime" , * opts . SinceTime , "only one of sinceTime or sinceSeconds can be provided" ) )
2015-09-10 03:46:11 +00:00
case opts . SinceSeconds != nil :
if * opts . SinceSeconds < 1 {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "sinceSeconds" , * opts . SinceSeconds , "sinceSeconds must be a positive integer" ) )
2015-09-10 03:46:11 +00:00
}
}
return allErrs
}
2015-10-12 19:09:20 +00:00
// ValidateLoadBalancerStatus validates required fields on a LoadBalancerStatus
2015-11-03 21:38:40 +00:00
func ValidateLoadBalancerStatus ( status * api . LoadBalancerStatus ) validation . ErrorList {
allErrs := validation . ErrorList { }
2015-10-12 19:09:20 +00:00
for _ , ingress := range status . Ingress {
if len ( ingress . IP ) > 0 {
if isIP := ( net . ParseIP ( ingress . IP ) != nil ) ; ! isIP {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "ingress.ip" , ingress . IP , "must be an IP address" ) )
2015-10-12 19:09:20 +00:00
}
}
if len ( ingress . Hostname ) > 0 {
if valid , errMsg := NameIsDNSSubdomain ( ingress . Hostname , false ) ; ! valid {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "ingress.hostname" , ingress . Hostname , errMsg ) )
2015-10-12 19:09:20 +00:00
}
if isIP := ( net . ParseIP ( ingress . Hostname ) != nil ) ; isIP {
2015-11-03 21:17:51 +00:00
allErrs = append ( allErrs , validation . NewFieldInvalid ( "ingress.hostname" , ingress . Hostname , "must be a DNS name, not an IP address" ) )
2015-10-12 19:09:20 +00:00
}
}
}
return allErrs
}