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-12 22:13:03 +00:00
"math/rand"
2014-07-01 20:01:39 +00:00
"strings"
"testing"
2015-03-09 16:04:35 +00:00
"time"
2014-07-01 22:14:25 +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/api/testapi"
2015-09-17 22:21:55 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/capabilities"
"k8s.io/kubernetes/pkg/util"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/fielderrors"
errors "k8s.io/kubernetes/pkg/util/fielderrors"
2015-09-09 17:45:01 +00:00
"k8s.io/kubernetes/pkg/util/sets"
2014-07-01 20:01:39 +00:00
)
2015-03-22 21:40:47 +00:00
func expectPrefix ( t * testing . T , prefix string , errs fielderrors . ValidationErrorList ) {
2014-08-20 03:54:20 +00:00
for i := range errs {
2014-11-20 22:11:23 +00:00
if f , p := errs [ i ] . ( * errors . ValidationError ) . Field , prefix ; ! strings . HasPrefix ( f , p ) {
2014-10-07 20:54:41 +00:00
t . Errorf ( "expected prefix '%s' for field '%s' (%v)" , p , f , errs [ i ] )
2014-08-20 03:54:20 +00:00
}
}
}
2015-01-27 23:56:38 +00:00
// Ensure custom name functions are allowed
func TestValidateObjectMetaCustomName ( t * testing . T ) {
errs := ValidateObjectMeta ( & api . ObjectMeta { Name : "test" , GenerateName : "foo" } , false , func ( s string , prefix bool ) ( bool , string ) {
if s == "test" {
return true , ""
}
return false , "name-gen"
} )
if len ( errs ) != 1 {
t . Fatalf ( "unexpected errors: %v" , errs )
}
if ! strings . Contains ( errs [ 0 ] . Error ( ) , "name-gen" ) {
t . Errorf ( "unexpected error message: %v" , errs )
}
}
2015-05-12 22:13:03 +00:00
// Ensure namespace names follow dns label format
func TestValidateObjectMetaNamespaces ( t * testing . T ) {
errs := ValidateObjectMeta ( & api . ObjectMeta { Name : "test" , Namespace : "foo.bar" } , false , func ( s string , prefix bool ) ( bool , string ) {
return true , ""
} )
if len ( errs ) != 1 {
t . Fatalf ( "unexpected errors: %v" , errs )
}
if ! strings . Contains ( errs [ 0 ] . Error ( ) , "invalid value 'foo.bar'" ) {
t . Errorf ( "unexpected error message: %v" , errs )
}
maxLength := 63
letters := [ ] rune ( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" )
b := make ( [ ] rune , maxLength + 1 )
for i := range b {
b [ i ] = letters [ rand . Intn ( len ( letters ) ) ]
}
errs = ValidateObjectMeta ( & api . ObjectMeta { Name : "test" , Namespace : string ( b ) } , false , func ( s string , prefix bool ) ( bool , string ) {
return true , ""
} )
if len ( errs ) != 1 {
t . Fatalf ( "unexpected errors: %v" , errs )
}
if ! strings . Contains ( errs [ 0 ] . Error ( ) , "invalid value" ) {
t . Errorf ( "unexpected error message: %v" , errs )
}
}
2015-03-09 16:04:35 +00:00
func TestValidateObjectMetaUpdateIgnoresCreationTimestamp ( t * testing . T ) {
if errs := ValidateObjectMetaUpdate (
2015-03-20 00:51:07 +00:00
& api . ObjectMeta { Name : "test" , ResourceVersion : "1" } ,
2015-09-17 22:21:55 +00:00
& api . ObjectMeta { Name : "test" , ResourceVersion : "1" , CreationTimestamp : unversioned . NewTime ( time . Unix ( 10 , 0 ) ) } ,
2015-03-09 16:04:35 +00:00
) ; len ( errs ) != 0 {
t . Fatalf ( "unexpected errors: %v" , errs )
}
if errs := ValidateObjectMetaUpdate (
2015-09-17 22:21:55 +00:00
& api . ObjectMeta { Name : "test" , ResourceVersion : "1" , CreationTimestamp : unversioned . NewTime ( time . Unix ( 10 , 0 ) ) } ,
2015-06-08 07:56:22 +00:00
& api . ObjectMeta { Name : "test" , ResourceVersion : "1" } ,
2015-03-09 16:04:35 +00:00
) ; len ( errs ) != 0 {
t . Fatalf ( "unexpected errors: %v" , errs )
}
if errs := ValidateObjectMetaUpdate (
2015-09-17 22:21:55 +00:00
& api . ObjectMeta { Name : "test" , ResourceVersion : "1" , CreationTimestamp : unversioned . NewTime ( time . Unix ( 10 , 0 ) ) } ,
& api . ObjectMeta { Name : "test" , ResourceVersion : "1" , CreationTimestamp : unversioned . NewTime ( time . Unix ( 11 , 0 ) ) } ,
2015-03-09 16:04:35 +00:00
) ; len ( errs ) != 0 {
t . Fatalf ( "unexpected errors: %v" , errs )
}
}
2015-01-27 23:56:38 +00:00
// Ensure trailing slash is allowed in generate name
func TestValidateObjectMetaTrimsTrailingSlash ( t * testing . T ) {
2015-06-09 12:53:30 +00:00
errs := ValidateObjectMeta ( & api . ObjectMeta { Name : "test" , GenerateName : "foo-" } , false , NameIsDNSSubdomain )
2015-01-27 23:56:38 +00:00
if len ( errs ) != 0 {
t . Fatalf ( "unexpected errors: %v" , errs )
}
}
2014-11-20 06:27:11 +00:00
func TestValidateLabels ( t * testing . T ) {
successCases := [ ] map [ string ] string {
{ "simple" : "bar" } ,
{ "now-with-dashes" : "bar" } ,
2014-11-20 06:27:11 +00:00
{ "1-starts-with-num" : "bar" } ,
{ "1234" : "bar" } ,
2014-11-20 06:27:11 +00:00
{ "simple/simple" : "bar" } ,
{ "now-with-dashes/simple" : "bar" } ,
{ "now-with-dashes/now-with-dashes" : "bar" } ,
{ "now.with.dots/simple" : "bar" } ,
{ "now-with.dashes-and.dots/simple" : "bar" } ,
2014-11-20 06:27:11 +00:00
{ "1-num.2-num/3-num" : "bar" } ,
{ "1234/5678" : "bar" } ,
{ "1.2.3.4/5678" : "bar" } ,
2015-02-27 15:08:02 +00:00
{ "UpperCaseAreOK123" : "bar" } ,
2015-03-02 13:41:13 +00:00
{ "goodvalue" : "123_-.BaR" } ,
2014-11-20 06:27:11 +00:00
}
for i := range successCases {
2015-01-20 03:32:39 +00:00
errs := ValidateLabels ( successCases [ i ] , "field" )
2014-11-20 06:27:11 +00:00
if len ( errs ) != 0 {
t . Errorf ( "case[%d] expected success, got %#v" , i , errs )
}
}
2015-02-27 15:08:02 +00:00
labelNameErrorCases := [ ] map [ string ] string {
2014-11-20 06:27:11 +00:00
{ "nospecialchars^=@" : "bar" } ,
{ "cantendwithadash-" : "bar" } ,
2014-11-20 06:27:11 +00:00
{ "only/one/slash" : "bar" } ,
2014-11-20 06:27:11 +00:00
{ strings . Repeat ( "a" , 254 ) : "bar" } ,
2014-11-20 06:27:11 +00:00
}
2015-02-27 15:08:02 +00:00
for i := range labelNameErrorCases {
errs := ValidateLabels ( labelNameErrorCases [ i ] , "field" )
2014-11-20 06:27:11 +00:00
if len ( errs ) != 1 {
t . Errorf ( "case[%d] expected failure" , i )
2015-02-05 00:36:27 +00:00
} else {
detail := errs [ 0 ] . ( * errors . ValidationError ) . Detail
if detail != qualifiedNameErrorMsg {
t . Errorf ( "error detail %s should be equal %s" , detail , qualifiedNameErrorMsg )
}
2014-11-20 06:27:11 +00:00
}
}
2015-02-27 15:08:02 +00:00
labelValueErrorCases := [ ] map [ string ] string {
{ "toolongvalue" : strings . Repeat ( "a" , 64 ) } ,
{ "backslashesinvalue" : "some\\bad\\value" } ,
2015-03-02 13:41:13 +00:00
{ "nocommasallowed" : "bad,value" } ,
2015-02-27 15:08:02 +00:00
{ "strangecharsinvalue" : "?#$notsogood" } ,
}
for i := range labelValueErrorCases {
errs := ValidateLabels ( labelValueErrorCases [ i ] , "field" )
if len ( errs ) != 1 {
t . Errorf ( "case[%d] expected failure" , i )
} else {
detail := errs [ 0 ] . ( * errors . ValidationError ) . Detail
if detail != labelValueErrorMsg {
t . Errorf ( "error detail %s should be equal %s" , detail , labelValueErrorMsg )
}
}
}
2014-11-20 06:27:11 +00:00
}
2015-02-02 00:03:04 +00:00
func TestValidateAnnotations ( t * testing . T ) {
successCases := [ ] map [ string ] string {
{ "simple" : "bar" } ,
{ "now-with-dashes" : "bar" } ,
{ "1-starts-with-num" : "bar" } ,
{ "1234" : "bar" } ,
{ "simple/simple" : "bar" } ,
{ "now-with-dashes/simple" : "bar" } ,
{ "now-with-dashes/now-with-dashes" : "bar" } ,
{ "now.with.dots/simple" : "bar" } ,
{ "now-with.dashes-and.dots/simple" : "bar" } ,
{ "1-num.2-num/3-num" : "bar" } ,
{ "1234/5678" : "bar" } ,
{ "1.2.3.4/5678" : "bar" } ,
{ "UpperCase123" : "bar" } ,
2015-03-02 13:41:13 +00:00
{ "a" : strings . Repeat ( "b" , ( 64 * 1024 ) - 1 ) } ,
{
"a" : strings . Repeat ( "b" , ( 32 * 1024 ) - 1 ) ,
"c" : strings . Repeat ( "d" , ( 32 * 1024 ) - 1 ) ,
} ,
2015-02-02 00:03:04 +00:00
}
for i := range successCases {
errs := ValidateAnnotations ( successCases [ i ] , "field" )
if len ( errs ) != 0 {
t . Errorf ( "case[%d] expected success, got %#v" , i , errs )
}
}
2015-03-02 13:41:13 +00:00
2015-02-27 15:08:02 +00:00
nameErrorCases := [ ] map [ string ] string {
2015-02-02 00:03:04 +00:00
{ "nospecialchars^=@" : "bar" } ,
{ "cantendwithadash-" : "bar" } ,
{ "only/one/slash" : "bar" } ,
{ strings . Repeat ( "a" , 254 ) : "bar" } ,
}
2015-02-27 15:08:02 +00:00
for i := range nameErrorCases {
errs := ValidateAnnotations ( nameErrorCases [ i ] , "field" )
if len ( errs ) != 1 {
t . Errorf ( "case[%d] expected failure" , i )
}
detail := errs [ 0 ] . ( * errors . ValidationError ) . Detail
if detail != qualifiedNameErrorMsg {
t . Errorf ( "error detail %s should be equal %s" , detail , qualifiedNameErrorMsg )
}
}
2015-03-02 13:41:13 +00:00
totalSizeErrorCases := [ ] map [ string ] string {
{ "a" : strings . Repeat ( "b" , 64 * 1024 ) } ,
{
"a" : strings . Repeat ( "b" , 32 * 1024 ) ,
"c" : strings . Repeat ( "d" , 32 * 1024 ) ,
} ,
2015-02-27 15:08:02 +00:00
}
2015-03-02 13:41:13 +00:00
for i := range totalSizeErrorCases {
errs := ValidateAnnotations ( totalSizeErrorCases [ i ] , "field" )
2015-02-02 00:03:04 +00:00
if len ( errs ) != 1 {
t . Errorf ( "case[%d] expected failure" , i )
}
}
}
2015-03-23 18:18:11 +00:00
func testVolume ( name string , namespace string , spec api . PersistentVolumeSpec ) * api . PersistentVolume {
objMeta := api . ObjectMeta { Name : name }
if namespace != "" {
objMeta . Namespace = namespace
}
return & api . PersistentVolume {
ObjectMeta : objMeta ,
Spec : spec ,
}
}
func TestValidatePersistentVolumes ( t * testing . T ) {
scenarios := map [ string ] struct {
isExpectedFailure bool
volume * api . PersistentVolume
} {
"good-volume" : {
isExpectedFailure : false ,
volume : testVolume ( "foo" , "" , api . PersistentVolumeSpec {
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode { api . ReadWriteOnce } ,
2015-03-23 18:18:11 +00:00
PersistentVolumeSource : api . PersistentVolumeSource {
HostPath : & api . HostPathVolumeSource { Path : "/foo" } ,
} ,
} ) ,
} ,
2015-07-24 19:55:54 +00:00
"invalid-accessmode" : {
isExpectedFailure : true ,
volume : testVolume ( "foo" , "" , api . PersistentVolumeSpec {
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
AccessModes : [ ] api . PersistentVolumeAccessMode { "fakemode" } ,
PersistentVolumeSource : api . PersistentVolumeSource {
HostPath : & api . HostPathVolumeSource { Path : "/foo" } ,
} ,
} ) ,
} ,
2015-03-23 18:18:11 +00:00
"unexpected-namespace" : {
isExpectedFailure : true ,
volume : testVolume ( "foo" , "unexpected-namespace" , api . PersistentVolumeSpec {
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode { api . ReadWriteOnce } ,
2015-03-23 18:18:11 +00:00
PersistentVolumeSource : api . PersistentVolumeSource {
HostPath : & api . HostPathVolumeSource { Path : "/foo" } ,
} ,
} ) ,
} ,
"bad-name" : {
isExpectedFailure : true ,
volume : testVolume ( "123*Bad(Name" , "unexpected-namespace" , api . PersistentVolumeSpec {
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode { api . ReadWriteOnce } ,
2015-03-23 18:18:11 +00:00
PersistentVolumeSource : api . PersistentVolumeSource {
HostPath : & api . HostPathVolumeSource { Path : "/foo" } ,
} ,
2015-05-13 00:44:29 +00:00
} ) ,
2015-03-23 18:18:11 +00:00
} ,
"missing-name" : {
isExpectedFailure : true ,
volume : testVolume ( "" , "" , api . PersistentVolumeSpec {
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode { api . ReadWriteOnce } ,
2015-03-23 18:18:11 +00:00
} ) ,
} ,
"missing-capacity" : {
isExpectedFailure : true ,
volume : testVolume ( "foo" , "" , api . PersistentVolumeSpec { } ) ,
} ,
2015-05-13 00:44:29 +00:00
"missing-accessmodes" : {
isExpectedFailure : true ,
volume : testVolume ( "goodname" , "missing-accessmodes" , api . PersistentVolumeSpec {
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
PersistentVolumeSource : api . PersistentVolumeSource {
HostPath : & api . HostPathVolumeSource { Path : "/foo" } ,
} ,
} ) ,
} ,
2015-03-23 18:18:11 +00:00
"too-many-sources" : {
isExpectedFailure : true ,
volume : testVolume ( "" , "" , api . PersistentVolumeSpec {
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "5G" ) ,
} ,
PersistentVolumeSource : api . PersistentVolumeSource {
HostPath : & api . HostPathVolumeSource { Path : "/foo" } ,
GCEPersistentDisk : & api . GCEPersistentDiskVolumeSource { PDName : "foo" , FSType : "ext4" } ,
} ,
} ) ,
} ,
}
for name , scenario := range scenarios {
errs := ValidatePersistentVolume ( scenario . volume )
if len ( errs ) == 0 && scenario . isExpectedFailure {
t . Errorf ( "Unexpected success for scenario: %s" , name )
}
if len ( errs ) > 0 && ! scenario . isExpectedFailure {
t . Errorf ( "Unexpected failure for scenario: %s - %+v" , name , errs )
}
}
}
func testVolumeClaim ( name string , namespace string , spec api . PersistentVolumeClaimSpec ) * api . PersistentVolumeClaim {
return & api . PersistentVolumeClaim {
ObjectMeta : api . ObjectMeta { Name : name , Namespace : namespace } ,
Spec : spec ,
}
}
func TestValidatePersistentVolumeClaim ( t * testing . T ) {
scenarios := map [ string ] struct {
isExpectedFailure bool
claim * api . PersistentVolumeClaim
} {
"good-claim" : {
isExpectedFailure : false ,
claim : testVolumeClaim ( "foo" , "ns" , api . PersistentVolumeClaimSpec {
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode {
2015-03-23 18:18:11 +00:00
api . ReadWriteOnce ,
api . ReadOnlyMany ,
} ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
2015-07-24 19:55:54 +00:00
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
} ,
} ) ,
} ,
"invalid-accessmode" : {
isExpectedFailure : true ,
claim : testVolumeClaim ( "foo" , "ns" , api . PersistentVolumeClaimSpec {
AccessModes : [ ] api . PersistentVolumeAccessMode { "fakemode" } ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
2015-03-23 18:18:11 +00:00
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
} ,
} ) ,
} ,
"missing-namespace" : {
isExpectedFailure : true ,
claim : testVolumeClaim ( "foo" , "" , api . PersistentVolumeClaimSpec {
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode {
2015-03-23 18:18:11 +00:00
api . ReadWriteOnce ,
api . ReadOnlyMany ,
} ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
} ,
} ) ,
} ,
"no-access-modes" : {
isExpectedFailure : true ,
claim : testVolumeClaim ( "foo" , "ns" , api . PersistentVolumeClaimSpec {
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
api . ResourceName ( api . ResourceStorage ) : resource . MustParse ( "10G" ) ,
} ,
} ,
} ) ,
} ,
"no-resource-requests" : {
isExpectedFailure : true ,
claim : testVolumeClaim ( "foo" , "ns" , api . PersistentVolumeClaimSpec {
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode {
2015-03-23 18:18:11 +00:00
api . ReadWriteOnce ,
} ,
} ) ,
} ,
2015-03-31 15:37:09 +00:00
"invalid-resource-requests" : {
isExpectedFailure : true ,
claim : testVolumeClaim ( "foo" , "ns" , api . PersistentVolumeClaimSpec {
2015-05-18 20:22:30 +00:00
AccessModes : [ ] api . PersistentVolumeAccessMode {
2015-03-31 15:37:09 +00:00
api . ReadWriteOnce ,
} ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
} ) ,
} ,
2015-03-23 18:18:11 +00:00
}
for name , scenario := range scenarios {
errs := ValidatePersistentVolumeClaim ( scenario . claim )
if len ( errs ) == 0 && scenario . isExpectedFailure {
t . Errorf ( "Unexpected success for scenario: %s" , name )
}
if len ( errs ) > 0 && ! scenario . isExpectedFailure {
t . Errorf ( "Unexpected failure for scenario: %s - %+v" , name , errs )
}
}
}
2014-07-01 21:40:36 +00:00
func TestValidateVolumes ( t * testing . T ) {
2015-08-11 15:19:29 +00:00
lun := 1
2014-08-30 01:20:27 +00:00
successCase := [ ] api . Volume {
2015-08-08 01:52:23 +00:00
{ Name : "abc" , VolumeSource : api . VolumeSource { HostPath : & api . HostPathVolumeSource { Path : "/mnt/path1" } } } ,
{ Name : "123" , VolumeSource : api . VolumeSource { HostPath : & api . HostPathVolumeSource { Path : "/mnt/path2" } } } ,
{ Name : "abc-123" , VolumeSource : api . VolumeSource { HostPath : & api . HostPathVolumeSource { Path : "/mnt/path3" } } } ,
2015-03-03 22:48:55 +00:00
{ Name : "empty" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } ,
2015-08-08 01:52:23 +00:00
{ Name : "gcepd" , VolumeSource : api . VolumeSource { GCEPersistentDisk : & api . GCEPersistentDiskVolumeSource { PDName : "my-PD" , FSType : "ext4" , Partition : 1 , ReadOnly : false } } } ,
{ Name : "awsebs" , VolumeSource : api . VolumeSource { AWSElasticBlockStore : & api . AWSElasticBlockStoreVolumeSource { VolumeID : "my-PD" , FSType : "ext4" , Partition : 1 , ReadOnly : false } } } ,
{ Name : "gitrepo" , VolumeSource : api . VolumeSource { GitRepo : & api . GitRepoVolumeSource { Repository : "my-repo" , Revision : "hashstring" } } } ,
{ Name : "iscsidisk" , VolumeSource : api . VolumeSource { ISCSI : & api . ISCSIVolumeSource { TargetPortal : "127.0.0.1" , IQN : "iqn.2015-02.example.com:test" , Lun : 1 , FSType : "ext4" , ReadOnly : false } } } ,
{ Name : "secret" , VolumeSource : api . VolumeSource { Secret : & api . SecretVolumeSource { SecretName : "my-secret" } } } ,
{ Name : "glusterfs" , VolumeSource : api . VolumeSource { Glusterfs : & api . GlusterfsVolumeSource { EndpointsName : "host1" , Path : "path" , ReadOnly : false } } } ,
2015-09-25 19:22:23 +00:00
{ Name : "flocker" , VolumeSource : api . VolumeSource { Flocker : & api . FlockerVolumeSource { DatasetName : "datasetName" } } } ,
2015-04-07 17:22:23 +00:00
{ Name : "rbd" , VolumeSource : api . VolumeSource { RBD : & api . RBDVolumeSource { CephMonitors : [ ] string { "foo" } , RBDImage : "bar" , FSType : "ext4" } } } ,
2015-04-10 16:54:01 +00:00
{ Name : "cinder" , VolumeSource : api . VolumeSource { Cinder : & api . CinderVolumeSource { "29ea5088-4f60-4757-962e-dba678767887" , "ext4" , false } } } ,
2015-04-09 18:05:24 +00:00
{ Name : "cephfs" , VolumeSource : api . VolumeSource { CephFS : & api . CephFSVolumeSource { Monitors : [ ] string { "foo" } } } } ,
2015-02-20 05:36:23 +00:00
{ Name : "downwardapi" , VolumeSource : api . VolumeSource { DownwardAPI : & api . DownwardAPIVolumeSource { Items : [ ] api . DownwardAPIVolumeFile {
{ Path : "labels" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } ,
{ Path : "annotations" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.annotations" } } ,
{ Path : "namespace" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.namespace" } } ,
{ Path : "name" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.name" } } ,
{ Path : "path/withslash/andslash" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } ,
{ Path : "path/./withdot" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } ,
{ Path : "path/with..dot" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } ,
{ Path : "second-level-dirent-can-have/..dot" , FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } ,
} } } } ,
2015-08-11 15:19:29 +00:00
{ Name : "fc" , VolumeSource : api . VolumeSource { FC : & api . FCVolumeSource { [ ] string { "some_wwn" } , & lun , "ext4" , false } } } ,
2014-07-01 21:40:36 +00:00
}
2014-07-08 06:20:30 +00:00
names , errs := validateVolumes ( successCase )
if len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
2014-07-01 21:40:36 +00:00
}
2015-08-11 15:19:29 +00:00
if len ( names ) != len ( successCase ) || ! names . HasAll ( "abc" , "123" , "abc-123" , "empty" , "gcepd" , "gitrepo" , "secret" , "iscsidisk" , "cinder" , "cephfs" , "fc" ) {
2014-07-01 21:40:36 +00:00
t . Errorf ( "wrong names result: %v" , names )
}
2015-02-20 06:27:27 +00:00
emptyVS := api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } }
2015-08-08 01:52:23 +00:00
emptyPortal := api . VolumeSource { ISCSI : & api . ISCSIVolumeSource { TargetPortal : "" , IQN : "iqn.2015-02.example.com:test" , Lun : 1 , FSType : "ext4" , ReadOnly : false } }
emptyIQN := api . VolumeSource { ISCSI : & api . ISCSIVolumeSource { TargetPortal : "127.0.0.1" , IQN : "" , Lun : 1 , FSType : "ext4" , ReadOnly : false } }
emptyHosts := api . VolumeSource { Glusterfs : & api . GlusterfsVolumeSource { EndpointsName : "" , Path : "path" , ReadOnly : false } }
emptyPath := api . VolumeSource { Glusterfs : & api . GlusterfsVolumeSource { EndpointsName : "host" , Path : "" , ReadOnly : false } }
2015-09-25 19:22:23 +00:00
emptyName := api . VolumeSource { Flocker : & api . FlockerVolumeSource { DatasetName : "" } }
2015-04-07 17:22:23 +00:00
emptyMon := api . VolumeSource { RBD : & api . RBDVolumeSource { CephMonitors : [ ] string { } , RBDImage : "bar" , FSType : "ext4" } }
emptyImage := api . VolumeSource { RBD : & api . RBDVolumeSource { CephMonitors : [ ] string { "foo" } , RBDImage : "" , FSType : "ext4" } }
2015-04-09 18:05:24 +00:00
emptyCephFSMon := api . VolumeSource { CephFS : & api . CephFSVolumeSource { Monitors : [ ] string { } } }
2015-02-20 05:36:23 +00:00
emptyPathName := api . VolumeSource { DownwardAPI : & api . DownwardAPIVolumeSource { Items : [ ] api . DownwardAPIVolumeFile { { Path : "" ,
FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } } ,
} }
absolutePathName := api . VolumeSource { DownwardAPI : & api . DownwardAPIVolumeSource { Items : [ ] api . DownwardAPIVolumeFile { { Path : "/absolutepath" ,
FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } } ,
} }
dotDotInPath := api . VolumeSource { DownwardAPI : & api . DownwardAPIVolumeSource { Items : [ ] api . DownwardAPIVolumeFile { { Path : "../../passwd" ,
FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } } ,
} }
dotDotPathName := api . VolumeSource { DownwardAPI : & api . DownwardAPIVolumeSource { Items : [ ] api . DownwardAPIVolumeFile { { Path : "..badFileName" ,
FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } } ,
} }
dotDotFirstLevelDirent := api . VolumeSource { DownwardAPI : & api . DownwardAPIVolumeSource { Items : [ ] api . DownwardAPIVolumeFile { { Path : "..badDirName/goodFileName" ,
FieldRef : api . ObjectFieldSelector {
APIVersion : "v1" ,
FieldPath : "metadata.labels" } } } ,
} }
2015-08-11 15:19:29 +00:00
zeroWWN := api . VolumeSource { FC : & api . FCVolumeSource { [ ] string { } , & lun , "ext4" , false } }
emptyLun := api . VolumeSource { FC : & api . FCVolumeSource { [ ] string { "wwn" } , nil , "ext4" , false } }
2015-09-25 19:22:23 +00:00
slashInName := api . VolumeSource { Flocker : & api . FlockerVolumeSource { DatasetName : "foo/bar" } }
2014-08-20 03:54:20 +00:00
errorCases := map [ string ] struct {
2014-08-30 01:20:27 +00:00
V [ ] api . Volume
2014-08-20 03:54:20 +00:00
T errors . ValidationErrorType
F string
2015-02-20 05:36:23 +00:00
D string
2014-08-20 03:54:20 +00:00
} {
2015-09-25 19:22:23 +00:00
"zero-length name" : { [ ] api . Volume { { Name : "" , VolumeSource : emptyVS } } , errors . ValidationErrorTypeRequired , "[0].name" , "" } ,
"name > 63 characters" : { [ ] api . Volume { { Name : strings . Repeat ( "a" , 64 ) , VolumeSource : emptyVS } } , errors . ValidationErrorTypeInvalid , "[0].name" , "must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. \"my-name\"" } ,
"name not a DNS label" : { [ ] api . Volume { { Name : "a.b.c" , VolumeSource : emptyVS } } , errors . ValidationErrorTypeInvalid , "[0].name" , "must be a DNS label (at most 63 characters, matching regex [a-z0-9]([-a-z0-9]*[a-z0-9])?): e.g. \"my-name\"" } ,
"name not unique" : { [ ] api . Volume { { Name : "abc" , VolumeSource : emptyVS } , { Name : "abc" , VolumeSource : emptyVS } } , errors . ValidationErrorTypeDuplicate , "[1].name" , "" } ,
"empty portal" : { [ ] api . Volume { { Name : "badportal" , VolumeSource : emptyPortal } } , errors . ValidationErrorTypeRequired , "[0].source.iscsi.targetPortal" , "" } ,
"empty iqn" : { [ ] api . Volume { { Name : "badiqn" , VolumeSource : emptyIQN } } , errors . ValidationErrorTypeRequired , "[0].source.iscsi.iqn" , "" } ,
"empty hosts" : { [ ] api . Volume { { Name : "badhost" , VolumeSource : emptyHosts } } , errors . ValidationErrorTypeRequired , "[0].source.glusterfs.endpoints" , "" } ,
"empty path" : { [ ] api . Volume { { Name : "badpath" , VolumeSource : emptyPath } } , errors . ValidationErrorTypeRequired , "[0].source.glusterfs.path" , "" } ,
"empty datasetName" : { [ ] api . Volume { { Name : "badname" , VolumeSource : emptyName } } , errors . ValidationErrorTypeRequired , "[0].source.flocker.datasetName" , "" } ,
"empty mon" : { [ ] api . Volume { { Name : "badmon" , VolumeSource : emptyMon } } , errors . ValidationErrorTypeRequired , "[0].source.rbd.monitors" , "" } ,
"empty image" : { [ ] api . Volume { { Name : "badimage" , VolumeSource : emptyImage } } , errors . ValidationErrorTypeRequired , "[0].source.rbd.image" , "" } ,
"empty cephfs mon" : { [ ] api . Volume { { Name : "badmon" , VolumeSource : emptyCephFSMon } } , errors . ValidationErrorTypeRequired , "[0].source.cephfs.monitors" , "" } ,
"empty metatada path" : { [ ] api . Volume { { Name : "emptyname" , VolumeSource : emptyPathName } } , errors . ValidationErrorTypeRequired , "[0].source.downwardApi.path" , "" } ,
"absolute path" : { [ ] api . Volume { { Name : "absolutepath" , VolumeSource : absolutePathName } } , errors . ValidationErrorTypeForbidden , "[0].source.downwardApi.path" , "" } ,
"dot dot path" : { [ ] api . Volume { { Name : "dotdotpath" , VolumeSource : dotDotInPath } } , errors . ValidationErrorTypeInvalid , "[0].source.downwardApi.path" , "must not contain \"..\"." } ,
"dot dot file name" : { [ ] api . Volume { { Name : "dotdotfilename" , VolumeSource : dotDotPathName } } , errors . ValidationErrorTypeInvalid , "[0].source.downwardApi.path" , "must not start with \"..\"." } ,
"dot dot first level dirent" : { [ ] api . Volume { { Name : "dotdotdirfilename" , VolumeSource : dotDotFirstLevelDirent } } , errors . ValidationErrorTypeInvalid , "[0].source.downwardApi.path" , "must not start with \"..\"." } ,
"empty wwn" : { [ ] api . Volume { { Name : "badimage" , VolumeSource : zeroWWN } } , errors . ValidationErrorTypeRequired , "[0].source.fc.targetWWNs" , "" } ,
"empty lun" : { [ ] api . Volume { { Name : "badimage" , VolumeSource : emptyLun } } , errors . ValidationErrorTypeRequired , "[0].source.fc.lun" , "" } ,
"slash in datasetName" : { [ ] api . Volume { { Name : "slashinname" , VolumeSource : slashInName } } , errors . ValidationErrorTypeInvalid , "[0].source.flocker.datasetName" , "must not contain '/'" } ,
2014-07-01 21:40:36 +00:00
}
for k , v := range errorCases {
2014-08-20 03:54:20 +00:00
_ , errs := validateVolumes ( v . V )
if len ( errs ) == 0 {
2014-10-10 22:34:48 +00:00
t . Errorf ( "expected failure %s for %v" , k , v . V )
2014-08-20 03:54:20 +00:00
continue
}
for i := range errs {
2014-11-20 22:11:23 +00:00
if errs [ i ] . ( * errors . ValidationError ) . Type != v . T {
2014-08-20 03:54:20 +00:00
t . Errorf ( "%s: expected errors to have type %s: %v" , k , v . T , errs [ i ] )
}
2014-11-20 22:11:23 +00:00
if errs [ i ] . ( * errors . ValidationError ) . Field != v . F {
2014-08-20 03:54:20 +00:00
t . Errorf ( "%s: expected errors to have field %s: %v" , k , v . F , errs [ i ] )
}
2015-02-05 00:36:27 +00:00
detail := errs [ i ] . ( * errors . ValidationError ) . Detail
2015-02-20 05:36:23 +00:00
if detail != v . D {
t . Errorf ( "%s: expected error detail \"%s\", got \"%s\"" , k , v . D , detail )
2015-02-05 00:36:27 +00:00
}
2014-07-01 22:56:30 +00:00
}
}
}
2014-07-08 04:32:56 +00:00
func TestValidatePorts ( t * testing . T ) {
2015-02-23 22:25:56 +00:00
successCase := [ ] api . ContainerPort {
2014-07-08 04:32:56 +00:00
{ Name : "abc" , ContainerPort : 80 , HostPort : 80 , Protocol : "TCP" } ,
{ Name : "easy" , ContainerPort : 82 , Protocol : "TCP" } ,
{ Name : "as" , ContainerPort : 83 , Protocol : "UDP" } ,
2015-01-26 17:52:50 +00:00
{ Name : "do-re-me" , ContainerPort : 84 , Protocol : "UDP" } ,
{ ContainerPort : 85 , Protocol : "TCP" } ,
2014-07-08 04:32:56 +00:00
}
2014-07-08 06:20:30 +00:00
if errs := validatePorts ( successCase ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
2014-07-08 04:32:56 +00:00
}
2015-02-23 22:25:56 +00:00
nonCanonicalCase := [ ] api . ContainerPort {
2015-01-26 17:52:50 +00:00
{ ContainerPort : 80 , Protocol : "TCP" } ,
2014-07-08 04:32:56 +00:00
}
2014-07-08 06:20:30 +00:00
if errs := validatePorts ( nonCanonicalCase ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
2014-07-08 04:32:56 +00:00
}
2014-08-20 03:54:20 +00:00
errorCases := map [ string ] struct {
2015-02-23 22:25:56 +00:00
P [ ] api . ContainerPort
2014-08-20 03:54:20 +00:00
T errors . ValidationErrorType
F string
2015-02-05 00:36:27 +00:00
D string
2014-08-20 03:54:20 +00:00
} {
2015-06-12 16:33:11 +00:00
"name > 15 characters" : { [ ] api . ContainerPort { { Name : strings . Repeat ( "a" , 16 ) , ContainerPort : 80 , Protocol : "TCP" } } , errors . ValidationErrorTypeInvalid , "[0].name" , portNameErrorMsg } ,
"name not a IANA svc name " : { [ ] api . ContainerPort { { Name : "a.b.c" , ContainerPort : 80 , Protocol : "TCP" } } , errors . ValidationErrorTypeInvalid , "[0].name" , portNameErrorMsg } ,
"name not a IANA svc name (i.e. a number)" : { [ ] api . ContainerPort { { Name : "80" , ContainerPort : 80 , Protocol : "TCP" } } , errors . ValidationErrorTypeInvalid , "[0].name" , portNameErrorMsg } ,
2015-02-23 22:25:56 +00:00
"name not unique" : { [ ] api . ContainerPort {
2015-01-26 17:52:50 +00:00
{ Name : "abc" , ContainerPort : 80 , Protocol : "TCP" } ,
{ Name : "abc" , ContainerPort : 81 , Protocol : "TCP" } ,
2015-02-05 00:36:27 +00:00
} , errors . ValidationErrorTypeDuplicate , "[1].name" , "" } ,
2015-02-23 22:25:56 +00:00
"zero container port" : { [ ] api . ContainerPort { { ContainerPort : 0 , Protocol : "TCP" } } , errors . ValidationErrorTypeInvalid , "[0].containerPort" , portRangeErrorMsg } ,
"invalid container port" : { [ ] api . ContainerPort { { ContainerPort : 65536 , Protocol : "TCP" } } , errors . ValidationErrorTypeInvalid , "[0].containerPort" , portRangeErrorMsg } ,
"invalid host port" : { [ ] api . ContainerPort { { ContainerPort : 80 , HostPort : 65536 , Protocol : "TCP" } } , errors . ValidationErrorTypeInvalid , "[0].hostPort" , portRangeErrorMsg } ,
2015-06-24 22:09:43 +00:00
"invalid protocol case" : { [ ] api . ContainerPort { { ContainerPort : 80 , Protocol : "tcp" } } , errors . ValidationErrorTypeNotSupported , "[0].protocol" , "supported values: TCP, UDP" } ,
"invalid protocol" : { [ ] api . ContainerPort { { ContainerPort : 80 , Protocol : "ICMP" } } , errors . ValidationErrorTypeNotSupported , "[0].protocol" , "supported values: TCP, UDP" } ,
2015-02-23 22:25:56 +00:00
"protocol required" : { [ ] api . ContainerPort { { Name : "abc" , ContainerPort : 80 } } , errors . ValidationErrorTypeRequired , "[0].protocol" , "" } ,
2014-07-08 04:32:56 +00:00
}
for k , v := range errorCases {
2014-08-20 03:54:20 +00:00
errs := validatePorts ( v . P )
if len ( errs ) == 0 {
2014-07-08 04:32:56 +00:00
t . Errorf ( "expected failure for %s" , k )
}
2014-08-20 03:54:20 +00:00
for i := range errs {
2014-11-20 22:11:23 +00:00
if errs [ i ] . ( * errors . ValidationError ) . Type != v . T {
2014-08-20 03:54:20 +00:00
t . Errorf ( "%s: expected errors to have type %s: %v" , k , v . T , errs [ i ] )
}
2014-11-20 22:11:23 +00:00
if errs [ i ] . ( * errors . ValidationError ) . Field != v . F {
2014-08-20 03:54:20 +00:00
t . Errorf ( "%s: expected errors to have field %s: %v" , k , v . F , errs [ i ] )
}
2015-02-05 00:36:27 +00:00
detail := errs [ i ] . ( * errors . ValidationError ) . Detail
if detail != v . D {
t . Errorf ( "%s: expected error detail either empty or %s, got %s" , k , v . D , detail )
}
2014-08-20 03:54:20 +00:00
}
2014-07-08 04:32:56 +00:00
}
}
2014-07-01 22:56:30 +00:00
func TestValidateEnv ( t * testing . T ) {
2014-08-30 01:20:27 +00:00
successCase := [ ] api . EnvVar {
2014-07-01 22:56:30 +00:00
{ Name : "abc" , Value : "value" } ,
{ Name : "ABC" , Value : "value" } ,
{ Name : "AbC_123" , Value : "value" } ,
{ Name : "abc" , Value : "" } ,
2015-04-23 20:57:30 +00:00
{
Name : "abc" ,
ValueFrom : & api . EnvVarSource {
2015-05-04 17:31:36 +00:00
FieldRef : & api . ObjectFieldSelector {
2015-09-04 07:06:01 +00:00
APIVersion : testapi . Default . Version ( ) ,
2015-04-23 20:57:30 +00:00
FieldPath : "metadata.name" ,
} ,
} ,
} ,
2014-07-01 22:56:30 +00:00
}
2014-07-08 06:20:30 +00:00
if errs := validateEnv ( successCase ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
2014-07-01 22:56:30 +00:00
}
2015-04-23 20:57:30 +00:00
errorCases := [ ] struct {
name string
envs [ ] api . EnvVar
expectedError string
} {
{
name : "zero-length name" ,
envs : [ ] api . EnvVar { { Name : "" } } ,
expectedError : "[0].name: required value" ,
} ,
{
name : "name not a C identifier" ,
envs : [ ] api . EnvVar { { Name : "a.b.c" } } ,
2015-07-31 23:43:39 +00:00
expectedError : ` [0].name: invalid value 'a.b.c', Details: must be a C identifier (matching regex [A-Za-z_][A-Za-z0-9_]*): e.g. "my_name" or "MyName" ` ,
2015-04-23 20:57:30 +00:00
} ,
{
name : "value and valueFrom specified" ,
envs : [ ] api . EnvVar { {
Name : "abc" ,
Value : "foo" ,
ValueFrom : & api . EnvVarSource {
2015-05-04 17:31:36 +00:00
FieldRef : & api . ObjectFieldSelector {
2015-09-04 07:06:01 +00:00
APIVersion : testapi . Default . Version ( ) ,
2015-04-23 20:57:30 +00:00
FieldPath : "metadata.name" ,
} ,
} ,
} } ,
2015-07-31 23:43:39 +00:00
expectedError : "[0].valueFrom: invalid value '', Details: sources cannot be specified when value is not empty" ,
2015-04-23 20:57:30 +00:00
} ,
{
name : "missing FieldPath on ObjectFieldSelector" ,
envs : [ ] api . EnvVar { {
Name : "abc" ,
ValueFrom : & api . EnvVarSource {
2015-05-04 17:31:36 +00:00
FieldRef : & api . ObjectFieldSelector {
2015-09-04 07:06:01 +00:00
APIVersion : testapi . Default . Version ( ) ,
2015-04-23 20:57:30 +00:00
} ,
} ,
} } ,
2015-05-04 17:31:36 +00:00
expectedError : "[0].valueFrom.fieldRef.fieldPath: required value" ,
2015-04-23 20:57:30 +00:00
} ,
{
name : "missing APIVersion on ObjectFieldSelector" ,
envs : [ ] api . EnvVar { {
Name : "abc" ,
ValueFrom : & api . EnvVarSource {
2015-05-04 17:31:36 +00:00
FieldRef : & api . ObjectFieldSelector {
2015-04-23 20:57:30 +00:00
FieldPath : "metadata.name" ,
} ,
} ,
} } ,
2015-05-04 17:31:36 +00:00
expectedError : "[0].valueFrom.fieldRef.apiVersion: required value" ,
2015-04-23 20:57:30 +00:00
} ,
{
name : "invalid fieldPath" ,
envs : [ ] api . EnvVar { {
Name : "abc" ,
ValueFrom : & api . EnvVarSource {
2015-05-04 17:31:36 +00:00
FieldRef : & api . ObjectFieldSelector {
2015-04-23 20:57:30 +00:00
FieldPath : "metadata.whoops" ,
2015-09-04 07:06:01 +00:00
APIVersion : testapi . Default . Version ( ) ,
2015-04-23 20:57:30 +00:00
} ,
} ,
} } ,
2015-07-31 23:43:39 +00:00
expectedError : "[0].valueFrom.fieldRef.fieldPath: invalid value 'metadata.whoops', Details: error converting fieldPath" ,
2015-04-23 20:57:30 +00:00
} ,
2015-02-20 05:36:23 +00:00
{
name : "invalid fieldPath labels" ,
envs : [ ] api . EnvVar { {
Name : "labels" ,
ValueFrom : & api . EnvVarSource {
FieldRef : & api . ObjectFieldSelector {
FieldPath : "metadata.labels" ,
APIVersion : "v1" ,
} ,
} ,
} } ,
expectedError : "[0].valueFrom.fieldRef.fieldPath: unsupported value 'metadata.labels', Details: supported values: metadata.name, metadata.namespace, status.podIP" ,
} ,
{
name : "invalid fieldPath annotations" ,
envs : [ ] api . EnvVar { {
Name : "abc" ,
ValueFrom : & api . EnvVarSource {
FieldRef : & api . ObjectFieldSelector {
FieldPath : "metadata.annotations" ,
APIVersion : "v1" ,
} ,
} ,
} } ,
expectedError : "[0].valueFrom.fieldRef.fieldPath: unsupported value 'metadata.annotations', Details: supported values: metadata.name, metadata.namespace, status.podIP" ,
} ,
2015-04-23 20:57:30 +00:00
{
name : "unsupported fieldPath" ,
envs : [ ] api . EnvVar { {
Name : "abc" ,
ValueFrom : & api . EnvVarSource {
2015-05-04 17:31:36 +00:00
FieldRef : & api . ObjectFieldSelector {
2015-04-23 20:57:30 +00:00
FieldPath : "status.phase" ,
2015-09-04 07:06:01 +00:00
APIVersion : testapi . Default . Version ( ) ,
2015-04-23 20:57:30 +00:00
} ,
} ,
} } ,
2015-08-12 18:14:49 +00:00
expectedError : "[0].valueFrom.fieldRef.fieldPath: unsupported value 'status.phase', Details: supported values: metadata.name, metadata.namespace, status.podIP" ,
2015-04-23 20:57:30 +00:00
} ,
2014-07-01 22:56:30 +00:00
}
2015-04-23 20:57:30 +00:00
for _ , tc := range errorCases {
if errs := validateEnv ( tc . envs ) ; len ( errs ) == 0 {
t . Errorf ( "expected failure for %s" , tc . name )
2015-02-05 00:36:27 +00:00
} else {
for i := range errs {
2015-04-23 20:57:30 +00:00
str := errs [ i ] . ( * errors . ValidationError ) . Error ( )
if str != "" && str != tc . expectedError {
t . Errorf ( "%s: expected error detail either empty or %s, got %s" , tc . name , tc . expectedError , str )
2015-02-05 00:36:27 +00:00
}
}
2014-07-01 21:40:36 +00:00
}
}
}
2014-07-05 02:46:56 +00:00
func TestValidateVolumeMounts ( t * testing . T ) {
2015-09-09 17:45:01 +00:00
volumes := sets . NewString ( "abc" , "123" , "abc-123" )
2014-07-05 02:46:56 +00:00
2014-08-30 01:20:27 +00:00
successCase := [ ] api . VolumeMount {
2014-07-05 02:46:56 +00:00
{ Name : "abc" , MountPath : "/foo" } ,
{ Name : "123" , MountPath : "/foo" } ,
{ Name : "abc-123" , MountPath : "/bar" } ,
}
2014-07-08 06:20:30 +00:00
if errs := validateVolumeMounts ( successCase , volumes ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
2014-07-05 02:46:56 +00:00
}
2014-08-30 01:20:27 +00:00
errorCases := map [ string ] [ ] api . VolumeMount {
2014-07-05 02:46:56 +00:00
"empty name" : { { Name : "" , MountPath : "/foo" } } ,
"name not found" : { { Name : "" , MountPath : "/foo" } } ,
"empty mountpath" : { { Name : "abc" , MountPath : "" } } ,
}
for k , v := range errorCases {
2014-07-08 06:20:30 +00:00
if errs := validateVolumeMounts ( v , volumes ) ; len ( errs ) == 0 {
2014-07-05 02:46:56 +00:00
t . Errorf ( "expected failure for %s" , k )
}
}
}
2015-02-15 07:02:07 +00:00
func TestValidateProbe ( t * testing . T ) {
handler := api . Handler { Exec : & api . ExecAction { Command : [ ] string { "echo" } } }
successCases := [ ] * api . Probe {
nil ,
{ TimeoutSeconds : 10 , InitialDelaySeconds : 0 , Handler : handler } ,
{ TimeoutSeconds : 0 , InitialDelaySeconds : 10 , Handler : handler } ,
}
for _ , p := range successCases {
if errs := validateProbe ( p ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
errorCases := [ ] * api . Probe {
{ TimeoutSeconds : 10 , InitialDelaySeconds : 10 } ,
{ TimeoutSeconds : 10 , InitialDelaySeconds : - 10 , Handler : handler } ,
{ TimeoutSeconds : - 10 , InitialDelaySeconds : 10 , Handler : handler } ,
{ TimeoutSeconds : - 10 , InitialDelaySeconds : - 10 , Handler : handler } ,
}
for _ , p := range errorCases {
if errs := validateProbe ( p ) ; len ( errs ) == 0 {
t . Errorf ( "expected failure for %v" , p )
}
}
}
2015-02-28 01:33:58 +00:00
func TestValidateHandler ( t * testing . T ) {
successCases := [ ] api . Handler {
{ Exec : & api . ExecAction { Command : [ ] string { "echo" } } } ,
2015-06-25 17:53:41 +00:00
{ HTTPGet : & api . HTTPGetAction { Path : "/" , Port : util . NewIntOrStringFromInt ( 1 ) , Host : "" , Scheme : "HTTP" } } ,
{ HTTPGet : & api . HTTPGetAction { Path : "/foo" , Port : util . NewIntOrStringFromInt ( 65535 ) , Host : "host" , Scheme : "HTTP" } } ,
{ HTTPGet : & api . HTTPGetAction { Path : "/" , Port : util . NewIntOrStringFromString ( "port" ) , Host : "" , Scheme : "HTTP" } } ,
2015-02-28 01:33:58 +00:00
}
for _ , h := range successCases {
if errs := validateHandler ( & h ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
errorCases := [ ] api . Handler {
{ } ,
{ Exec : & api . ExecAction { Command : [ ] string { } } } ,
{ HTTPGet : & api . HTTPGetAction { Path : "" , Port : util . NewIntOrStringFromInt ( 0 ) , Host : "" } } ,
{ HTTPGet : & api . HTTPGetAction { Path : "/foo" , Port : util . NewIntOrStringFromInt ( 65536 ) , Host : "host" } } ,
{ HTTPGet : & api . HTTPGetAction { Path : "" , Port : util . NewIntOrStringFromString ( "" ) , Host : "" } } ,
}
for _ , h := range errorCases {
if errs := validateHandler ( & h ) ; len ( errs ) == 0 {
t . Errorf ( "expected failure for %#v" , h )
}
}
}
2015-01-16 23:02:36 +00:00
func TestValidatePullPolicy ( t * testing . T ) {
type T struct {
Container api . Container
ExpectedPolicy api . PullPolicy
}
testCases := map [ string ] T {
"NotPresent1" : {
2015-01-21 04:30:42 +00:00
api . Container { Name : "abc" , Image : "image:latest" , ImagePullPolicy : "IfNotPresent" } ,
2015-01-16 23:02:36 +00:00
api . PullIfNotPresent ,
} ,
"NotPresent2" : {
2015-01-21 04:30:42 +00:00
api . Container { Name : "abc1" , Image : "image" , ImagePullPolicy : "IfNotPresent" } ,
2015-01-16 23:02:36 +00:00
api . PullIfNotPresent ,
} ,
"Always1" : {
2015-01-21 04:30:42 +00:00
api . Container { Name : "123" , Image : "image:latest" , ImagePullPolicy : "Always" } ,
2015-01-16 23:02:36 +00:00
api . PullAlways ,
} ,
"Always2" : {
2015-01-21 04:30:42 +00:00
api . Container { Name : "1234" , Image : "image" , ImagePullPolicy : "Always" } ,
2015-01-16 23:02:36 +00:00
api . PullAlways ,
} ,
"Never1" : {
2015-01-21 04:30:42 +00:00
api . Container { Name : "abc-123" , Image : "image:latest" , ImagePullPolicy : "Never" } ,
2015-01-16 23:02:36 +00:00
api . PullNever ,
} ,
"Never2" : {
2015-01-21 04:30:42 +00:00
api . Container { Name : "abc-1234" , Image : "image" , ImagePullPolicy : "Never" } ,
2015-01-16 23:02:36 +00:00
api . PullNever ,
} ,
}
for k , v := range testCases {
ctr := & v . Container
2015-01-26 17:52:50 +00:00
errs := validatePullPolicy ( ctr )
2015-01-16 23:02:36 +00:00
if len ( errs ) != 0 {
t . Errorf ( "case[%s] expected success, got %#v" , k , errs )
}
if ctr . ImagePullPolicy != v . ExpectedPolicy {
t . Errorf ( "case[%s] expected policy %v, got %v" , k , v . ExpectedPolicy , ctr . ImagePullPolicy )
}
}
}
2015-01-25 04:19:36 +00:00
func getResourceLimits ( cpu , memory string ) api . ResourceList {
res := api . ResourceList { }
res [ api . ResourceCPU ] = resource . MustParse ( cpu )
res [ api . ResourceMemory ] = resource . MustParse ( memory )
return res
}
2014-07-01 22:14:25 +00:00
func TestValidateContainers ( t * testing . T ) {
2015-09-09 17:45:01 +00:00
volumes := sets . String { }
2014-09-16 22:18:33 +00:00
capabilities . SetForTests ( capabilities . Capabilities {
2014-09-16 14:04:12 +00:00
AllowPrivileged : true ,
} )
2014-07-01 22:14:25 +00:00
2014-08-30 01:20:27 +00:00
successCase := [ ] api . Container {
2015-01-26 17:52:50 +00:00
{ Name : "abc" , Image : "image" , ImagePullPolicy : "IfNotPresent" } ,
{ Name : "123" , Image : "image" , ImagePullPolicy : "IfNotPresent" } ,
{ Name : "abc-123" , Image : "image" , ImagePullPolicy : "IfNotPresent" } ,
2014-09-12 23:04:10 +00:00
{
Name : "life-123" ,
Image : "image" ,
Lifecycle : & api . Lifecycle {
PreStop : & api . Handler {
Exec : & api . ExecAction { Command : [ ] string { "ls" , "-l" } } ,
} ,
} ,
2015-01-26 17:52:50 +00:00
ImagePullPolicy : "IfNotPresent" ,
2014-09-12 23:04:10 +00:00
} ,
2015-01-25 04:19:36 +00:00
{
Name : "resources-test" ,
Image : "image" ,
2015-02-09 22:44:32 +00:00
Resources : api . ResourceRequirements {
2015-01-25 04:19:36 +00:00
Limits : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
api . ResourceName ( "my.org/resource" ) : resource . MustParse ( "10m" ) ,
} ,
} ,
2015-01-26 17:52:50 +00:00
ImagePullPolicy : "IfNotPresent" ,
2015-01-25 04:19:36 +00:00
} ,
2015-07-30 19:59:22 +00:00
{
Name : "resources-request-limit-simple" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "8" ) ,
} ,
Limits : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
} ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
{
Name : "resources-request-limit-edge" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
api . ResourceName ( "my.org/resource" ) : resource . MustParse ( "10m" ) ,
} ,
Limits : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
api . ResourceName ( "my.org/resource" ) : resource . MustParse ( "10m" ) ,
} ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
{
Name : "resources-request-limit-partials" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "9.5" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
Limits : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( "my.org/resource" ) : resource . MustParse ( "10m" ) ,
} ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
{
Name : "resources-request" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "9.5" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
2015-05-19 05:18:40 +00:00
{
Name : "same-host-port-different-protocol" ,
Image : "image" ,
Ports : [ ] api . ContainerPort {
{ ContainerPort : 80 , HostPort : 80 , Protocol : "TCP" } ,
{ ContainerPort : 80 , HostPort : 80 , Protocol : "UDP" } ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
2015-05-05 23:02:13 +00:00
{ Name : "abc-1234" , Image : "image" , ImagePullPolicy : "IfNotPresent" , SecurityContext : fakeValidSecurityContext ( true ) } ,
2014-07-01 22:14:25 +00:00
}
2014-07-08 06:20:30 +00:00
if errs := validateContainers ( successCase , volumes ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
2014-07-01 22:14:25 +00:00
}
2014-09-16 22:18:33 +00:00
capabilities . SetForTests ( capabilities . Capabilities {
2014-09-16 14:04:12 +00:00
AllowPrivileged : false ,
} )
2014-08-30 01:20:27 +00:00
errorCases := map [ string ] [ ] api . Container {
2015-02-04 23:44:46 +00:00
"zero-length name" : { { Name : "" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
"name > 63 characters" : { { Name : strings . Repeat ( "a" , 64 ) , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
"name not a DNS label" : { { Name : "a.b.c" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2014-07-01 22:14:25 +00:00
"name not unique" : {
2015-02-04 23:44:46 +00:00
{ Name : "abc" , Image : "image" , ImagePullPolicy : "IfNotPresent" } ,
{ Name : "abc" , Image : "image" , ImagePullPolicy : "IfNotPresent" } ,
2014-07-01 22:14:25 +00:00
} ,
2015-02-04 23:44:46 +00:00
"zero-length image" : { { Name : "abc" , Image : "" , ImagePullPolicy : "IfNotPresent" } } ,
2014-07-08 04:32:56 +00:00
"host port not unique" : {
2015-02-23 22:25:56 +00:00
{ Name : "abc" , Image : "image" , Ports : [ ] api . ContainerPort { { ContainerPort : 80 , HostPort : 80 , Protocol : "TCP" } } ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" } ,
2015-02-23 22:25:56 +00:00
{ Name : "def" , Image : "image" , Ports : [ ] api . ContainerPort { { ContainerPort : 81 , HostPort : 80 , Protocol : "TCP" } } ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" } ,
2014-07-08 04:32:56 +00:00
} ,
2014-07-01 22:56:30 +00:00
"invalid env var name" : {
2015-02-04 23:44:46 +00:00
{ Name : "abc" , Image : "image" , Env : [ ] api . EnvVar { { Name : "ev.1" } } , ImagePullPolicy : "IfNotPresent" } ,
2014-07-01 22:56:30 +00:00
} ,
2014-07-05 02:46:56 +00:00
"unknown volume name" : {
2015-02-04 23:44:46 +00:00
{ Name : "abc" , Image : "image" , VolumeMounts : [ ] api . VolumeMount { { Name : "anything" , MountPath : "/foo" } } ,
ImagePullPolicy : "IfNotPresent" } ,
2014-07-05 02:46:56 +00:00
} ,
2014-09-12 23:04:10 +00:00
"invalid lifecycle, no exec command." : {
{
Name : "life-123" ,
Image : "image" ,
Lifecycle : & api . Lifecycle {
PreStop : & api . Handler {
Exec : & api . ExecAction { } ,
} ,
} ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" ,
2014-09-12 23:04:10 +00:00
} ,
} ,
"invalid lifecycle, no http path." : {
{
Name : "life-123" ,
Image : "image" ,
Lifecycle : & api . Lifecycle {
PreStop : & api . Handler {
HTTPGet : & api . HTTPGetAction { } ,
} ,
} ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" ,
2014-09-12 23:04:10 +00:00
} ,
} ,
2015-02-27 03:20:34 +00:00
"invalid lifecycle, no tcp socket port." : {
{
Name : "life-123" ,
Image : "image" ,
Lifecycle : & api . Lifecycle {
PreStop : & api . Handler {
TCPSocket : & api . TCPSocketAction { } ,
} ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
} ,
"invalid lifecycle, zero tcp socket port." : {
{
Name : "life-123" ,
Image : "image" ,
Lifecycle : & api . Lifecycle {
PreStop : & api . Handler {
TCPSocket : & api . TCPSocketAction {
Port : util . IntOrString { IntVal : 0 } ,
} ,
} ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
} ,
2014-09-12 23:04:10 +00:00
"invalid lifecycle, no action." : {
{
Name : "life-123" ,
Image : "image" ,
Lifecycle : & api . Lifecycle {
PreStop : & api . Handler { } ,
} ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" ,
2014-09-12 23:04:10 +00:00
} ,
} ,
2015-02-27 03:20:34 +00:00
"invalid liveness probe, no tcp socket port." : {
{
Name : "life-123" ,
Image : "image" ,
LivenessProbe : & api . Probe {
Handler : api . Handler {
TCPSocket : & api . TCPSocketAction { } ,
} ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
} ,
"invalid liveness probe, no action." : {
{
Name : "life-123" ,
Image : "image" ,
LivenessProbe : & api . Probe {
Handler : api . Handler { } ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
} ,
2014-09-16 14:04:12 +00:00
"privilege disabled" : {
2015-05-05 23:02:13 +00:00
{ Name : "abc" , Image : "image" , SecurityContext : fakeValidSecurityContext ( true ) } ,
2014-09-16 14:04:12 +00:00
} ,
2015-01-25 04:19:36 +00:00
"invalid compute resource" : {
{
Name : "abc-123" ,
Image : "image" ,
2015-02-09 22:44:32 +00:00
Resources : api . ResourceRequirements {
2015-01-25 04:19:36 +00:00
Limits : api . ResourceList {
"disk" : resource . MustParse ( "10G" ) ,
} ,
} ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" ,
2015-01-25 04:19:36 +00:00
} ,
} ,
"Resource CPU invalid" : {
{
Name : "abc-123" ,
Image : "image" ,
2015-02-09 22:44:32 +00:00
Resources : api . ResourceRequirements {
2015-01-25 04:19:36 +00:00
Limits : getResourceLimits ( "-10" , "0" ) ,
} ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" ,
2015-01-25 04:19:36 +00:00
} ,
} ,
2015-04-20 18:56:15 +00:00
"Resource Requests CPU invalid" : {
{
Name : "abc-123" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Requests : getResourceLimits ( "-10" , "0" ) ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
} ,
2015-01-25 04:19:36 +00:00
"Resource Memory invalid" : {
{
Name : "abc-123" ,
Image : "image" ,
2015-02-09 22:44:32 +00:00
Resources : api . ResourceRequirements {
2015-01-25 04:19:36 +00:00
Limits : getResourceLimits ( "0" , "-10" ) ,
} ,
2015-02-04 23:44:46 +00:00
ImagePullPolicy : "IfNotPresent" ,
2015-01-25 04:19:36 +00:00
} ,
} ,
2015-07-30 19:59:22 +00:00
"Request limit simple invalid" : {
{
Name : "abc-123" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Limits : getResourceLimits ( "5" , "3" ) ,
Requests : getResourceLimits ( "6" , "3" ) ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
} ,
"Request limit multiple invalid" : {
{
Name : "abc-123" ,
Image : "image" ,
Resources : api . ResourceRequirements {
Limits : getResourceLimits ( "5" , "3" ) ,
Requests : getResourceLimits ( "6" , "4" ) ,
} ,
ImagePullPolicy : "IfNotPresent" ,
} ,
} ,
2014-07-01 22:14:25 +00:00
}
for k , v := range errorCases {
2014-07-08 06:20:30 +00:00
if errs := validateContainers ( v , volumes ) ; len ( errs ) == 0 {
2014-07-01 22:14:25 +00:00
t . Errorf ( "expected failure for %s" , k )
}
}
}
2014-08-26 18:25:17 +00:00
func TestValidateRestartPolicy ( t * testing . T ) {
successCases := [ ] api . RestartPolicy {
2015-03-14 01:38:07 +00:00
api . RestartPolicyAlways ,
api . RestartPolicyOnFailure ,
api . RestartPolicyNever ,
2014-08-26 18:25:17 +00:00
}
for _ , policy := range successCases {
if errs := validateRestartPolicy ( & policy ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
2015-03-14 01:38:07 +00:00
errorCases := [ ] api . RestartPolicy { "" , "newpolicy" }
2014-08-26 18:25:17 +00:00
for k , policy := range errorCases {
if errs := validateRestartPolicy ( & policy ) ; len ( errs ) == 0 {
2014-10-10 00:06:32 +00:00
t . Errorf ( "expected failure for %d" , k )
2014-08-26 18:25:17 +00:00
}
}
2015-01-06 19:11:52 +00:00
}
2014-08-26 18:25:17 +00:00
2015-01-06 19:11:52 +00:00
func TestValidateDNSPolicy ( t * testing . T ) {
2015-01-26 17:52:50 +00:00
successCases := [ ] api . DNSPolicy { api . DNSClusterFirst , api . DNSDefault , api . DNSPolicy ( api . DNSClusterFirst ) }
2015-01-06 19:11:52 +00:00
for _ , policy := range successCases {
if errs := validateDNSPolicy ( & policy ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
errorCases := [ ] api . DNSPolicy { api . DNSPolicy ( "invalid" ) }
for _ , policy := range errorCases {
if errs := validateDNSPolicy ( & policy ) ; len ( errs ) == 0 {
t . Errorf ( "expected failure for %v" , policy )
}
}
2014-08-26 18:25:17 +00:00
}
2015-01-06 19:11:52 +00:00
func TestValidatePodSpec ( t * testing . T ) {
2015-05-09 05:01:43 +00:00
activeDeadlineSeconds := int64 ( 30 )
2015-01-06 19:11:52 +00:00
successCases := [ ] api . PodSpec {
{ // Populate basic fields, leave defaults for most.
2015-03-03 22:48:55 +00:00
Volumes : [ ] api . Volume { { Name : "vol" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } } ,
2015-01-26 17:52:50 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-01-26 17:52:50 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-01-06 19:11:52 +00:00
} ,
{ // Populate all fields.
Volumes : [ ] api . Volume {
2015-03-03 22:48:55 +00:00
{ Name : "vol" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } ,
2015-01-06 19:11:52 +00:00
} ,
2015-01-26 17:52:50 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-01-06 19:11:52 +00:00
NodeSelector : map [ string ] string {
"key" : "value" ,
2014-10-23 20:51:34 +00:00
} ,
2015-05-22 23:40:57 +00:00
NodeName : "foobar" ,
2015-05-09 05:01:43 +00:00
DNSPolicy : api . DNSClusterFirst ,
ActiveDeadlineSeconds : & activeDeadlineSeconds ,
2015-06-19 02:35:42 +00:00
ServiceAccountName : "acct" ,
2015-01-06 19:11:52 +00:00
} ,
2015-03-23 23:34:35 +00:00
{ // Populate HostNetwork.
Containers : [ ] api . Container {
{ Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" , Ports : [ ] api . ContainerPort {
{ HostPort : 8080 , ContainerPort : 8080 , Protocol : "TCP" } } ,
} ,
} ,
2015-09-14 21:56:51 +00:00
SecurityContext : & api . PodSecurityContext {
HostNetwork : true ,
} ,
2015-03-23 23:34:35 +00:00
RestartPolicy : api . RestartPolicyAlways ,
DNSPolicy : api . DNSClusterFirst ,
} ,
2015-09-21 15:34:02 +00:00
{ // Populate HostIPC.
2015-09-14 21:56:51 +00:00
SecurityContext : & api . PodSecurityContext {
HostIPC : true ,
} ,
2015-09-21 15:34:02 +00:00
Volumes : [ ] api . Volume { { Name : "vol" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } } ,
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
RestartPolicy : api . RestartPolicyAlways ,
DNSPolicy : api . DNSClusterFirst ,
} ,
{ // Populate HostPID.
2015-09-14 21:56:51 +00:00
SecurityContext : & api . PodSecurityContext {
HostPID : true ,
} ,
2015-09-21 15:34:02 +00:00
Volumes : [ ] api . Volume { { Name : "vol" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } } ,
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
RestartPolicy : api . RestartPolicyAlways ,
DNSPolicy : api . DNSClusterFirst ,
} ,
2015-01-06 19:11:52 +00:00
}
for i := range successCases {
if errs := ValidatePodSpec ( & successCases [ i ] ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
2015-05-09 05:01:43 +00:00
activeDeadlineSeconds = int64 ( 0 )
2015-01-06 19:11:52 +00:00
failureCases := map [ string ] api . PodSpec {
"bad volume" : {
2015-02-04 23:44:46 +00:00
Volumes : [ ] api . Volume { { } } ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
} ,
"no containers" : {
RestartPolicy : api . RestartPolicyAlways ,
DNSPolicy : api . DNSClusterFirst ,
2014-07-22 18:45:12 +00:00
} ,
2015-01-06 19:11:52 +00:00
"bad container" : {
2015-02-04 23:44:46 +00:00
Containers : [ ] api . Container { { } } ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-01-06 19:11:52 +00:00
} ,
"bad DNS policy" : {
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSPolicy ( "invalid" ) ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-02-04 23:44:46 +00:00
} ,
2015-06-11 21:16:58 +00:00
"bad service account name" : {
2015-06-19 02:35:42 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
RestartPolicy : api . RestartPolicyAlways ,
DNSPolicy : api . DNSClusterFirst ,
ServiceAccountName : "invalidName" ,
2015-06-11 21:16:58 +00:00
} ,
2015-02-04 23:44:46 +00:00
"bad restart policy" : {
2015-03-14 01:38:07 +00:00
RestartPolicy : "UnknowPolicy" ,
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-01-06 19:11:52 +00:00
} ,
2015-03-23 23:34:35 +00:00
"with hostNetwork hostPort not equal to containerPort" : {
Containers : [ ] api . Container {
{ Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" , Ports : [ ] api . ContainerPort {
{ HostPort : 8080 , ContainerPort : 2600 , Protocol : "TCP" } } ,
} ,
} ,
2015-09-14 21:56:51 +00:00
SecurityContext : & api . PodSecurityContext {
HostNetwork : true ,
} ,
2015-03-23 23:34:35 +00:00
RestartPolicy : api . RestartPolicyAlways ,
DNSPolicy : api . DNSClusterFirst ,
} ,
2015-05-09 05:01:43 +00:00
"bad-active-deadline-seconds" : {
Volumes : [ ] api . Volume {
{ Name : "vol" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } ,
} ,
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
RestartPolicy : api . RestartPolicyAlways ,
NodeSelector : map [ string ] string {
"key" : "value" ,
} ,
2015-05-22 23:40:57 +00:00
NodeName : "foobar" ,
2015-05-09 05:01:43 +00:00
DNSPolicy : api . DNSClusterFirst ,
ActiveDeadlineSeconds : & activeDeadlineSeconds ,
} ,
2015-01-06 19:11:52 +00:00
}
for k , v := range failureCases {
if errs := ValidatePodSpec ( & v ) ; len ( errs ) == 0 {
t . Errorf ( "expected failure for %q" , k )
}
}
}
func TestValidatePod ( t * testing . T ) {
successCases := [ ] api . Pod {
{ // Basic fields.
ObjectMeta : api . ObjectMeta { Name : "123" , Namespace : "ns" } ,
Spec : api . PodSpec {
2015-03-03 22:48:55 +00:00
Volumes : [ ] api . Volume { { Name : "vol" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } } ,
2015-01-26 17:52:50 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-01-26 17:52:50 +00:00
DNSPolicy : api . DNSClusterFirst ,
2014-08-26 18:25:17 +00:00
} ,
2014-07-22 18:45:12 +00:00
} ,
2015-01-06 19:11:52 +00:00
{ // Just about everything.
ObjectMeta : api . ObjectMeta { Name : "abc.123.do-re-mi" , Namespace : "ns" } ,
Spec : api . PodSpec {
Volumes : [ ] api . Volume {
2015-03-03 22:48:55 +00:00
{ Name : "vol" , VolumeSource : api . VolumeSource { EmptyDir : & api . EmptyDirVolumeSource { } } } ,
2015-01-06 19:11:52 +00:00
} ,
2015-01-26 17:52:50 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-01-06 19:11:52 +00:00
DNSPolicy : api . DNSClusterFirst ,
NodeSelector : map [ string ] string {
"key" : "value" ,
} ,
2015-05-22 23:40:57 +00:00
NodeName : "foobar" ,
2014-10-23 20:51:34 +00:00
} ,
2014-07-22 18:45:12 +00:00
} ,
2015-01-06 19:11:52 +00:00
}
for _ , pod := range successCases {
if errs := ValidatePod ( & pod ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
2014-07-22 18:45:12 +00:00
}
2015-01-06 19:11:52 +00:00
errorCases := map [ string ] api . Pod {
2015-02-04 23:44:46 +00:00
"bad name" : {
ObjectMeta : api . ObjectMeta { Name : "" , Namespace : "ns" } ,
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-02-04 23:44:46 +00:00
} ,
} ,
"bad namespace" : {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "" } ,
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-02-04 23:44:46 +00:00
} ,
} ,
2015-01-06 19:11:52 +00:00
"bad spec" : {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "ns" } ,
Spec : api . PodSpec {
Containers : [ ] api . Container { { } } ,
2014-10-23 20:14:13 +00:00
} ,
} ,
2015-01-24 14:36:22 +00:00
"bad label" : {
ObjectMeta : api . ObjectMeta {
Name : "abc" ,
Namespace : "ns" ,
Labels : map [ string ] string {
"NoUppercaseOrSpecialCharsLike=Equals" : "bar" ,
} ,
} ,
2015-02-04 23:44:46 +00:00
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-02-04 23:44:46 +00:00
} ,
2015-01-24 14:36:22 +00:00
} ,
2015-01-06 19:11:52 +00:00
}
for k , v := range errorCases {
if errs := ValidatePod ( & v ) ; len ( errs ) == 0 {
2015-03-18 15:00:18 +00:00
t . Errorf ( "expected failure for %q" , k )
2015-01-06 19:11:52 +00:00
}
2014-10-23 20:14:13 +00:00
}
2014-07-22 18:45:12 +00:00
}
2014-10-10 03:30:34 +00:00
func TestValidatePodUpdate ( t * testing . T ) {
2015-09-17 22:21:55 +00:00
now := unversioned . Now ( )
2015-08-19 23:59:43 +00:00
grace := int64 ( 30 )
grace2 := int64 ( 31 )
2014-10-10 03:30:34 +00:00
tests := [ ] struct {
a api . Pod
b api . Pod
isValid bool
test string
} {
{ api . Pod { } , api . Pod { } , true , "nothing" } ,
{
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-10-10 03:30:34 +00:00
} ,
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "bar" } ,
2014-10-10 03:30:34 +00:00
} ,
false ,
"ids" ,
} ,
{
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string {
"foo" : "bar" ,
} ,
2014-10-10 03:30:34 +00:00
} ,
} ,
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string {
"bar" : "foo" ,
} ,
2014-10-10 03:30:34 +00:00
} ,
} ,
true ,
"labels" ,
} ,
2015-01-24 14:36:22 +00:00
{
api . Pod {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Annotations : map [ string ] string {
"foo" : "bar" ,
} ,
} ,
} ,
api . Pod {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Annotations : map [ string ] string {
"bar" : "foo" ,
} ,
} ,
} ,
true ,
"annotations" ,
} ,
2014-10-10 03:30:34 +00:00
{
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V1" ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V2" ,
} ,
{
Image : "bar:V2" ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
false ,
"more containers" ,
} ,
{
api . Pod {
2015-08-19 23:59:43 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" , DeletionTimestamp : & now } ,
Spec : api . PodSpec { Containers : [ ] api . Container { { Image : "foo:V1" } } } ,
} ,
api . Pod {
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
Spec : api . PodSpec { Containers : [ ] api . Container { { Image : "foo:V1" } } } ,
} ,
true ,
"deletion timestamp filled out" ,
} ,
{
api . Pod {
ObjectMeta : api . ObjectMeta { Name : "foo" , DeletionTimestamp : & now , DeletionGracePeriodSeconds : & grace } ,
Spec : api . PodSpec { Containers : [ ] api . Container { { Image : "foo:V1" } } } ,
} ,
api . Pod {
ObjectMeta : api . ObjectMeta { Name : "foo" , DeletionTimestamp : & now , DeletionGracePeriodSeconds : & grace2 } ,
Spec : api . PodSpec { Containers : [ ] api . Container { { Image : "foo:V1" } } } ,
} ,
false ,
"deletion grace period seconds cleared" ,
} ,
2014-10-10 03:30:34 +00:00
{
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V1" ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V2" ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
true ,
"image change" ,
} ,
{
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V1" ,
2015-02-09 22:44:32 +00:00
Resources : api . ResourceRequirements {
2015-01-25 04:19:36 +00:00
Limits : getResourceLimits ( "100m" , "0" ) ,
} ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V2" ,
2015-02-09 22:44:32 +00:00
Resources : api . ResourceRequirements {
2015-01-25 04:19:36 +00:00
Limits : getResourceLimits ( "1000m" , "0" ) ,
} ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
false ,
"cpu change" ,
} ,
{
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V1" ,
2015-02-23 22:25:56 +00:00
Ports : [ ] api . ContainerPort {
2014-11-13 15:52:13 +00:00
{ HostPort : 8080 , ContainerPort : 80 } ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
} ,
api . Pod {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "foo" } ,
2014-11-13 15:52:13 +00:00
Spec : api . PodSpec {
Containers : [ ] api . Container {
{
Image : "foo:V2" ,
2015-02-23 22:25:56 +00:00
Ports : [ ] api . ContainerPort {
2014-11-13 15:52:13 +00:00
{ HostPort : 8000 , ContainerPort : 80 } ,
2014-10-10 03:30:34 +00:00
} ,
} ,
} ,
} ,
} ,
false ,
"port change" ,
} ,
2015-02-04 22:21:34 +00:00
{
api . Pod {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string {
"foo" : "bar" ,
} ,
} ,
} ,
api . Pod {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string {
"Bar" : "foo" ,
} ,
} ,
} ,
true ,
"bad label change" ,
} ,
2014-10-10 03:30:34 +00:00
}
for _ , test := range tests {
2015-03-20 00:51:07 +00:00
test . a . ObjectMeta . ResourceVersion = "1"
test . b . ObjectMeta . ResourceVersion = "1"
2014-10-10 03:30:34 +00:00
errs := ValidatePodUpdate ( & test . a , & test . b )
if test . isValid {
if len ( errs ) != 0 {
t . Errorf ( "unexpected invalid: %s %v, %v" , test . test , test . a , test . b )
}
} else {
if len ( errs ) == 0 {
t . Errorf ( "unexpected valid: %s %v, %v" , test . test , test . a , test . b )
}
}
}
}
2015-03-31 18:13:44 +00:00
func makeValidService ( ) api . Service {
return api . Service {
ObjectMeta : api . ObjectMeta {
Name : "valid" ,
Namespace : "valid" ,
Labels : map [ string ] string { } ,
Annotations : map [ string ] string { } ,
ResourceVersion : "1" ,
} ,
Spec : api . ServiceSpec {
Selector : map [ string ] string { "key" : "val" } ,
SessionAffinity : "None" ,
2015-05-22 21:49:26 +00:00
Type : api . ServiceTypeClusterIP ,
2015-06-12 16:33:11 +00:00
Ports : [ ] api . ServicePort { { Name : "p" , Protocol : "TCP" , Port : 8675 , TargetPort : util . NewIntOrStringFromInt ( 8675 ) } } ,
2015-03-31 18:13:44 +00:00
} ,
}
}
2014-07-10 19:45:01 +00:00
func TestValidateService ( t * testing . T ) {
2014-09-10 16:41:31 +00:00
testCases := [ ] struct {
2015-03-31 18:13:44 +00:00
name string
tweakSvc func ( svc * api . Service ) // given a basic valid service, each test case can customize it
numErrs int
2014-09-10 16:41:31 +00:00
} {
{
2015-03-08 05:40:18 +00:00
name : "missing namespace" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Namespace = ""
2015-01-26 17:52:50 +00:00
} ,
numErrs : 1 ,
} ,
{
2015-03-08 05:40:18 +00:00
name : "invalid namespace" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Namespace = "-123"
2015-01-26 17:52:50 +00:00
} ,
numErrs : 1 ,
} ,
{
2015-03-08 05:40:18 +00:00
name : "missing name" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Name = ""
2014-09-10 16:41:31 +00:00
} ,
numErrs : 1 ,
2014-07-10 19:45:01 +00:00
} ,
2014-09-29 21:18:18 +00:00
{
2015-03-08 05:40:18 +00:00
name : "invalid name" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Name = "-123"
2014-09-29 21:18:18 +00:00
} ,
numErrs : 1 ,
} ,
2014-09-10 16:41:31 +00:00
{
2015-03-08 05:40:18 +00:00
name : "too long name" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Name = strings . Repeat ( "a" , 25 )
2014-09-10 16:41:31 +00:00
} ,
numErrs : 1 ,
2014-08-22 21:44:21 +00:00
} ,
2015-01-27 23:56:38 +00:00
{
2015-03-08 05:40:18 +00:00
name : "invalid generateName" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . GenerateName = "-123"
2015-01-27 23:56:38 +00:00
} ,
numErrs : 1 ,
} ,
{
2015-03-08 05:40:18 +00:00
name : "too long generateName" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . GenerateName = strings . Repeat ( "a" , 25 )
2015-01-27 23:56:38 +00:00
} ,
numErrs : 1 ,
} ,
2014-09-10 16:41:31 +00:00
{
2015-03-08 05:40:18 +00:00
name : "invalid label" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Labels [ "NoUppercaseOrSpecialCharsLike=Equals" ] = "bar"
2014-09-10 16:41:31 +00:00
} ,
numErrs : 1 ,
} ,
{
2015-03-08 05:40:18 +00:00
name : "invalid annotation" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Annotations [ "NoSpecialCharsLike=Equals" ] = "bar"
2014-09-10 16:41:31 +00:00
} ,
numErrs : 1 ,
} ,
2015-03-13 15:16:41 +00:00
{
name : "nil selector" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Selector = nil
} ,
numErrs : 0 ,
} ,
2014-09-10 16:53:40 +00:00
{
2015-03-08 05:40:18 +00:00
name : "invalid selector" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Spec . Selector [ "NoSpecialCharsLike=Equals" ] = "bar"
2014-09-10 16:53:40 +00:00
} ,
numErrs : 1 ,
} ,
2014-09-10 16:41:31 +00:00
{
2015-03-08 05:40:18 +00:00
name : "missing session affinity" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
s . Spec . SessionAffinity = ""
2014-09-10 16:41:31 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 1 ,
2014-09-10 16:41:31 +00:00
} ,
2015-05-22 21:49:26 +00:00
{
name : "missing type" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = ""
} ,
numErrs : 1 ,
} ,
2015-03-13 15:16:41 +00:00
{
name : "missing ports" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports = nil
} ,
numErrs : 1 ,
} ,
{
name : "empty port[0] name" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Name = ""
} ,
numErrs : 0 ,
} ,
{
name : "empty port[1] name" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "" , Protocol : "TCP" , Port : 12345 , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-03-13 15:16:41 +00:00
} ,
numErrs : 1 ,
} ,
2015-05-05 18:51:51 +00:00
{
name : "empty multi-port port[0] name" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Ports [ 0 ] . Name = ""
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "p" , Protocol : "TCP" , Port : 12345 , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-05 18:51:51 +00:00
} ,
numErrs : 1 ,
} ,
2015-03-13 15:16:41 +00:00
{
name : "invalid port name" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Name = "INVALID"
} ,
numErrs : 1 ,
} ,
2014-09-10 16:41:31 +00:00
{
2015-03-08 05:40:18 +00:00
name : "missing protocol" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Protocol = ""
2014-09-10 16:41:31 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 1 ,
2014-09-10 16:41:31 +00:00
} ,
{
2015-03-08 05:40:18 +00:00
name : "invalid protocol" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Protocol = "INVALID"
2014-09-10 16:41:31 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 1 ,
2014-09-10 16:41:31 +00:00
} ,
2015-03-16 21:36:30 +00:00
{
2015-05-23 20:41:11 +00:00
name : "invalid cluster ip" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-05-23 20:41:11 +00:00
s . Spec . ClusterIP = "invalid"
2015-03-16 21:36:30 +00:00
} ,
numErrs : 1 ,
} ,
2014-09-10 16:41:31 +00:00
{
2015-03-08 05:40:18 +00:00
name : "missing port" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Port = 0
2014-09-10 16:41:31 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 1 ,
2014-07-10 19:45:01 +00:00
} ,
2014-10-31 06:03:52 +00:00
{
2015-03-08 05:40:18 +00:00
name : "invalid port" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Port = 65536
2014-10-31 06:03:52 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 1 ,
2014-10-31 06:03:52 +00:00
} ,
{
2015-03-13 15:16:41 +00:00
name : "invalid TargetPort int" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . TargetPort = util . NewIntOrStringFromInt ( 65536 )
2014-10-31 06:03:52 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 1 ,
} ,
2015-03-16 14:03:05 +00:00
{
name : "invalid publicIPs localhost" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-08-12 00:18:21 +00:00
s . Spec . ExternalIPs = [ ] string { "127.0.0.1" }
2015-03-16 14:03:05 +00:00
} ,
numErrs : 1 ,
} ,
{
name : "invalid publicIPs" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-08-12 00:18:21 +00:00
s . Spec . ExternalIPs = [ ] string { "0.0.0.0" }
2015-03-16 14:03:05 +00:00
} ,
numErrs : 1 ,
} ,
{
2015-08-12 00:18:21 +00:00
name : "invalid publicIPs host" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-08-12 00:18:21 +00:00
s . Spec . ExternalIPs = [ ] string { "myhost.mydomain" }
2015-03-16 14:03:05 +00:00
} ,
2015-08-12 00:18:21 +00:00
numErrs : 1 ,
2015-03-16 14:03:05 +00:00
} ,
2015-03-08 05:40:18 +00:00
{
2015-03-13 15:16:41 +00:00
name : "dup port name" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Name = "p"
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "p" , Port : 12345 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2014-10-31 06:03:52 +00:00
} ,
2015-03-13 15:16:41 +00:00
numErrs : 1 ,
2014-10-31 06:03:52 +00:00
} ,
2015-04-03 19:06:25 +00:00
{
name : "invalid load balancer protocol 1" ,
tweakSvc : func ( s * api . Service ) {
2015-05-22 21:49:26 +00:00
s . Spec . Type = api . ServiceTypeLoadBalancer
2015-04-03 19:06:25 +00:00
s . Spec . Ports [ 0 ] . Protocol = "UDP"
} ,
numErrs : 1 ,
} ,
{
name : "invalid load balancer protocol 2" ,
tweakSvc : func ( s * api . Service ) {
2015-05-22 21:49:26 +00:00
s . Spec . Type = api . ServiceTypeLoadBalancer
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "UDP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-04-03 19:06:25 +00:00
} ,
numErrs : 1 ,
} ,
2014-10-31 06:03:52 +00:00
{
2015-03-08 05:40:18 +00:00
name : "valid 1" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-08 05:40:18 +00:00
// do nothing
2014-10-31 06:03:52 +00:00
} ,
numErrs : 0 ,
} ,
2014-10-23 20:14:13 +00:00
{
2015-03-08 05:40:18 +00:00
name : "valid 2" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . Protocol = "UDP"
s . Spec . Ports [ 0 ] . TargetPort = util . NewIntOrStringFromInt ( 12345 )
2014-11-18 17:49:00 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 0 ,
2014-11-18 17:49:00 +00:00
} ,
{
2015-03-08 05:40:18 +00:00
name : "valid 3" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . TargetPort = util . NewIntOrStringFromString ( "http" )
2014-10-23 20:14:13 +00:00
} ,
2015-03-08 05:40:18 +00:00
numErrs : 0 ,
2014-10-23 20:14:13 +00:00
} ,
2015-03-16 21:36:30 +00:00
{
2015-05-23 20:41:11 +00:00
name : "valid cluster ip - none " ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-05-23 20:41:11 +00:00
s . Spec . ClusterIP = "None"
2015-03-16 21:36:30 +00:00
} ,
numErrs : 0 ,
} ,
{
2015-05-23 20:41:11 +00:00
name : "valid cluster ip - empty" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( s * api . Service ) {
2015-05-23 20:41:11 +00:00
s . Spec . ClusterIP = ""
2015-03-13 15:16:41 +00:00
s . Spec . Ports [ 0 ] . TargetPort = util . NewIntOrStringFromString ( "http" )
2015-03-16 21:36:30 +00:00
} ,
numErrs : 0 ,
} ,
2015-04-03 19:06:25 +00:00
{
2015-05-20 15:59:34 +00:00
name : "valid type - cluster" ,
2015-05-22 21:49:26 +00:00
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeClusterIP
} ,
numErrs : 0 ,
} ,
{
2015-05-20 15:59:34 +00:00
name : "valid type - loadbalancer" ,
2015-05-22 21:49:26 +00:00
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeLoadBalancer
} ,
numErrs : 0 ,
} ,
{
name : "valid type loadbalancer 2 ports" ,
2015-04-03 19:06:25 +00:00
tweakSvc : func ( s * api . Service ) {
2015-05-22 21:49:26 +00:00
s . Spec . Type = api . ServiceTypeLoadBalancer
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-04-03 19:06:25 +00:00
} ,
numErrs : 0 ,
} ,
{
name : "valid external load balancer 2 ports" ,
tweakSvc : func ( s * api . Service ) {
2015-05-22 21:49:26 +00:00
s . Spec . Type = api . ServiceTypeLoadBalancer
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-04-03 19:06:25 +00:00
} ,
numErrs : 0 ,
} ,
2015-05-22 21:54:19 +00:00
{
name : "duplicate nodeports" ,
tweakSvc : func ( s * api . Service ) {
2015-05-20 15:59:34 +00:00
s . Spec . Type = api . ServiceTypeNodePort
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 1 , Protocol : "TCP" , NodePort : 1 , TargetPort : util . NewIntOrStringFromInt ( 1 ) } )
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "r" , Port : 2 , Protocol : "TCP" , NodePort : 1 , TargetPort : util . NewIntOrStringFromInt ( 2 ) } )
2015-05-22 21:54:19 +00:00
} ,
2015-05-20 15:59:34 +00:00
numErrs : 1 ,
2015-05-22 21:54:19 +00:00
} ,
{
name : "duplicate nodeports (different protocols)" ,
tweakSvc : func ( s * api . Service ) {
2015-05-20 15:59:34 +00:00
s . Spec . Type = api . ServiceTypeNodePort
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 1 , Protocol : "TCP" , NodePort : 1 , TargetPort : util . NewIntOrStringFromInt ( 1 ) } )
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "r" , Port : 2 , Protocol : "UDP" , NodePort : 1 , TargetPort : util . NewIntOrStringFromInt ( 2 ) } )
2015-05-22 21:54:19 +00:00
} ,
2015-05-20 15:59:34 +00:00
numErrs : 0 ,
} ,
{
name : "valid type - cluster" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeClusterIP
} ,
numErrs : 0 ,
} ,
{
name : "valid type - nodeport" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeNodePort
} ,
numErrs : 0 ,
} ,
{
name : "valid type - loadbalancer" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeLoadBalancer
} ,
numErrs : 0 ,
} ,
{
name : "valid type loadbalancer 2 ports" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeLoadBalancer
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 0 ,
} ,
{
name : "valid type loadbalancer with NodePort" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeLoadBalancer
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , NodePort : 12345 , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 0 ,
} ,
{
name : "valid type=NodePort service with NodePort" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeNodePort
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , NodePort : 12345 , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 0 ,
} ,
{
name : "valid type=NodePort service without NodePort" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeNodePort
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 0 ,
} ,
{
name : "valid cluster service without NodePort" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeClusterIP
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 0 ,
} ,
{
name : "invalid cluster service with NodePort" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeClusterIP
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , NodePort : 12345 , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 1 ,
} ,
{
name : "invalid public service with duplicate NodePort" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeNodePort
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "p1" , Port : 1 , Protocol : "TCP" , NodePort : 1 , TargetPort : util . NewIntOrStringFromInt ( 1 ) } )
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "p2" , Port : 2 , Protocol : "TCP" , NodePort : 1 , TargetPort : util . NewIntOrStringFromInt ( 2 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 1 ,
} ,
{
name : "valid type=LoadBalancer" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeLoadBalancer
2015-06-12 16:33:11 +00:00
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "q" , Port : 12345 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
2015-05-20 15:59:34 +00:00
} ,
numErrs : 0 ,
2015-05-22 21:54:19 +00:00
} ,
2015-07-09 05:02:10 +00:00
{
// For now we open firewalls, and its insecure if we open 10250, remove this
// when we have better protections in place.
name : "invalid port type=LoadBalancer" ,
tweakSvc : func ( s * api . Service ) {
s . Spec . Type = api . ServiceTypeLoadBalancer
s . Spec . Ports = append ( s . Spec . Ports , api . ServicePort { Name : "kubelet" , Port : 10250 , Protocol : "TCP" , TargetPort : util . NewIntOrStringFromInt ( 12345 ) } )
} ,
numErrs : 1 ,
} ,
2014-07-10 19:45:01 +00:00
}
2014-09-10 16:41:31 +00:00
for _ , tc := range testCases {
2015-03-31 18:13:44 +00:00
svc := makeValidService ( )
tc . tweakSvc ( & svc )
2015-03-08 05:40:18 +00:00
errs := ValidateService ( & svc )
2014-09-10 16:41:31 +00:00
if len ( errs ) != tc . numErrs {
2015-01-09 06:10:03 +00:00
t . Errorf ( "Unexpected error list for case %q: %v" , tc . name , utilerrors . NewAggregate ( errs ) )
2014-09-10 16:41:31 +00:00
}
2014-07-10 19:45:01 +00:00
}
}
2014-07-25 16:15:17 +00:00
2015-02-05 04:55:16 +00:00
func TestValidateReplicationControllerUpdate ( t * testing . T ) {
validSelector := map [ string ] string { "a" : "b" }
validPodTemplate := api . PodTemplate {
2015-03-04 15:46:27 +00:00
Template : api . PodTemplateSpec {
2015-02-05 04:55:16 +00:00
ObjectMeta : api . ObjectMeta {
Labels : validSelector ,
} ,
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-05 04:55:16 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "abc" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-02-05 04:55:16 +00:00
} ,
} ,
}
readWriteVolumePodTemplate := api . PodTemplate {
2015-03-04 15:46:27 +00:00
Template : api . PodTemplateSpec {
2015-02-05 04:55:16 +00:00
ObjectMeta : api . ObjectMeta {
Labels : validSelector ,
} ,
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-05 04:55:16 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "abc" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-08-08 01:52:23 +00:00
Volumes : [ ] api . Volume { { Name : "gcepd" , VolumeSource : api . VolumeSource { GCEPersistentDisk : & api . GCEPersistentDiskVolumeSource { PDName : "my-PD" , FSType : "ext4" , Partition : 1 , ReadOnly : false } } } } ,
2015-02-05 04:55:16 +00:00
} ,
} ,
}
invalidSelector := map [ string ] string { "NoUppercaseOrSpecialCharsLike=Equals" : "b" }
invalidPodTemplate := api . PodTemplate {
2015-03-04 15:46:27 +00:00
Template : api . PodTemplateSpec {
2015-02-05 04:55:16 +00:00
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-05 04:55:16 +00:00
DNSPolicy : api . DNSClusterFirst ,
} ,
ObjectMeta : api . ObjectMeta {
Labels : invalidSelector ,
} ,
} ,
}
type rcUpdateTest struct {
old api . ReplicationController
update api . ReplicationController
}
successCases := [ ] rcUpdateTest {
{
old : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
update : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Replicas : 3 ,
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
} ,
{
old : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
update : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Replicas : 1 ,
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & readWriteVolumePodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
} ,
}
for _ , successCase := range successCases {
2015-03-20 00:51:07 +00:00
successCase . old . ObjectMeta . ResourceVersion = "1"
successCase . update . ObjectMeta . ResourceVersion = "1"
2015-02-05 04:55:16 +00:00
if errs := ValidateReplicationControllerUpdate ( & successCase . old , & successCase . update ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
errorCases := map [ string ] rcUpdateTest {
"more than one read/write" : {
old : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
update : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Replicas : 2 ,
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & readWriteVolumePodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
} ,
"invalid selector" : {
old : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
update : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Replicas : 2 ,
Selector : invalidSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
} ,
"invalid pod" : {
old : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
update : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Replicas : 2 ,
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & invalidPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
} ,
"negative replicas" : {
old : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
update : api . ReplicationController {
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Replicas : - 1 ,
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
} ,
}
for testName , errorCase := range errorCases {
if errs := ValidateReplicationControllerUpdate ( & errorCase . old , & errorCase . update ) ; len ( errs ) == 0 {
t . Errorf ( "expected failure: %s" , testName )
}
}
}
2014-07-25 16:15:17 +00:00
func TestValidateReplicationController ( t * testing . T ) {
validSelector := map [ string ] string { "a" : "b" }
2014-08-30 01:20:27 +00:00
validPodTemplate := api . PodTemplate {
2015-03-04 15:46:27 +00:00
Template : api . PodTemplateSpec {
2014-11-07 02:08:46 +00:00
ObjectMeta : api . ObjectMeta {
Labels : validSelector ,
2014-07-25 16:15:17 +00:00
} ,
2015-01-26 17:52:50 +00:00
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-01-26 17:52:50 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "abc" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2015-01-26 17:52:50 +00:00
} ,
2014-07-25 16:15:17 +00:00
} ,
}
2015-02-05 04:55:16 +00:00
readWriteVolumePodTemplate := api . PodTemplate {
2015-03-04 15:46:27 +00:00
Template : api . PodTemplateSpec {
2015-02-05 04:55:16 +00:00
ObjectMeta : api . ObjectMeta {
Labels : validSelector ,
} ,
2014-11-07 02:08:46 +00:00
Spec : api . PodSpec {
2015-08-08 01:52:23 +00:00
Volumes : [ ] api . Volume { { Name : "gcepd" , VolumeSource : api . VolumeSource { GCEPersistentDisk : & api . GCEPersistentDiskVolumeSource { PDName : "my-PD" , FSType : "ext4" , Partition : 1 , ReadOnly : false } } } } ,
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-02-04 23:44:46 +00:00
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "abc" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2014-08-05 17:58:43 +00:00
} ,
} ,
}
2014-10-23 20:14:13 +00:00
invalidSelector := map [ string ] string { "NoUppercaseOrSpecialCharsLike=Equals" : "b" }
invalidPodTemplate := api . PodTemplate {
2015-03-04 15:46:27 +00:00
Template : api . PodTemplateSpec {
2014-11-18 04:08:23 +00:00
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyAlways ,
2015-01-26 17:52:50 +00:00
DNSPolicy : api . DNSClusterFirst ,
2014-11-18 04:08:23 +00:00
} ,
2014-11-07 02:08:46 +00:00
ObjectMeta : api . ObjectMeta {
Labels : invalidSelector ,
2014-10-23 20:14:13 +00:00
} ,
} ,
}
2014-08-30 01:20:27 +00:00
successCases := [ ] api . ReplicationController {
2014-07-25 16:15:17 +00:00
{
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2014-07-25 16:15:17 +00:00
} ,
} ,
{
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc-123" , Namespace : api . NamespaceDefault } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2014-07-25 16:15:17 +00:00
} ,
} ,
2015-02-05 04:55:16 +00:00
{
ObjectMeta : api . ObjectMeta { Name : "abc-123" , Namespace : api . NamespaceDefault } ,
Spec : api . ReplicationControllerSpec {
Replicas : 1 ,
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & readWriteVolumePodTemplate . Template ,
2015-02-05 04:55:16 +00:00
} ,
} ,
2014-07-25 16:15:17 +00:00
}
for _ , successCase := range successCases {
if errs := ValidateReplicationController ( & successCase ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
2014-08-30 01:20:27 +00:00
errorCases := map [ string ] api . ReplicationController {
2014-07-25 16:15:17 +00:00
"zero-length ID" : {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "" , Namespace : api . NamespaceDefault } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2014-09-29 21:18:18 +00:00
} ,
} ,
"missing-namespace" : {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc-123" } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2014-07-25 16:15:17 +00:00
} ,
} ,
"empty selector" : {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2014-07-25 16:15:17 +00:00
} ,
} ,
2014-08-22 00:02:39 +00:00
"selector_doesnt_match" : {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Selector : map [ string ] string { "foo" : "bar" } ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2014-08-22 00:02:39 +00:00
} ,
} ,
2014-07-25 16:15:17 +00:00
"invalid manifest" : {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2014-07-25 16:15:17 +00:00
} ,
} ,
2015-02-05 04:55:16 +00:00
"read-write persistent disk with > 1 pod" : {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc" } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
2015-02-05 04:55:16 +00:00
Replicas : 2 ,
2014-11-07 02:08:46 +00:00
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & readWriteVolumePodTemplate . Template ,
2014-08-05 17:58:43 +00:00
} ,
} ,
2014-08-04 19:02:51 +00:00
"negative_replicas" : {
2014-10-23 20:51:34 +00:00
ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : api . NamespaceDefault } ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Replicas : - 1 ,
Selector : validSelector ,
2014-08-04 19:02:51 +00:00
} ,
} ,
2014-10-23 20:14:13 +00:00
"invalid_label" : {
ObjectMeta : api . ObjectMeta {
Name : "abc-123" ,
Namespace : api . NamespaceDefault ,
Labels : map [ string ] string {
"NoUppercaseOrSpecialCharsLike=Equals" : "bar" ,
} ,
} ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
2015-03-04 15:46:27 +00:00
Template : & validPodTemplate . Template ,
2014-10-23 20:14:13 +00:00
} ,
} ,
"invalid_label 2" : {
ObjectMeta : api . ObjectMeta {
Name : "abc-123" ,
Namespace : api . NamespaceDefault ,
Labels : map [ string ] string {
"NoUppercaseOrSpecialCharsLike=Equals" : "bar" ,
} ,
} ,
2014-11-07 02:08:46 +00:00
Spec : api . ReplicationControllerSpec {
2015-03-04 15:46:27 +00:00
Template : & invalidPodTemplate . Template ,
} ,
} ,
"invalid_annotation" : {
ObjectMeta : api . ObjectMeta {
Name : "abc-123" ,
Namespace : api . NamespaceDefault ,
Annotations : map [ string ] string {
"NoUppercaseOrSpecialCharsLike=Equals" : "bar" ,
} ,
} ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
Template : & validPodTemplate . Template ,
2014-10-23 20:14:13 +00:00
} ,
} ,
2014-11-18 04:08:23 +00:00
"invalid restart policy 1" : {
ObjectMeta : api . ObjectMeta {
Name : "abc-123" ,
Namespace : api . NamespaceDefault ,
} ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
Template : & api . PodTemplateSpec {
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyOnFailure ,
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2014-11-18 04:08:23 +00:00
} ,
ObjectMeta : api . ObjectMeta {
Labels : validSelector ,
} ,
} ,
} ,
} ,
"invalid restart policy 2" : {
ObjectMeta : api . ObjectMeta {
Name : "abc-123" ,
Namespace : api . NamespaceDefault ,
} ,
Spec : api . ReplicationControllerSpec {
Selector : validSelector ,
Template : & api . PodTemplateSpec {
Spec : api . PodSpec {
2015-03-14 01:38:07 +00:00
RestartPolicy : api . RestartPolicyNever ,
DNSPolicy : api . DNSClusterFirst ,
2015-03-18 15:00:18 +00:00
Containers : [ ] api . Container { { Name : "ctr" , Image : "image" , ImagePullPolicy : "IfNotPresent" } } ,
2014-11-18 04:08:23 +00:00
} ,
ObjectMeta : api . ObjectMeta {
Labels : validSelector ,
} ,
} ,
} ,
} ,
2014-07-25 16:15:17 +00:00
}
for k , v := range errorCases {
2014-08-20 03:54:20 +00:00
errs := ValidateReplicationController ( & v )
if len ( errs ) == 0 {
2014-07-25 16:15:17 +00:00
t . Errorf ( "expected failure for %s" , k )
}
2014-08-20 03:54:20 +00:00
for i := range errs {
2014-11-20 22:11:23 +00:00
field := errs [ i ] . ( * errors . ValidationError ) . Field
2014-11-07 02:08:46 +00:00
if ! strings . HasPrefix ( field , "spec.template." ) &&
2015-08-12 15:26:23 +00:00
field != "metadata.name" &&
2015-01-27 23:55:54 +00:00
field != "metadata.namespace" &&
2014-11-07 02:08:46 +00:00
field != "spec.selector" &&
field != "spec.template" &&
2014-08-05 17:58:43 +00:00
field != "GCEPersistentDisk.ReadOnly" &&
2014-11-07 02:08:46 +00:00
field != "spec.replicas" &&
2014-11-20 05:55:45 +00:00
field != "spec.template.labels" &&
2015-01-27 23:55:54 +00:00
field != "metadata.annotations" &&
field != "metadata.labels" {
2014-08-20 03:54:20 +00:00
t . Errorf ( "%s: missing prefix for: %v" , k , errs [ i ] )
}
}
2014-07-25 16:15:17 +00:00
}
}
2014-10-08 19:56:02 +00:00
2015-04-22 17:55:05 +00:00
func TestValidateNode ( t * testing . T ) {
2014-11-12 17:38:15 +00:00
validSelector := map [ string ] string { "a" : "b" }
invalidSelector := map [ string ] string { "NoUppercaseOrSpecialCharsLike=Equals" : "b" }
2014-12-08 03:44:27 +00:00
successCases := [ ] api . Node {
2014-11-12 17:38:15 +00:00
{
2014-11-19 22:39:10 +00:00
ObjectMeta : api . ObjectMeta {
Name : "abc" ,
Labels : validSelector ,
} ,
Status : api . NodeStatus {
2015-02-13 19:07:23 +00:00
Addresses : [ ] api . NodeAddress {
{ Type : api . NodeLegacyHostIP , Address : "something" } ,
} ,
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
api . ResourceName ( "my.org/gpu" ) : resource . MustParse ( "10" ) ,
} ,
} ,
2015-03-25 13:44:40 +00:00
Spec : api . NodeSpec {
ExternalID : "external" ,
} ,
2014-11-12 17:38:15 +00:00
} ,
{
2015-01-27 23:56:38 +00:00
ObjectMeta : api . ObjectMeta {
Name : "abc" ,
} ,
2014-11-19 22:39:10 +00:00
Status : api . NodeStatus {
2015-02-13 19:07:23 +00:00
Addresses : [ ] api . NodeAddress {
{ Type : api . NodeLegacyHostIP , Address : "something" } ,
} ,
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "0" ) ,
} ,
} ,
2015-03-25 13:44:40 +00:00
Spec : api . NodeSpec {
ExternalID : "external" ,
} ,
2014-11-12 17:38:15 +00:00
} ,
}
for _ , successCase := range successCases {
2015-04-22 17:55:05 +00:00
if errs := ValidateNode ( & successCase ) ; len ( errs ) != 0 {
2014-11-12 17:38:15 +00:00
t . Errorf ( "expected success: %v" , errs )
}
}
2014-12-08 03:44:27 +00:00
errorCases := map [ string ] api . Node {
2014-11-12 17:38:15 +00:00
"zero-length Name" : {
2014-11-19 22:39:10 +00:00
ObjectMeta : api . ObjectMeta {
Name : "" ,
Labels : validSelector ,
} ,
Status : api . NodeStatus {
2015-02-13 19:07:23 +00:00
Addresses : [ ] api . NodeAddress { } ,
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
2015-03-25 13:44:40 +00:00
Spec : api . NodeSpec {
ExternalID : "external" ,
} ,
2014-11-12 17:38:15 +00:00
} ,
"invalid-labels" : {
2014-11-19 22:39:10 +00:00
ObjectMeta : api . ObjectMeta {
Name : "abc-123" ,
Labels : invalidSelector ,
} ,
2015-03-25 13:44:40 +00:00
Status : api . NodeStatus {
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
2015-03-25 13:44:40 +00:00
Spec : api . NodeSpec {
ExternalID : "external" ,
} ,
2015-03-24 17:24:07 +00:00
} ,
"missing-external-id" : {
ObjectMeta : api . ObjectMeta {
Name : "abc-123" ,
Labels : validSelector ,
} ,
2015-03-25 13:44:40 +00:00
Status : api . NodeStatus {
2015-03-24 17:24:07 +00:00
Capacity : api . ResourceList {
api . ResourceName ( api . ResourceCPU ) : resource . MustParse ( "10" ) ,
api . ResourceName ( api . ResourceMemory ) : resource . MustParse ( "10G" ) ,
} ,
} ,
} ,
2014-11-12 17:38:15 +00:00
}
for k , v := range errorCases {
2015-04-22 17:55:05 +00:00
errs := ValidateNode ( & v )
2014-11-12 17:38:15 +00:00
if len ( errs ) == 0 {
t . Errorf ( "expected failure for %s" , k )
}
for i := range errs {
2014-11-20 22:11:23 +00:00
field := errs [ i ] . ( * errors . ValidationError ) . Field
2015-03-24 17:24:07 +00:00
expectedFields := map [ string ] bool {
2015-08-12 15:26:23 +00:00
"metadata.name" : true ,
"metadata.labels" : true ,
"metadata.annotations" : true ,
"metadata.namespace" : true ,
"spec.ExternalID" : true ,
2015-03-24 17:24:07 +00:00
}
if expectedFields [ field ] == false {
2014-11-12 17:38:15 +00:00
t . Errorf ( "%s: missing prefix for: %v" , k , errs [ i ] )
}
}
}
}
2014-11-17 18:22:27 +00:00
2015-04-22 17:55:05 +00:00
func TestValidateNodeUpdate ( t * testing . T ) {
2014-11-17 18:22:27 +00:00
tests := [ ] struct {
2015-04-22 17:55:05 +00:00
oldNode api . Node
node api . Node
valid bool
2014-11-17 18:22:27 +00:00
} {
2014-12-08 03:44:27 +00:00
{ api . Node { } , api . Node { } , true } ,
{ api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" } } ,
2014-12-08 03:44:27 +00:00
api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "bar" } ,
} , false } ,
2014-12-08 03:44:27 +00:00
{ api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "foo" : "bar" } ,
} ,
2014-12-08 03:44:27 +00:00
} , api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , true } ,
2014-12-08 03:44:27 +00:00
{ api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
2014-12-08 03:44:27 +00:00
} , api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , true } ,
2014-12-08 03:44:27 +00:00
{ api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "bar" : "foo" } ,
} ,
2014-12-08 03:44:27 +00:00
} , api . Node {
2014-11-17 18:22:27 +00:00
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , true } ,
2014-12-12 05:39:56 +00:00
{ api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
2015-03-25 13:44:40 +00:00
Status : api . NodeStatus {
2014-12-12 05:39:56 +00:00
Capacity : api . ResourceList {
2015-01-07 01:20:01 +00:00
api . ResourceCPU : resource . MustParse ( "10000" ) ,
api . ResourceMemory : resource . MustParse ( "100" ) ,
2014-12-12 05:39:56 +00:00
} ,
} ,
} , api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
2015-03-25 13:44:40 +00:00
Status : api . NodeStatus {
2014-12-12 05:39:56 +00:00
Capacity : api . ResourceList {
2015-01-07 01:20:01 +00:00
api . ResourceCPU : resource . MustParse ( "100" ) ,
api . ResourceMemory : resource . MustParse ( "10000" ) ,
2014-12-12 05:39:56 +00:00
} ,
} ,
} , true } ,
{ api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "bar" : "foo" } ,
} ,
2015-03-25 13:44:40 +00:00
Status : api . NodeStatus {
2014-12-12 05:39:56 +00:00
Capacity : api . ResourceList {
2015-01-07 01:20:01 +00:00
api . ResourceCPU : resource . MustParse ( "10000" ) ,
api . ResourceMemory : resource . MustParse ( "100" ) ,
2014-12-12 05:39:56 +00:00
} ,
} ,
} , api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "bar" : "fooobaz" } ,
} ,
2015-03-25 13:44:40 +00:00
Status : api . NodeStatus {
2014-12-12 05:39:56 +00:00
Capacity : api . ResourceList {
2015-01-07 01:20:01 +00:00
api . ResourceCPU : resource . MustParse ( "100" ) ,
api . ResourceMemory : resource . MustParse ( "10000" ) ,
2014-12-12 05:39:56 +00:00
} ,
} ,
} , true } ,
2014-12-22 19:04:57 +00:00
{ api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "bar" : "foo" } ,
} ,
Status : api . NodeStatus {
2015-02-13 19:07:23 +00:00
Addresses : [ ] api . NodeAddress {
{ Type : api . NodeLegacyHostIP , Address : "1.2.3.4" } ,
} ,
2014-12-22 19:04:57 +00:00
} ,
} , api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "bar" : "fooobaz" } ,
} ,
} , true } ,
2015-02-04 22:21:34 +00:00
{ api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Labels : map [ string ] string { "Foo" : "baz" } ,
} ,
2015-02-27 15:08:02 +00:00
} , true } ,
2015-02-17 20:03:14 +00:00
{ api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
Spec : api . NodeSpec {
Unschedulable : false ,
} ,
} , api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
Spec : api . NodeSpec {
Unschedulable : true ,
} ,
} , true } ,
2015-04-22 17:55:05 +00:00
{ api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
Spec : api . NodeSpec {
Unschedulable : false ,
} ,
} , api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
Status : api . NodeStatus {
Addresses : [ ] api . NodeAddress {
{ Type : api . NodeExternalIP , Address : "1.1.1.1" } ,
{ Type : api . NodeExternalIP , Address : "1.1.1.1" } ,
} ,
} ,
} , false } ,
{ api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
Spec : api . NodeSpec {
Unschedulable : false ,
} ,
} , api . Node {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
} ,
Status : api . NodeStatus {
Addresses : [ ] api . NodeAddress {
{ Type : api . NodeExternalIP , Address : "1.1.1.1" } ,
{ Type : api . NodeInternalIP , Address : "10.1.1.1" } ,
} ,
} ,
} , true } ,
2014-11-17 18:22:27 +00:00
}
2015-01-27 23:55:54 +00:00
for i , test := range tests {
2015-04-22 17:55:05 +00:00
test . oldNode . ObjectMeta . ResourceVersion = "1"
test . node . ObjectMeta . ResourceVersion = "1"
errs := ValidateNodeUpdate ( & test . oldNode , & test . node )
2014-11-17 18:22:27 +00:00
if test . valid && len ( errs ) > 0 {
2015-01-27 23:55:54 +00:00
t . Errorf ( "%d: Unexpected error: %v" , i , errs )
2015-04-22 17:55:05 +00:00
t . Logf ( "%#v vs %#v" , test . oldNode . ObjectMeta , test . node . ObjectMeta )
2014-11-17 18:22:27 +00:00
}
if ! test . valid && len ( errs ) == 0 {
2015-01-27 23:55:54 +00:00
t . Errorf ( "%d: Unexpected non-error" , i )
}
}
}
func TestValidateServiceUpdate ( t * testing . T ) {
2015-03-31 18:13:44 +00:00
testCases := [ ] struct {
name string
tweakSvc func ( oldSvc , newSvc * api . Service ) // given basic valid services, each test case can customize them
numErrs int
2015-01-27 23:55:54 +00:00
} {
2015-03-31 18:13:44 +00:00
{
name : "no change" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
// do nothing
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 0 ,
} ,
{
name : "change name" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Name += "2"
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 1 ,
} ,
{
name : "change namespace" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Namespace += "2"
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 1 ,
} ,
{
name : "change label valid" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Labels [ "key" ] = "other-value"
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 0 ,
} ,
{
name : "add label" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Labels [ "key2" ] = "value2"
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 0 ,
} ,
{
2015-05-23 20:41:11 +00:00
name : "change cluster IP" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
2015-05-23 20:41:11 +00:00
oldSvc . Spec . ClusterIP = "1.2.3.4"
newSvc . Spec . ClusterIP = "8.6.7.5"
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 1 ,
} ,
{
2015-05-23 20:41:11 +00:00
name : "remove cluster IP" ,
2015-03-31 18:13:44 +00:00
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
2015-05-23 20:41:11 +00:00
oldSvc . Spec . ClusterIP = "1.2.3.4"
newSvc . Spec . ClusterIP = ""
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 1 ,
} ,
{
name : "change affinity" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Spec . SessionAffinity = "ClientIP"
2015-01-27 23:55:54 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 0 ,
} ,
{
name : "remove affinity" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Spec . SessionAffinity = ""
2015-02-04 22:21:34 +00:00
} ,
2015-03-31 18:13:44 +00:00
numErrs : 1 ,
} ,
2015-05-22 21:49:26 +00:00
{
name : "change type" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Spec . Type = api . ServiceTypeLoadBalancer
} ,
numErrs : 0 ,
} ,
{
name : "remove type" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Spec . Type = ""
} ,
numErrs : 1 ,
} ,
2015-05-20 15:59:34 +00:00
{
name : "change type -> nodeport" ,
tweakSvc : func ( oldSvc , newSvc * api . Service ) {
newSvc . Spec . Type = api . ServiceTypeNodePort
} ,
numErrs : 0 ,
} ,
2015-01-27 23:55:54 +00:00
}
2015-03-31 18:13:44 +00:00
for _ , tc := range testCases {
oldSvc := makeValidService ( )
newSvc := makeValidService ( )
tc . tweakSvc ( & oldSvc , & newSvc )
errs := ValidateServiceUpdate ( & oldSvc , & newSvc )
if len ( errs ) != tc . numErrs {
t . Errorf ( "Unexpected error list for case %q: %v" , tc . name , utilerrors . NewAggregate ( errs ) )
2014-11-17 18:22:27 +00:00
}
}
}
2015-01-17 00:34:47 +00:00
func TestValidateResourceNames ( t * testing . T ) {
table := [ ] struct {
input string
success bool
} {
{ "memory" , true } ,
{ "cpu" , true } ,
{ "network" , false } ,
{ "disk" , false } ,
{ "" , false } ,
{ "." , false } ,
{ ".." , false } ,
{ "my.favorite.app.co/12345" , true } ,
2015-03-02 13:41:13 +00:00
{ "my.favorite.app.co/_12345" , false } ,
2015-01-17 00:34:47 +00:00
{ "my.favorite.app.co/12345_" , false } ,
{ "kubernetes.io/.." , false } ,
2015-05-13 04:24:41 +00:00
{ "kubernetes.io/" + strings . Repeat ( "a" , 63 ) , true } ,
{ "kubernetes.io/" + strings . Repeat ( "a" , 64 ) , false } ,
2015-01-17 00:34:47 +00:00
{ "kubernetes.io//" , false } ,
{ "kubernetes.io" , false } ,
{ "kubernetes.io/will/not/work/" , false } ,
}
2015-02-05 00:36:27 +00:00
for k , item := range table {
err := validateResourceName ( item . input , "sth" )
2015-01-17 00:34:47 +00:00
if len ( err ) != 0 && item . success {
t . Errorf ( "expected no failure for input %q" , item . input )
} else if len ( err ) == 0 && ! item . success {
t . Errorf ( "expected failure for input %q" , item . input )
2015-02-05 00:36:27 +00:00
for i := range err {
detail := err [ i ] . ( * errors . ValidationError ) . Detail
if detail != "" && detail != qualifiedNameErrorMsg {
2015-08-08 01:52:23 +00:00
t . Errorf ( "%d: expected error detail either empty or %s, got %s" , k , qualifiedNameErrorMsg , detail )
2015-02-05 00:36:27 +00:00
}
}
2015-01-17 00:34:47 +00:00
}
}
}
2015-01-22 21:52:40 +00:00
2015-09-08 18:49:54 +00:00
func getResourceList ( cpu , memory string ) api . ResourceList {
res := api . ResourceList { }
if cpu != "" {
res [ api . ResourceCPU ] = resource . MustParse ( cpu )
2015-06-16 20:16:34 +00:00
}
2015-09-08 18:49:54 +00:00
if memory != "" {
res [ api . ResourceMemory ] = resource . MustParse ( memory )
2015-08-28 16:26:36 +00:00
}
2015-09-08 18:49:54 +00:00
return res
}
2015-08-28 16:26:36 +00:00
2015-09-08 18:49:54 +00:00
func TestValidateLimitRange ( t * testing . T ) {
successCases := [ ] struct {
name string
spec api . LimitRangeSpec
} {
{
name : "all-fields-valid" ,
spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypePod ,
Max : getResourceList ( "100m" , "10000Mi" ) ,
Min : getResourceList ( "5m" , "100Mi" ) ,
2015-09-10 20:39:59 +00:00
MaxLimitRequestRatio : getResourceList ( "10" , "" ) ,
} ,
{
Type : api . LimitTypeContainer ,
Max : getResourceList ( "100m" , "10000Mi" ) ,
Min : getResourceList ( "5m" , "100Mi" ) ,
2015-09-08 18:49:54 +00:00
Default : getResourceList ( "50m" , "500Mi" ) ,
DefaultRequest : getResourceList ( "10m" , "200Mi" ) ,
MaxLimitRequestRatio : getResourceList ( "10" , "" ) ,
} ,
2015-08-28 16:26:36 +00:00
} ,
} ,
} ,
2015-01-22 21:52:40 +00:00
{
2015-09-08 18:49:54 +00:00
name : "all-fields-valid-big-numbers" ,
spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
2015-09-10 20:39:59 +00:00
Type : api . LimitTypeContainer ,
2015-09-08 18:49:54 +00:00
Max : getResourceList ( "100m" , "10000T" ) ,
Min : getResourceList ( "5m" , "100Mi" ) ,
Default : getResourceList ( "50m" , "500Mi" ) ,
DefaultRequest : getResourceList ( "10m" , "200Mi" ) ,
MaxLimitRequestRatio : getResourceList ( "10" , "" ) ,
} ,
} ,
2015-01-22 21:52:40 +00:00
} ,
} ,
}
2015-01-23 17:38:30 +00:00
2015-01-22 21:52:40 +00:00
for _ , successCase := range successCases {
2015-09-08 18:49:54 +00:00
limitRange := & api . LimitRange { ObjectMeta : api . ObjectMeta { Name : successCase . name , Namespace : "foo" } , Spec : successCase . spec }
if errs := ValidateLimitRange ( limitRange ) ; len ( errs ) != 0 {
t . Errorf ( "Case %v, unexpected error: %v" , successCase . name , errs )
2015-01-22 21:52:40 +00:00
}
}
2015-02-05 00:36:27 +00:00
errorCases := map [ string ] struct {
R api . LimitRange
D string
} {
2015-09-08 18:49:54 +00:00
"zero-length-name" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "" , Namespace : "foo" } , Spec : api . LimitRangeSpec { } } ,
2015-08-12 15:26:23 +00:00
"name or generateName is required" ,
2015-01-22 21:52:40 +00:00
} ,
"zero-length-namespace" : {
2015-09-08 18:49:54 +00:00
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "" } , Spec : api . LimitRangeSpec { } } ,
2015-02-05 00:36:27 +00:00
"" ,
} ,
2015-09-08 18:49:54 +00:00
"invalid-name" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "^Invalid" , Namespace : "foo" } , Spec : api . LimitRangeSpec { } } ,
2015-06-09 12:53:30 +00:00
DNSSubdomainErrorMsg ,
2015-02-05 00:36:27 +00:00
} ,
2015-09-08 18:49:54 +00:00
"invalid-namespace" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "^Invalid" } , Spec : api . LimitRangeSpec { } } ,
2015-06-09 12:53:30 +00:00
DNS1123LabelErrorMsg ,
2015-01-22 21:52:40 +00:00
} ,
2015-09-08 18:49:54 +00:00
"duplicate-limit-type" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypePod ,
Max : getResourceList ( "100m" , "10000m" ) ,
Min : getResourceList ( "0m" , "100m" ) ,
} ,
{
Type : api . LimitTypePod ,
Min : getResourceList ( "0m" , "100m" ) ,
} ,
} ,
} } ,
2015-06-16 20:16:34 +00:00
"" ,
} ,
2015-09-10 20:39:59 +00:00
"default-limit-type-pod" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypePod ,
Max : getResourceList ( "100m" , "10000m" ) ,
Min : getResourceList ( "0m" , "100m" ) ,
Default : getResourceList ( "10m" , "100m" ) ,
} ,
} ,
} } ,
"Default is not supported when limit type is Pod" ,
} ,
"default-request-limit-type-pod" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypePod ,
Max : getResourceList ( "100m" , "10000m" ) ,
Min : getResourceList ( "0m" , "100m" ) ,
DefaultRequest : getResourceList ( "10m" , "100m" ) ,
} ,
} ,
} } ,
"DefaultRequest is not supported when limit type is Pod" ,
} ,
2015-09-08 18:49:54 +00:00
"min value 100m is greater than max value 10m" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypePod ,
Max : getResourceList ( "10m" , "" ) ,
Min : getResourceList ( "100m" , "" ) ,
} ,
} ,
} } ,
"min value 100m is greater than max value 10m" ,
2015-06-16 20:16:34 +00:00
} ,
"invalid spec default outside range" : {
2015-09-08 18:49:54 +00:00
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
2015-09-10 20:39:59 +00:00
Type : api . LimitTypeContainer ,
2015-09-08 18:49:54 +00:00
Max : getResourceList ( "1" , "" ) ,
Min : getResourceList ( "100m" , "" ) ,
Default : getResourceList ( "2000m" , "" ) ,
} ,
} ,
} } ,
"default value 2 is greater than max value 1" ,
2015-06-16 20:16:34 +00:00
} ,
2015-08-28 16:26:36 +00:00
"invalid spec defaultrequest outside range" : {
2015-09-08 18:49:54 +00:00
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
2015-09-10 20:39:59 +00:00
Type : api . LimitTypeContainer ,
2015-09-08 18:49:54 +00:00
Max : getResourceList ( "1" , "" ) ,
Min : getResourceList ( "100m" , "" ) ,
DefaultRequest : getResourceList ( "2000m" , "" ) ,
} ,
} ,
} } ,
"default request value 2 is greater than max value 1" ,
2015-08-28 16:26:36 +00:00
} ,
"invalid spec defaultrequest more than default" : {
2015-09-08 18:49:54 +00:00
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypeContainer ,
Max : getResourceList ( "2" , "" ) ,
Min : getResourceList ( "100m" , "" ) ,
Default : getResourceList ( "500m" , "" ) ,
DefaultRequest : getResourceList ( "800m" , "" ) ,
} ,
} ,
} } ,
"default request value 800m is greater than default limit value 500m" ,
2015-08-28 16:26:36 +00:00
} ,
2015-09-11 07:38:38 +00:00
"invalid spec maxLimitRequestRatio less than 1" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypePod ,
MaxLimitRequestRatio : getResourceList ( "800m" , "" ) ,
} ,
} ,
} } ,
"maxLimitRequestRatio 800m is less than 1" ,
} ,
"invalid spec maxLimitRequestRatio greater than max/min" : {
api . LimitRange { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : api . LimitRangeSpec {
Limits : [ ] api . LimitRangeItem {
{
Type : api . LimitTypeContainer ,
Max : getResourceList ( "" , "2Gi" ) ,
Min : getResourceList ( "" , "512Mi" ) ,
MaxLimitRequestRatio : getResourceList ( "" , "10" ) ,
} ,
} ,
} } ,
"maxLimitRequestRatio 10 is greater than max/min = 4.000000" ,
} ,
2015-01-22 21:52:40 +00:00
}
2015-09-08 18:49:54 +00:00
2015-01-22 21:52:40 +00:00
for k , v := range errorCases {
2015-02-05 00:36:27 +00:00
errs := ValidateLimitRange ( & v . R )
2015-01-22 21:52:40 +00:00
if len ( errs ) == 0 {
t . Errorf ( "expected failure for %s" , k )
}
for i := range errs {
2015-02-05 00:36:27 +00:00
detail := errs [ i ] . ( * errors . ValidationError ) . Detail
if detail != v . D {
t . Errorf ( "%s: expected error detail either empty or %s, got %s" , k , v . D , detail )
}
2015-01-22 21:52:40 +00:00
}
}
2015-09-08 18:49:54 +00:00
2015-01-22 21:52:40 +00:00
}
2015-01-23 17:38:30 +00:00
func TestValidateResourceQuota ( t * testing . T ) {
2015-02-05 00:36:27 +00:00
spec := api . ResourceQuotaSpec {
Hard : api . ResourceList {
api . ResourceCPU : resource . MustParse ( "100" ) ,
api . ResourceMemory : resource . MustParse ( "10000" ) ,
api . ResourcePods : resource . MustParse ( "10" ) ,
2015-09-24 14:15:40 +00:00
api . ResourceServices : resource . MustParse ( "0" ) ,
2015-02-05 00:36:27 +00:00
api . ResourceReplicationControllers : resource . MustParse ( "10" ) ,
api . ResourceQuotas : resource . MustParse ( "10" ) ,
} ,
}
2015-09-24 14:15:40 +00:00
negativeSpec := api . ResourceQuotaSpec {
Hard : api . ResourceList {
api . ResourceCPU : resource . MustParse ( "-100" ) ,
api . ResourceMemory : resource . MustParse ( "-10000" ) ,
api . ResourcePods : resource . MustParse ( "-10" ) ,
api . ResourceServices : resource . MustParse ( "-10" ) ,
api . ResourceReplicationControllers : resource . MustParse ( "-10" ) ,
api . ResourceQuotas : resource . MustParse ( "-10" ) ,
} ,
}
2015-01-23 17:38:30 +00:00
successCases := [ ] api . ResourceQuota {
{
ObjectMeta : api . ObjectMeta {
Name : "abc" ,
Namespace : "foo" ,
} ,
2015-02-05 00:36:27 +00:00
Spec : spec ,
2015-01-23 17:38:30 +00:00
} ,
}
for _ , successCase := range successCases {
if errs := ValidateResourceQuota ( & successCase ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
2015-02-05 00:36:27 +00:00
errorCases := map [ string ] struct {
R api . ResourceQuota
D string
} {
2015-01-23 17:38:30 +00:00
"zero-length Name" : {
2015-02-05 00:36:27 +00:00
api . ResourceQuota { ObjectMeta : api . ObjectMeta { Name : "" , Namespace : "foo" } , Spec : spec } ,
2015-08-12 15:26:23 +00:00
"name or generateName is required" ,
2015-01-23 17:38:30 +00:00
} ,
2015-02-05 00:36:27 +00:00
"zero-length Namespace" : {
api . ResourceQuota { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "" } , Spec : spec } ,
"" ,
} ,
"invalid Name" : {
api . ResourceQuota { ObjectMeta : api . ObjectMeta { Name : "^Invalid" , Namespace : "foo" } , Spec : spec } ,
2015-06-09 12:53:30 +00:00
DNSSubdomainErrorMsg ,
2015-02-05 00:36:27 +00:00
} ,
"invalid Namespace" : {
api . ResourceQuota { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "^Invalid" } , Spec : spec } ,
2015-06-09 12:53:30 +00:00
DNS1123LabelErrorMsg ,
2015-01-23 17:38:30 +00:00
} ,
2015-09-24 14:15:40 +00:00
"negative-limits" : {
api . ResourceQuota { ObjectMeta : api . ObjectMeta { Name : "abc" , Namespace : "foo" } , Spec : negativeSpec } ,
isNegativeErrorMsg ,
} ,
2015-01-23 17:38:30 +00:00
}
for k , v := range errorCases {
2015-02-05 00:36:27 +00:00
errs := ValidateResourceQuota ( & v . R )
2015-01-23 17:38:30 +00:00
if len ( errs ) == 0 {
t . Errorf ( "expected failure for %s" , k )
}
for i := range errs {
field := errs [ i ] . ( * errors . ValidationError ) . Field
2015-02-05 00:36:27 +00:00
detail := errs [ i ] . ( * errors . ValidationError ) . Detail
2015-09-24 14:15:40 +00:00
if field != "metadata.name" && field != "metadata.namespace" && ! api . IsStandardResourceName ( field ) {
2015-06-16 20:16:34 +00:00
t . Errorf ( "%s: missing prefix for: %v" , k , field )
2015-01-23 17:38:30 +00:00
}
2015-02-05 00:36:27 +00:00
if detail != v . D {
t . Errorf ( "%s: expected error detail either empty or %s, got %s" , k , v . D , detail )
}
2015-01-23 17:38:30 +00:00
}
}
}
2015-01-19 21:50:00 +00:00
func TestValidateNamespace ( t * testing . T ) {
validLabels := map [ string ] string { "a" : "b" }
invalidLabels := map [ string ] string { "NoUppercaseOrSpecialCharsLike=Equals" : "b" }
successCases := [ ] api . Namespace {
{
ObjectMeta : api . ObjectMeta { Name : "abc" , Labels : validLabels } ,
} ,
{
ObjectMeta : api . ObjectMeta { Name : "abc-123" } ,
2015-03-31 21:00:04 +00:00
Spec : api . NamespaceSpec {
Finalizers : [ ] api . FinalizerName { "example.com/something" , "example.com/other" } ,
} ,
2015-01-19 21:50:00 +00:00
} ,
}
for _ , successCase := range successCases {
if errs := ValidateNamespace ( & successCase ) ; len ( errs ) != 0 {
t . Errorf ( "expected success: %v" , errs )
}
}
errorCases := map [ string ] struct {
R api . Namespace
D string
} {
"zero-length name" : {
api . Namespace { ObjectMeta : api . ObjectMeta { Name : "" } } ,
"" ,
} ,
"defined-namespace" : {
api . Namespace { ObjectMeta : api . ObjectMeta { Name : "abc-123" , Namespace : "makesnosense" } } ,
"" ,
} ,
"invalid-labels" : {
api . Namespace { ObjectMeta : api . ObjectMeta { Name : "abc" , Labels : invalidLabels } } ,
"" ,
} ,
}
for k , v := range errorCases {
errs := ValidateNamespace ( & v . R )
if len ( errs ) == 0 {
t . Errorf ( "expected failure for %s" , k )
}
}
}
2015-03-20 16:48:12 +00:00
func TestValidateNamespaceFinalizeUpdate ( t * testing . T ) {
tests := [ ] struct {
oldNamespace api . Namespace
namespace api . Namespace
valid bool
} {
{ api . Namespace { } , api . Namespace { } , true } ,
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } } ,
api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } ,
Spec : api . NamespaceSpec {
Finalizers : [ ] api . FinalizerName { "Foo" } ,
} ,
} , false } ,
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } ,
Spec : api . NamespaceSpec {
Finalizers : [ ] api . FinalizerName { "foo.com/bar" } ,
} ,
} ,
api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } ,
Spec : api . NamespaceSpec {
Finalizers : [ ] api . FinalizerName { "foo.com/bar" , "what.com/bar" } ,
} ,
} , true } ,
2015-03-31 21:00:04 +00:00
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "fooemptyfinalizer" } ,
Spec : api . NamespaceSpec {
Finalizers : [ ] api . FinalizerName { "foo.com/bar" } ,
} ,
} ,
api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "fooemptyfinalizer" } ,
Spec : api . NamespaceSpec {
Finalizers : [ ] api . FinalizerName { "" , "foo.com/bar" , "what.com/bar" } ,
} ,
} , false } ,
2015-03-20 16:48:12 +00:00
}
for i , test := range tests {
2015-03-20 00:51:07 +00:00
test . namespace . ObjectMeta . ResourceVersion = "1"
test . oldNamespace . ObjectMeta . ResourceVersion = "1"
2015-03-20 16:48:12 +00:00
errs := ValidateNamespaceFinalizeUpdate ( & test . namespace , & test . oldNamespace )
if test . valid && len ( errs ) > 0 {
t . Errorf ( "%d: Unexpected error: %v" , i , errs )
t . Logf ( "%#v vs %#v" , test . oldNamespace , test . namespace )
}
if ! test . valid && len ( errs ) == 0 {
t . Errorf ( "%d: Unexpected non-error" , i )
}
}
}
func TestValidateNamespaceStatusUpdate ( t * testing . T ) {
2015-09-17 22:21:55 +00:00
now := unversioned . Now ( )
2015-04-10 15:41:18 +00:00
2015-03-20 16:48:12 +00:00
tests := [ ] struct {
oldNamespace api . Namespace
namespace api . Namespace
valid bool
} {
2015-04-10 15:41:18 +00:00
{ api . Namespace { } , api . Namespace {
Status : api . NamespaceStatus {
Phase : api . NamespaceActive ,
} ,
} , true } ,
2015-03-20 16:48:12 +00:00
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } } ,
api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-04-10 15:41:18 +00:00
Name : "foo" ,
DeletionTimestamp : & now } ,
2015-03-20 16:48:12 +00:00
Status : api . NamespaceStatus {
Phase : api . NamespaceTerminating ,
} ,
} , true } ,
2015-04-10 15:41:18 +00:00
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } } ,
api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } ,
Status : api . NamespaceStatus {
Phase : api . NamespaceTerminating ,
} ,
} , false } ,
2015-03-20 16:48:12 +00:00
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo" } } ,
api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "bar" } ,
Status : api . NamespaceStatus {
Phase : api . NamespaceTerminating ,
} ,
} , false } ,
}
for i , test := range tests {
2015-03-20 00:51:07 +00:00
test . namespace . ObjectMeta . ResourceVersion = "1"
test . oldNamespace . ObjectMeta . ResourceVersion = "1"
2015-04-10 15:41:18 +00:00
errs := ValidateNamespaceStatusUpdate ( & test . namespace , & test . oldNamespace )
2015-03-20 16:48:12 +00:00
if test . valid && len ( errs ) > 0 {
t . Errorf ( "%d: Unexpected error: %v" , i , errs )
t . Logf ( "%#v vs %#v" , test . oldNamespace . ObjectMeta , test . namespace . ObjectMeta )
}
if ! test . valid && len ( errs ) == 0 {
t . Errorf ( "%d: Unexpected non-error" , i )
}
}
}
2015-01-19 21:50:00 +00:00
func TestValidateNamespaceUpdate ( t * testing . T ) {
tests := [ ] struct {
oldNamespace api . Namespace
namespace api . Namespace
valid bool
} {
{ api . Namespace { } , api . Namespace { } , true } ,
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo1" } } ,
2015-01-19 21:50:00 +00:00
api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "bar1" } ,
2015-01-19 21:50:00 +00:00
} , false } ,
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo2" ,
2015-01-19 21:50:00 +00:00
Labels : map [ string ] string { "foo" : "bar" } ,
} ,
} , api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo2" ,
2015-01-19 21:50:00 +00:00
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , true } ,
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo3" ,
2015-01-19 21:50:00 +00:00
} ,
} , api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo3" ,
2015-01-19 21:50:00 +00:00
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , true } ,
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo4" ,
2015-01-19 21:50:00 +00:00
Labels : map [ string ] string { "bar" : "foo" } ,
} ,
} , api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo4" ,
2015-01-19 21:50:00 +00:00
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , true } ,
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo5" ,
2015-01-19 21:50:00 +00:00
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , api . Namespace {
ObjectMeta : api . ObjectMeta {
2015-03-31 21:00:04 +00:00
Name : "foo5" ,
2015-01-19 21:50:00 +00:00
Labels : map [ string ] string { "Foo" : "baz" } ,
} ,
2015-02-27 15:08:02 +00:00
} , true } ,
2015-03-31 21:00:04 +00:00
{ api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo6" ,
Labels : map [ string ] string { "foo" : "baz" } ,
} ,
} , api . Namespace {
ObjectMeta : api . ObjectMeta {
Name : "foo6" ,
Labels : map [ string ] string { "Foo" : "baz" } ,
} ,
Spec : api . NamespaceSpec {
Finalizers : [ ] api . FinalizerName { "kubernetes" } ,
} ,
Status : api . NamespaceStatus {
Phase : api . NamespaceTerminating ,
} ,
} , true } ,
2015-01-19 21:50:00 +00:00
}
for i , test := range tests {
2015-03-20 00:51:07 +00:00
test . namespace . ObjectMeta . ResourceVersion = "1"
test . oldNamespace . ObjectMeta . ResourceVersion = "1"
2015-03-31 21:00:04 +00:00
errs := ValidateNamespaceUpdate ( & test . namespace , & test . oldNamespace )
2015-01-19 21:50:00 +00:00
if test . valid && len ( errs ) > 0 {
t . Errorf ( "%d: Unexpected error: %v" , i , errs )
t . Logf ( "%#v vs %#v" , test . oldNamespace . ObjectMeta , test . namespace . ObjectMeta )
}
if ! test . valid && len ( errs ) == 0 {
t . Errorf ( "%d: Unexpected non-error" , i )
}
}
}
2015-02-18 01:24:50 +00:00
func TestValidateSecret ( t * testing . T ) {
2015-04-28 03:51:20 +00:00
// Opaque secret validation
2015-02-18 01:24:50 +00:00
validSecret := func ( ) api . Secret {
return api . Secret {
ObjectMeta : api . ObjectMeta { Name : "foo" , Namespace : "bar" } ,
Data : map [ string ] [ ] byte {
2015-02-18 01:26:41 +00:00
"data-1" : [ ] byte ( "bar" ) ,
2015-02-18 01:24:50 +00:00
} ,
}
}
var (
2015-05-11 19:03:10 +00:00
emptyName = validSecret ( )
invalidName = validSecret ( )
emptyNs = validSecret ( )
invalidNs = validSecret ( )
overMaxSize = validSecret ( )
invalidKey = validSecret ( )
leadingDotKey = validSecret ( )
dotKey = validSecret ( )
doubleDotKey = validSecret ( )
2015-02-18 01:24:50 +00:00
)
emptyName . Name = ""
invalidName . Name = "NoUppercaseOrSpecialCharsLike=Equals"
emptyNs . Namespace = ""
invalidNs . Namespace = "NoUppercaseOrSpecialCharsLike=Equals"
overMaxSize . Data = map [ string ] [ ] byte {
"over" : make ( [ ] byte , api . MaxSecretSize + 1 ) ,
}
2015-02-18 01:26:41 +00:00
invalidKey . Data [ "a..b" ] = [ ] byte ( "whoops" )
2015-05-11 19:03:10 +00:00
leadingDotKey . Data [ ".key" ] = [ ] byte ( "bar" )
dotKey . Data [ "." ] = [ ] byte ( "bar" )
doubleDotKey . Data [ ".." ] = [ ] byte ( "bar" )
2015-02-18 01:24:50 +00:00
2015-04-28 03:51:20 +00:00
// kubernetes.io/service-account-token secret validation
validServiceAccountTokenSecret := func ( ) api . Secret {
return api . Secret {
ObjectMeta : api . ObjectMeta {
Name : "foo" ,
Namespace : "bar" ,
Annotations : map [ string ] string {
api . ServiceAccountNameKey : "foo" ,
} ,
} ,
Type : api . SecretTypeServiceAccountToken ,
Data : map [ string ] [ ] byte {
"data-1" : [ ] byte ( "bar" ) ,
} ,
}
}
var (
emptyTokenAnnotation = validServiceAccountTokenSecret ( )
missingTokenAnnotation = validServiceAccountTokenSecret ( )
missingTokenAnnotations = validServiceAccountTokenSecret ( )
)
emptyTokenAnnotation . Annotations [ api . ServiceAccountNameKey ] = ""
delete ( missingTokenAnnotation . Annotations , api . ServiceAccountNameKey )
missingTokenAnnotations . Annotations = nil
2015-02-18 01:24:50 +00:00
tests := map [ string ] struct {
secret api . Secret
valid bool
} {
2015-05-11 19:03:10 +00:00
"valid" : { validSecret ( ) , true } ,
"empty name" : { emptyName , false } ,
"invalid name" : { invalidName , false } ,
"empty namespace" : { emptyNs , false } ,
"invalid namespace" : { invalidNs , false } ,
"over max size" : { overMaxSize , false } ,
"invalid key" : { invalidKey , false } ,
2015-04-28 03:51:20 +00:00
"valid service-account-token secret" : { validServiceAccountTokenSecret ( ) , true } ,
"empty service-account-token annotation" : { emptyTokenAnnotation , false } ,
"missing service-account-token annotation" : { missingTokenAnnotation , false } ,
"missing service-account-token annotations" : { missingTokenAnnotations , false } ,
2015-05-11 19:03:10 +00:00
"leading dot key" : { leadingDotKey , true } ,
"dot key" : { dotKey , false } ,
"double dot key" : { doubleDotKey , false } ,
2015-02-18 01:24:50 +00:00
}
for name , tc := range tests {
errs := ValidateSecret ( & tc . secret )
2015-05-06 14:09:18 +00:00
if tc . valid && len ( errs ) > 0 {
t . Errorf ( "%v: Unexpected error: %v" , name , errs )
}
if ! tc . valid && len ( errs ) == 0 {
t . Errorf ( "%v: Unexpected non-error" , name )
}
}
}
func TestValidateDockerConfigSecret ( t * testing . T ) {
validDockerSecret := func ( ) api . Secret {
return api . Secret {
ObjectMeta : api . ObjectMeta { Name : "foo" , Namespace : "bar" } ,
Type : api . SecretTypeDockercfg ,
Data : map [ string ] [ ] byte {
api . DockerConfigKey : [ ] byte ( ` { "https://index.docker.io/v1/": { "auth": "Y2x1ZWRyb29sZXIwMDAxOnBhc3N3b3Jk","email": "fake@example.com"}} ` ) ,
} ,
}
}
var (
missingDockerConfigKey = validDockerSecret ( )
emptyDockerConfigKey = validDockerSecret ( )
invalidDockerConfigKey = validDockerSecret ( )
)
delete ( missingDockerConfigKey . Data , api . DockerConfigKey )
emptyDockerConfigKey . Data [ api . DockerConfigKey ] = [ ] byte ( "" )
invalidDockerConfigKey . Data [ api . DockerConfigKey ] = [ ] byte ( "bad" )
tests := map [ string ] struct {
secret api . Secret
valid bool
} {
"valid" : { validDockerSecret ( ) , true } ,
"missing dockercfg" : { missingDockerConfigKey , false } ,
"empty dockercfg" : { emptyDockerConfigKey , false } ,
"invalid dockercfg" : { invalidDockerConfigKey , false } ,
}
for name , tc := range tests {
errs := ValidateSecret ( & tc . secret )
2015-02-18 01:24:50 +00:00
if tc . valid && len ( errs ) > 0 {
t . Errorf ( "%v: Unexpected error: %v" , name , errs )
}
if ! tc . valid && len ( errs ) == 0 {
t . Errorf ( "%v: Unexpected non-error" , name )
}
}
}
2015-03-20 21:24:43 +00:00
func TestValidateEndpoints ( t * testing . T ) {
2015-03-20 14:40:20 +00:00
successCases := map [ string ] api . Endpoints {
"simple endpoint" : {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.1.1" } , { IP : "10.10.2.2" } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 8675 , Protocol : "TCP" } , { Name : "b" , Port : 309 , Protocol : "TCP" } } ,
} ,
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.3.3" } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 93 , Protocol : "TCP" } , { Name : "b" , Port : 76 , Protocol : "TCP" } } ,
} ,
} ,
} ,
"empty subsets" : {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
} ,
"no name required for singleton port" : {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.1.1" } } ,
Ports : [ ] api . EndpointPort { { Port : 8675 , Protocol : "TCP" } } ,
} ,
} ,
} ,
}
for k , v := range successCases {
if errs := ValidateEndpoints ( & v ) ; len ( errs ) != 0 {
t . Errorf ( "Expected success for %s, got %v" , k , errs )
}
}
errorCases := map [ string ] struct {
endpoints api . Endpoints
errorType fielderrors . ValidationErrorType
errorDetail string
} {
"missing namespace" : {
endpoints : api . Endpoints { ObjectMeta : api . ObjectMeta { Name : "mysvc" } } ,
errorType : "FieldValueRequired" ,
} ,
"missing name" : {
endpoints : api . Endpoints { ObjectMeta : api . ObjectMeta { Namespace : "namespace" } } ,
errorType : "FieldValueRequired" ,
} ,
"invalid namespace" : {
endpoints : api . Endpoints { ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "no@#invalid.;chars\"allowed" } } ,
errorType : "FieldValueInvalid" ,
2015-06-09 12:53:30 +00:00
errorDetail : DNS1123LabelErrorMsg ,
2015-03-20 14:40:20 +00:00
} ,
"invalid name" : {
endpoints : api . Endpoints { ObjectMeta : api . ObjectMeta { Name : "-_Invliad^&Characters" , Namespace : "namespace" } } ,
errorType : "FieldValueInvalid" ,
2015-06-09 12:53:30 +00:00
errorDetail : DNSSubdomainErrorMsg ,
2015-03-20 14:40:20 +00:00
} ,
"empty addresses" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 93 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueRequired" ,
} ,
"empty ports" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.3.3" } } ,
} ,
} ,
} ,
errorType : "FieldValueRequired" ,
} ,
"invalid IP" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "2001:0db8:85a3:0042:1000:8a2e:0370:7334" } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 93 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueInvalid" ,
errorDetail : "invalid IPv4 address" ,
} ,
"Multiple ports, one without name" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.1.1" } } ,
Ports : [ ] api . EndpointPort { { Port : 8675 , Protocol : "TCP" } , { Name : "b" , Port : 309 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueRequired" ,
} ,
"Invalid port number" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.1.1" } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 66000 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueInvalid" ,
errorDetail : portRangeErrorMsg ,
} ,
"Invalid protocol" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.1.1" } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 93 , Protocol : "Protocol" } } ,
} ,
} ,
} ,
errorType : "FieldValueNotSupported" ,
} ,
"Address missing IP" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 93 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueInvalid" ,
errorDetail : "invalid IPv4 address" ,
} ,
"Port missing number" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.1.1" } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueInvalid" ,
errorDetail : portRangeErrorMsg ,
} ,
"Port missing protocol" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "10.10.1.1" } } ,
Ports : [ ] api . EndpointPort { { Name : "a" , Port : 93 } } ,
} ,
} ,
} ,
errorType : "FieldValueRequired" ,
} ,
2015-07-04 04:05:15 +00:00
"Address is loopback" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "127.0.0.1" } } ,
Ports : [ ] api . EndpointPort { { Name : "p" , Port : 93 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueInvalid" ,
errorDetail : "loopback" ,
} ,
2015-06-03 04:49:51 +00:00
"Address is link-local" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "169.254.169.254" } } ,
Ports : [ ] api . EndpointPort { { Name : "p" , Port : 93 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueInvalid" ,
errorDetail : "link-local" ,
} ,
2015-07-04 04:05:15 +00:00
"Address is link-local multicast" : {
endpoints : api . Endpoints {
ObjectMeta : api . ObjectMeta { Name : "mysvc" , Namespace : "namespace" } ,
Subsets : [ ] api . EndpointSubset {
{
Addresses : [ ] api . EndpointAddress { { IP : "224.0.0.1" } } ,
Ports : [ ] api . EndpointPort { { Name : "p" , Port : 93 , Protocol : "TCP" } } ,
} ,
} ,
} ,
errorType : "FieldValueInvalid" ,
errorDetail : "link-local multicast" ,
} ,
2015-03-20 14:40:20 +00:00
}
for k , v := range errorCases {
2015-06-03 04:49:51 +00:00
if errs := ValidateEndpoints ( & v . endpoints ) ; len ( errs ) == 0 || errs [ 0 ] . ( * errors . ValidationError ) . Type != v . errorType || ! strings . Contains ( errs [ 0 ] . ( * errors . ValidationError ) . Detail , v . errorDetail ) {
2015-03-20 14:40:20 +00:00
t . Errorf ( "Expected error type %s with detail %s for %s, got %v" , v . errorType , v . errorDetail , k , errs )
}
}
2015-03-20 21:24:43 +00:00
}
2015-05-05 23:02:13 +00:00
func TestValidateSecurityContext ( t * testing . T ) {
priv := false
var runAsUser int64 = 1
fullValidSC := func ( ) * api . SecurityContext {
return & api . SecurityContext {
Privileged : & priv ,
Capabilities : & api . Capabilities {
2015-05-18 20:37:10 +00:00
Add : [ ] api . Capability { "foo" } ,
Drop : [ ] api . Capability { "bar" } ,
2015-05-05 23:02:13 +00:00
} ,
SELinuxOptions : & api . SELinuxOptions {
User : "user" ,
Role : "role" ,
Type : "type" ,
Level : "level" ,
} ,
RunAsUser : & runAsUser ,
}
}
//setup data
allSettings := fullValidSC ( )
noCaps := fullValidSC ( )
noCaps . Capabilities = nil
noSELinux := fullValidSC ( )
noSELinux . SELinuxOptions = nil
noPrivRequest := fullValidSC ( )
noPrivRequest . Privileged = nil
noRunAsUser := fullValidSC ( )
noRunAsUser . RunAsUser = nil
successCases := map [ string ] struct {
sc * api . SecurityContext
} {
"all settings" : { allSettings } ,
"no capabilities" : { noCaps } ,
"no selinux" : { noSELinux } ,
"no priv request" : { noPrivRequest } ,
"no run as user" : { noRunAsUser } ,
}
for k , v := range successCases {
if errs := ValidateSecurityContext ( v . sc ) ; len ( errs ) != 0 {
t . Errorf ( "Expected success for %s, got %v" , k , errs )
}
}
privRequestWithGlobalDeny := fullValidSC ( )
requestPrivileged := true
privRequestWithGlobalDeny . Privileged = & requestPrivileged
negativeRunAsUser := fullValidSC ( )
var negativeUser int64 = - 1
negativeRunAsUser . RunAsUser = & negativeUser
errorCases := map [ string ] struct {
sc * api . SecurityContext
errorType fielderrors . ValidationErrorType
errorDetail string
} {
"request privileged when capabilities forbids" : {
sc : privRequestWithGlobalDeny ,
errorType : "FieldValueForbidden" ,
errorDetail : "" ,
} ,
"negative RunAsUser" : {
sc : negativeRunAsUser ,
errorType : "FieldValueInvalid" ,
errorDetail : "runAsUser cannot be negative" ,
} ,
}
for k , v := range errorCases {
if errs := ValidateSecurityContext ( v . sc ) ; len ( errs ) == 0 || errs [ 0 ] . ( * errors . ValidationError ) . Type != v . errorType || errs [ 0 ] . ( * errors . ValidationError ) . Detail != v . errorDetail {
t . Errorf ( "Expected error type %s with detail %s for %s, got %v" , v . errorType , v . errorDetail , k , errs )
}
}
}
func fakeValidSecurityContext ( priv bool ) * api . SecurityContext {
return & api . SecurityContext {
Privileged : & priv ,
}
}
2015-09-10 03:46:11 +00:00
func TestValidPodLogOptions ( t * testing . T ) {
now := unversioned . Now ( )
negative := int64 ( - 1 )
zero := int64 ( 0 )
positive := int64 ( 1 )
tests := [ ] struct {
opt api . PodLogOptions
errs int
} {
{ api . PodLogOptions { } , 0 } ,
{ api . PodLogOptions { Previous : true } , 0 } ,
{ api . PodLogOptions { Follow : true } , 0 } ,
{ api . PodLogOptions { TailLines : & zero } , 0 } ,
{ api . PodLogOptions { TailLines : & negative } , 1 } ,
{ api . PodLogOptions { TailLines : & positive } , 0 } ,
{ api . PodLogOptions { LimitBytes : & zero } , 1 } ,
{ api . PodLogOptions { LimitBytes : & negative } , 1 } ,
{ api . PodLogOptions { LimitBytes : & positive } , 0 } ,
{ api . PodLogOptions { SinceSeconds : & negative } , 1 } ,
{ api . PodLogOptions { SinceSeconds : & positive } , 0 } ,
{ api . PodLogOptions { SinceSeconds : & zero } , 1 } ,
{ api . PodLogOptions { SinceTime : & now } , 0 } ,
}
for i , test := range tests {
errs := ValidatePodLogOptions ( & test . opt )
if test . errs != len ( errs ) {
t . Errorf ( "%d: Unexpected errors: %v" , i , errs )
}
}
}