1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- 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.
- */
- package validation
- import (
- "fmt"
- "strings"
- "testing"
- "k8s.io/kubernetes/pkg/api"
- "k8s.io/kubernetes/pkg/api/unversioned"
- "k8s.io/kubernetes/pkg/apis/extensions"
- "k8s.io/kubernetes/pkg/security/apparmor"
- psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
- "k8s.io/kubernetes/pkg/util/intstr"
- "k8s.io/kubernetes/pkg/util/validation/field"
- )
- func TestValidateDaemonSetStatusUpdate(t *testing.T) {
- type dsUpdateTest struct {
- old extensions.DaemonSet
- update extensions.DaemonSet
- }
- successCases := []dsUpdateTest{
- {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Status: extensions.DaemonSetStatus{
- CurrentNumberScheduled: 1,
- NumberMisscheduled: 2,
- DesiredNumberScheduled: 3,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Status: extensions.DaemonSetStatus{
- CurrentNumberScheduled: 1,
- NumberMisscheduled: 1,
- DesiredNumberScheduled: 3,
- },
- },
- },
- }
- for _, successCase := range successCases {
- successCase.old.ObjectMeta.ResourceVersion = "1"
- successCase.update.ObjectMeta.ResourceVersion = "1"
- if errs := ValidateDaemonSetStatusUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]dsUpdateTest{
- "negative values": {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{
- Name: "abc",
- Namespace: api.NamespaceDefault,
- ResourceVersion: "10",
- },
- Status: extensions.DaemonSetStatus{
- CurrentNumberScheduled: 1,
- NumberMisscheduled: 2,
- DesiredNumberScheduled: 3,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{
- Name: "abc",
- Namespace: api.NamespaceDefault,
- ResourceVersion: "10",
- },
- Status: extensions.DaemonSetStatus{
- CurrentNumberScheduled: -1,
- NumberMisscheduled: -1,
- DesiredNumberScheduled: -3,
- },
- },
- },
- }
- for testName, errorCase := range errorCases {
- if errs := ValidateDaemonSetStatusUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
- t.Errorf("expected failure: %s", testName)
- }
- }
- }
- func TestValidateDaemonSetUpdate(t *testing.T) {
- validSelector := map[string]string{"a": "b"}
- validSelector2 := map[string]string{"c": "d"}
- invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
- validPodSpecAbc := api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- }
- validPodSpecDef := api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "def", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- }
- validPodSpecNodeSelector := api.PodSpec{
- NodeSelector: validSelector,
- NodeName: "xyz",
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- }
- validPodSpecVolume := api.PodSpec{
- Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- }
- validPodTemplateAbc := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector,
- },
- Spec: validPodSpecAbc,
- },
- }
- validPodTemplateNodeSelector := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector,
- },
- Spec: validPodSpecNodeSelector,
- },
- }
- validPodTemplateAbc2 := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector2,
- },
- Spec: validPodSpecAbc,
- },
- }
- validPodTemplateDef := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector2,
- },
- Spec: validPodSpecDef,
- },
- }
- invalidPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- },
- ObjectMeta: api.ObjectMeta{
- Labels: invalidSelector,
- },
- },
- }
- readWriteVolumePodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector,
- },
- Spec: validPodSpecVolume,
- },
- }
- type dsUpdateTest struct {
- old extensions.DaemonSet
- update extensions.DaemonSet
- }
- successCases := []dsUpdateTest{
- {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- },
- {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector2},
- Template: validPodTemplateAbc2.Template,
- },
- },
- },
- {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateNodeSelector.Template,
- },
- },
- },
- }
- for _, successCase := range successCases {
- successCase.old.ObjectMeta.ResourceVersion = "1"
- successCase.update.ObjectMeta.ResourceVersion = "1"
- if errs := ValidateDaemonSetUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]dsUpdateTest{
- "change daemon name": {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- },
- "invalid selector": {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: invalidSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- },
- "invalid pod": {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: invalidPodTemplate.Template,
- },
- },
- },
- "change container image": {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateDef.Template,
- },
- },
- },
- "read-write volume": {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: readWriteVolumePodTemplate.Template,
- },
- },
- },
- "invalid update strategy": {
- old: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- update: extensions.DaemonSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: invalidSelector},
- Template: validPodTemplateAbc.Template,
- },
- },
- },
- }
- for testName, errorCase := range errorCases {
- if errs := ValidateDaemonSetUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
- t.Errorf("expected failure: %s", testName)
- }
- }
- }
- func TestValidateDaemonSet(t *testing.T) {
- validSelector := map[string]string{"a": "b"}
- validPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector,
- },
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- },
- }
- invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
- invalidPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- },
- ObjectMeta: api.ObjectMeta{
- Labels: invalidSelector,
- },
- },
- }
- successCases := []extensions.DaemonSet{
- {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplate.Template,
- },
- },
- {
- ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplate.Template,
- },
- },
- }
- for _, successCase := range successCases {
- if errs := ValidateDaemonSet(&successCase); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]extensions.DaemonSet{
- "zero-length ID": {
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplate.Template,
- },
- },
- "missing-namespace": {
- ObjectMeta: api.ObjectMeta{Name: "abc-123"},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplate.Template,
- },
- },
- "nil selector": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Template: validPodTemplate.Template,
- },
- },
- "empty selector": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{},
- Template: validPodTemplate.Template,
- },
- },
- "selector_doesnt_match": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
- Template: validPodTemplate.Template,
- },
- },
- "invalid template": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- },
- },
- "invalid_label": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- Labels: map[string]string{
- "NoUppercaseOrSpecialCharsLike=Equals": "bar",
- },
- },
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplate.Template,
- },
- },
- "invalid_label 2": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- Labels: map[string]string{
- "NoUppercaseOrSpecialCharsLike=Equals": "bar",
- },
- },
- Spec: extensions.DaemonSetSpec{
- Template: invalidPodTemplate.Template,
- },
- },
- "invalid_annotation": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- Annotations: map[string]string{
- "NoUppercaseOrSpecialCharsLike=Equals": "bar",
- },
- },
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: validPodTemplate.Template,
- },
- },
- "invalid restart policy 1": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyOnFailure,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector,
- },
- },
- },
- },
- "invalid restart policy 2": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.DaemonSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validSelector},
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyNever,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- ObjectMeta: api.ObjectMeta{
- Labels: validSelector,
- },
- },
- },
- },
- }
- for k, v := range errorCases {
- errs := ValidateDaemonSet(&v)
- if len(errs) == 0 {
- t.Errorf("expected failure for %s", k)
- }
- for i := range errs {
- field := errs[i].Field
- if !strings.HasPrefix(field, "spec.template.") &&
- !strings.HasPrefix(field, "spec.updateStrategy") &&
- field != "metadata.name" &&
- field != "metadata.namespace" &&
- field != "spec.selector" &&
- field != "spec.template" &&
- field != "GCEPersistentDisk.ReadOnly" &&
- field != "spec.template.labels" &&
- field != "metadata.annotations" &&
- field != "metadata.labels" {
- t.Errorf("%s: missing prefix for: %v", k, errs[i])
- }
- }
- }
- }
- func validDeployment() *extensions.Deployment {
- return &extensions.Deployment{
- ObjectMeta: api.ObjectMeta{
- Name: "abc",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.DeploymentSpec{
- Selector: &unversioned.LabelSelector{
- MatchLabels: map[string]string{
- "name": "abc",
- },
- },
- Strategy: extensions.DeploymentStrategy{
- Type: extensions.RollingUpdateDeploymentStrategyType,
- RollingUpdate: &extensions.RollingUpdateDeployment{
- MaxSurge: intstr.FromInt(1),
- MaxUnavailable: intstr.FromInt(1),
- },
- },
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Name: "abc",
- Namespace: api.NamespaceDefault,
- Labels: map[string]string{
- "name": "abc",
- },
- },
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSDefault,
- Containers: []api.Container{
- {
- Name: "nginx",
- Image: "image",
- ImagePullPolicy: api.PullNever,
- },
- },
- },
- },
- RollbackTo: &extensions.RollbackConfig{
- Revision: 1,
- },
- },
- }
- }
- func TestValidateDeployment(t *testing.T) {
- successCases := []*extensions.Deployment{
- validDeployment(),
- }
- for _, successCase := range successCases {
- if errs := ValidateDeployment(successCase); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]*extensions.Deployment{}
- errorCases["metadata.name: Required value"] = &extensions.Deployment{
- ObjectMeta: api.ObjectMeta{
- Namespace: api.NamespaceDefault,
- },
- }
- // selector should match the labels in pod template.
- invalidSelectorDeployment := validDeployment()
- invalidSelectorDeployment.Spec.Selector = &unversioned.LabelSelector{
- MatchLabels: map[string]string{
- "name": "def",
- },
- }
- errorCases["`selector` does not match template `labels`"] = invalidSelectorDeployment
- // RestartPolicy should be always.
- invalidRestartPolicyDeployment := validDeployment()
- invalidRestartPolicyDeployment.Spec.Template.Spec.RestartPolicy = api.RestartPolicyNever
- errorCases["Unsupported value: \"Never\""] = invalidRestartPolicyDeployment
- // must have valid strategy type
- invalidStrategyDeployment := validDeployment()
- invalidStrategyDeployment.Spec.Strategy.Type = extensions.DeploymentStrategyType("randomType")
- errorCases["supported values: Recreate, RollingUpdate"] = invalidStrategyDeployment
- // rollingUpdate should be nil for recreate.
- invalidRecreateDeployment := validDeployment()
- invalidRecreateDeployment.Spec.Strategy = extensions.DeploymentStrategy{
- Type: extensions.RecreateDeploymentStrategyType,
- RollingUpdate: &extensions.RollingUpdateDeployment{},
- }
- errorCases["may not be specified when strategy `type` is 'Recreate'"] = invalidRecreateDeployment
- // MaxSurge should be in the form of 20%.
- invalidMaxSurgeDeployment := validDeployment()
- invalidMaxSurgeDeployment.Spec.Strategy = extensions.DeploymentStrategy{
- Type: extensions.RollingUpdateDeploymentStrategyType,
- RollingUpdate: &extensions.RollingUpdateDeployment{
- MaxSurge: intstr.FromString("20Percent"),
- },
- }
- errorCases["must match the regex"] = invalidMaxSurgeDeployment
- // MaxSurge and MaxUnavailable cannot both be zero.
- invalidRollingUpdateDeployment := validDeployment()
- invalidRollingUpdateDeployment.Spec.Strategy = extensions.DeploymentStrategy{
- Type: extensions.RollingUpdateDeploymentStrategyType,
- RollingUpdate: &extensions.RollingUpdateDeployment{
- MaxSurge: intstr.FromString("0%"),
- MaxUnavailable: intstr.FromInt(0),
- },
- }
- errorCases["may not be 0 when `maxSurge` is 0"] = invalidRollingUpdateDeployment
- // MaxUnavailable should not be more than 100%.
- invalidMaxUnavailableDeployment := validDeployment()
- invalidMaxUnavailableDeployment.Spec.Strategy = extensions.DeploymentStrategy{
- Type: extensions.RollingUpdateDeploymentStrategyType,
- RollingUpdate: &extensions.RollingUpdateDeployment{
- MaxUnavailable: intstr.FromString("110%"),
- },
- }
- errorCases["must not be greater than 100%"] = invalidMaxUnavailableDeployment
- // Rollback.Revision must be non-negative
- invalidRollbackRevisionDeployment := validDeployment()
- invalidRollbackRevisionDeployment.Spec.RollbackTo.Revision = -3
- errorCases["must be greater than or equal to 0"] = invalidRollbackRevisionDeployment
- for k, v := range errorCases {
- errs := ValidateDeployment(v)
- if len(errs) == 0 {
- t.Errorf("[%s] expected failure", k)
- } else if !strings.Contains(errs[0].Error(), k) {
- t.Errorf("unexpected error: %q, expected: %q", errs[0].Error(), k)
- }
- }
- }
- func validDeploymentRollback() *extensions.DeploymentRollback {
- return &extensions.DeploymentRollback{
- Name: "abc",
- UpdatedAnnotations: map[string]string{
- "created-by": "abc",
- },
- RollbackTo: extensions.RollbackConfig{
- Revision: 1,
- },
- }
- }
- func TestValidateDeploymentRollback(t *testing.T) {
- noAnnotation := validDeploymentRollback()
- noAnnotation.UpdatedAnnotations = nil
- successCases := []*extensions.DeploymentRollback{
- validDeploymentRollback(),
- noAnnotation,
- }
- for _, successCase := range successCases {
- if errs := ValidateDeploymentRollback(successCase); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]*extensions.DeploymentRollback{}
- invalidNoName := validDeploymentRollback()
- invalidNoName.Name = ""
- errorCases["name: Required value"] = invalidNoName
- for k, v := range errorCases {
- errs := ValidateDeploymentRollback(v)
- if len(errs) == 0 {
- t.Errorf("[%s] expected failure", k)
- } else if !strings.Contains(errs[0].Error(), k) {
- t.Errorf("unexpected error: %q, expected: %q", errs[0].Error(), k)
- }
- }
- }
- type ingressRules map[string]string
- func TestValidateIngress(t *testing.T) {
- defaultBackend := extensions.IngressBackend{
- ServiceName: "default-backend",
- ServicePort: intstr.FromInt(80),
- }
- newValid := func() extensions.Ingress {
- return extensions.Ingress{
- ObjectMeta: api.ObjectMeta{
- Name: "foo",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.IngressSpec{
- Backend: &extensions.IngressBackend{
- ServiceName: "default-backend",
- ServicePort: intstr.FromInt(80),
- },
- Rules: []extensions.IngressRule{
- {
- Host: "foo.bar.com",
- IngressRuleValue: extensions.IngressRuleValue{
- HTTP: &extensions.HTTPIngressRuleValue{
- Paths: []extensions.HTTPIngressPath{
- {
- Path: "/foo",
- Backend: defaultBackend,
- },
- },
- },
- },
- },
- },
- },
- Status: extensions.IngressStatus{
- LoadBalancer: api.LoadBalancerStatus{
- Ingress: []api.LoadBalancerIngress{
- {IP: "127.0.0.1"},
- },
- },
- },
- }
- }
- servicelessBackend := newValid()
- servicelessBackend.Spec.Backend.ServiceName = ""
- invalidNameBackend := newValid()
- invalidNameBackend.Spec.Backend.ServiceName = "defaultBackend"
- noPortBackend := newValid()
- noPortBackend.Spec.Backend = &extensions.IngressBackend{ServiceName: defaultBackend.ServiceName}
- noForwardSlashPath := newValid()
- noForwardSlashPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []extensions.HTTPIngressPath{
- {
- Path: "invalid",
- Backend: defaultBackend,
- },
- }
- noPaths := newValid()
- noPaths.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []extensions.HTTPIngressPath{}
- badHost := newValid()
- badHost.Spec.Rules[0].Host = "foobar:80"
- badRegexPath := newValid()
- badPathExpr := "/invalid["
- badRegexPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []extensions.HTTPIngressPath{
- {
- Path: badPathExpr,
- Backend: defaultBackend,
- },
- }
- badPathErr := fmt.Sprintf("spec.rules[0].http.paths[0].path: Invalid value: '%v'", badPathExpr)
- hostIP := "127.0.0.1"
- badHostIP := newValid()
- badHostIP.Spec.Rules[0].Host = hostIP
- badHostIPErr := fmt.Sprintf("spec.rules[0].host: Invalid value: '%v'", hostIP)
- errorCases := map[string]extensions.Ingress{
- "spec.backend.serviceName: Required value": servicelessBackend,
- "spec.backend.serviceName: Invalid value": invalidNameBackend,
- "spec.backend.servicePort: Invalid value": noPortBackend,
- "spec.rules[0].host: Invalid value": badHost,
- "spec.rules[0].http.paths: Required value": noPaths,
- "spec.rules[0].http.paths[0].path: Invalid value": noForwardSlashPath,
- }
- errorCases[badPathErr] = badRegexPath
- errorCases[badHostIPErr] = badHostIP
- wildcardHost := "foo.*.bar.com"
- badWildcard := newValid()
- badWildcard.Spec.Rules[0].Host = wildcardHost
- badWildcardErr := fmt.Sprintf("spec.rules[0].host: Invalid value: '%v'", wildcardHost)
- errorCases[badWildcardErr] = badWildcard
- for k, v := range errorCases {
- errs := ValidateIngress(&v)
- if len(errs) == 0 {
- t.Errorf("expected failure for %q", k)
- } else {
- s := strings.Split(k, ":")
- err := errs[0]
- if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
- t.Errorf("unexpected error: %q, expected: %q", err, k)
- }
- }
- }
- }
- func TestValidateIngressTLS(t *testing.T) {
- defaultBackend := extensions.IngressBackend{
- ServiceName: "default-backend",
- ServicePort: intstr.FromInt(80),
- }
- newValid := func() extensions.Ingress {
- return extensions.Ingress{
- ObjectMeta: api.ObjectMeta{
- Name: "foo",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.IngressSpec{
- Backend: &extensions.IngressBackend{
- ServiceName: "default-backend",
- ServicePort: intstr.FromInt(80),
- },
- Rules: []extensions.IngressRule{
- {
- Host: "foo.bar.com",
- IngressRuleValue: extensions.IngressRuleValue{
- HTTP: &extensions.HTTPIngressRuleValue{
- Paths: []extensions.HTTPIngressPath{
- {
- Path: "/foo",
- Backend: defaultBackend,
- },
- },
- },
- },
- },
- },
- },
- Status: extensions.IngressStatus{
- LoadBalancer: api.LoadBalancerStatus{
- Ingress: []api.LoadBalancerIngress{
- {IP: "127.0.0.1"},
- },
- },
- },
- }
- }
- errorCases := map[string]extensions.Ingress{}
- wildcardHost := "foo.*.bar.com"
- badWildcardTLS := newValid()
- badWildcardTLS.Spec.Rules[0].Host = "*.foo.bar.com"
- badWildcardTLS.Spec.TLS = []extensions.IngressTLS{
- {
- Hosts: []string{wildcardHost},
- },
- }
- badWildcardTLSErr := fmt.Sprintf("spec.tls[0].hosts: Invalid value: '%v'", wildcardHost)
- errorCases[badWildcardTLSErr] = badWildcardTLS
- for k, v := range errorCases {
- errs := ValidateIngress(&v)
- if len(errs) == 0 {
- t.Errorf("expected failure for %q", k)
- } else {
- s := strings.Split(k, ":")
- err := errs[0]
- if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
- t.Errorf("unexpected error: %q, expected: %q", err, k)
- }
- }
- }
- }
- func TestValidateIngressStatusUpdate(t *testing.T) {
- defaultBackend := extensions.IngressBackend{
- ServiceName: "default-backend",
- ServicePort: intstr.FromInt(80),
- }
- newValid := func() extensions.Ingress {
- return extensions.Ingress{
- ObjectMeta: api.ObjectMeta{
- Name: "foo",
- Namespace: api.NamespaceDefault,
- ResourceVersion: "9",
- },
- Spec: extensions.IngressSpec{
- Backend: &extensions.IngressBackend{
- ServiceName: "default-backend",
- ServicePort: intstr.FromInt(80),
- },
- Rules: []extensions.IngressRule{
- {
- Host: "foo.bar.com",
- IngressRuleValue: extensions.IngressRuleValue{
- HTTP: &extensions.HTTPIngressRuleValue{
- Paths: []extensions.HTTPIngressPath{
- {
- Path: "/foo",
- Backend: defaultBackend,
- },
- },
- },
- },
- },
- },
- },
- Status: extensions.IngressStatus{
- LoadBalancer: api.LoadBalancerStatus{
- Ingress: []api.LoadBalancerIngress{
- {IP: "127.0.0.1", Hostname: "foo.bar.com"},
- },
- },
- },
- }
- }
- oldValue := newValid()
- newValue := newValid()
- newValue.Status = extensions.IngressStatus{
- LoadBalancer: api.LoadBalancerStatus{
- Ingress: []api.LoadBalancerIngress{
- {IP: "127.0.0.2", Hostname: "foo.com"},
- },
- },
- }
- invalidIP := newValid()
- invalidIP.Status = extensions.IngressStatus{
- LoadBalancer: api.LoadBalancerStatus{
- Ingress: []api.LoadBalancerIngress{
- {IP: "abcd", Hostname: "foo.com"},
- },
- },
- }
- invalidHostname := newValid()
- invalidHostname.Status = extensions.IngressStatus{
- LoadBalancer: api.LoadBalancerStatus{
- Ingress: []api.LoadBalancerIngress{
- {IP: "127.0.0.1", Hostname: "127.0.0.1"},
- },
- },
- }
- errs := ValidateIngressStatusUpdate(&newValue, &oldValue)
- if len(errs) != 0 {
- t.Errorf("Unexpected error %v", errs)
- }
- errorCases := map[string]extensions.Ingress{
- "status.loadBalancer.ingress[0].ip: Invalid value": invalidIP,
- "status.loadBalancer.ingress[0].hostname: Invalid value": invalidHostname,
- }
- for k, v := range errorCases {
- errs := ValidateIngressStatusUpdate(&v, &oldValue)
- if len(errs) == 0 {
- t.Errorf("expected failure for %s", k)
- } else {
- s := strings.Split(k, ":")
- err := errs[0]
- if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
- t.Errorf("unexpected error: %q, expected: %q", err, k)
- }
- }
- }
- }
- func TestValidateScale(t *testing.T) {
- successCases := []extensions.Scale{
- {
- ObjectMeta: api.ObjectMeta{
- Name: "frontend",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.ScaleSpec{
- Replicas: 1,
- },
- },
- {
- ObjectMeta: api.ObjectMeta{
- Name: "frontend",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.ScaleSpec{
- Replicas: 10,
- },
- },
- {
- ObjectMeta: api.ObjectMeta{
- Name: "frontend",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.ScaleSpec{
- Replicas: 0,
- },
- },
- }
- for _, successCase := range successCases {
- if errs := ValidateScale(&successCase); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := []struct {
- scale extensions.Scale
- msg string
- }{
- {
- scale: extensions.Scale{
- ObjectMeta: api.ObjectMeta{
- Name: "frontend",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.ScaleSpec{
- Replicas: -1,
- },
- },
- msg: "must be greater than or equal to 0",
- },
- }
- for _, c := range errorCases {
- if errs := ValidateScale(&c.scale); len(errs) == 0 {
- t.Errorf("expected failure for %s", c.msg)
- } else if !strings.Contains(errs[0].Error(), c.msg) {
- t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg)
- }
- }
- }
- func TestValidateReplicaSetStatusUpdate(t *testing.T) {
- validLabels := map[string]string{"a": "b"}
- validPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validLabels,
- },
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- },
- }
- type rcUpdateTest struct {
- old extensions.ReplicaSet
- update extensions.ReplicaSet
- }
- successCases := []rcUpdateTest{
- {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- Status: extensions.ReplicaSetStatus{
- Replicas: 2,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 3,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- Status: extensions.ReplicaSetStatus{
- Replicas: 4,
- },
- },
- },
- }
- for _, successCase := range successCases {
- successCase.old.ObjectMeta.ResourceVersion = "1"
- successCase.update.ObjectMeta.ResourceVersion = "1"
- if errs := ValidateReplicaSetStatusUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]rcUpdateTest{
- "negative replicas": {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- Status: extensions.ReplicaSetStatus{
- Replicas: 3,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 2,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- Status: extensions.ReplicaSetStatus{
- Replicas: -3,
- },
- },
- },
- }
- for testName, errorCase := range errorCases {
- if errs := ValidateReplicaSetStatusUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
- t.Errorf("expected failure: %s", testName)
- }
- }
- }
- func TestValidateReplicaSetUpdate(t *testing.T) {
- validLabels := map[string]string{"a": "b"}
- validPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validLabels,
- },
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- },
- }
- readWriteVolumePodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validLabels,
- },
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
- },
- },
- }
- invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
- invalidPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- },
- ObjectMeta: api.ObjectMeta{
- Labels: invalidLabels,
- },
- },
- }
- type rcUpdateTest struct {
- old extensions.ReplicaSet
- update extensions.ReplicaSet
- }
- successCases := []rcUpdateTest{
- {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 3,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- },
- {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 1,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: readWriteVolumePodTemplate.Template,
- },
- },
- },
- }
- for _, successCase := range successCases {
- successCase.old.ObjectMeta.ResourceVersion = "1"
- successCase.update.ObjectMeta.ResourceVersion = "1"
- if errs := ValidateReplicaSetUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]rcUpdateTest{
- "more than one read/write": {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 2,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: readWriteVolumePodTemplate.Template,
- },
- },
- },
- "invalid selector": {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 2,
- Selector: &unversioned.LabelSelector{MatchLabels: invalidLabels},
- Template: validPodTemplate.Template,
- },
- },
- },
- "invalid pod": {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 2,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: invalidPodTemplate.Template,
- },
- },
- },
- "negative replicas": {
- old: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- update: extensions.ReplicaSet{
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: -1,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- },
- }
- for testName, errorCase := range errorCases {
- if errs := ValidateReplicaSetUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
- t.Errorf("expected failure: %s", testName)
- }
- }
- }
- func TestValidateReplicaSet(t *testing.T) {
- validLabels := map[string]string{"a": "b"}
- validPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validLabels,
- },
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- },
- }
- readWriteVolumePodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- ObjectMeta: api.ObjectMeta{
- Labels: validLabels,
- },
- Spec: api.PodSpec{
- Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}},
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- },
- }
- invalidLabels := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
- invalidPodTemplate := api.PodTemplate{
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyAlways,
- DNSPolicy: api.DNSClusterFirst,
- },
- ObjectMeta: api.ObjectMeta{
- Labels: invalidLabels,
- },
- },
- }
- successCases := []extensions.ReplicaSet{
- {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- {
- ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- {
- ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 1,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: readWriteVolumePodTemplate.Template,
- },
- },
- }
- for _, successCase := range successCases {
- if errs := ValidateReplicaSet(&successCase); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]extensions.ReplicaSet{
- "zero-length ID": {
- ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- "missing-namespace": {
- ObjectMeta: api.ObjectMeta{Name: "abc-123"},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- "empty selector": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Template: validPodTemplate.Template,
- },
- },
- "selector_doesnt_match": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
- Template: validPodTemplate.Template,
- },
- },
- "invalid manifest": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- },
- },
- "read-write persistent disk with > 1 pod": {
- ObjectMeta: api.ObjectMeta{Name: "abc"},
- Spec: extensions.ReplicaSetSpec{
- Replicas: 2,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: readWriteVolumePodTemplate.Template,
- },
- },
- "negative_replicas": {
- ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
- Spec: extensions.ReplicaSetSpec{
- Replicas: -1,
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- },
- },
- "invalid_label": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- Labels: map[string]string{
- "NoUppercaseOrSpecialCharsLike=Equals": "bar",
- },
- },
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- "invalid_label 2": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- Labels: map[string]string{
- "NoUppercaseOrSpecialCharsLike=Equals": "bar",
- },
- },
- Spec: extensions.ReplicaSetSpec{
- Template: invalidPodTemplate.Template,
- },
- },
- "invalid_annotation": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- Annotations: map[string]string{
- "NoUppercaseOrSpecialCharsLike=Equals": "bar",
- },
- },
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: validPodTemplate.Template,
- },
- },
- "invalid restart policy 1": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyOnFailure,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- ObjectMeta: api.ObjectMeta{
- Labels: validLabels,
- },
- },
- },
- },
- "invalid restart policy 2": {
- ObjectMeta: api.ObjectMeta{
- Name: "abc-123",
- Namespace: api.NamespaceDefault,
- },
- Spec: extensions.ReplicaSetSpec{
- Selector: &unversioned.LabelSelector{MatchLabels: validLabels},
- Template: api.PodTemplateSpec{
- Spec: api.PodSpec{
- RestartPolicy: api.RestartPolicyNever,
- DNSPolicy: api.DNSClusterFirst,
- Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}},
- },
- ObjectMeta: api.ObjectMeta{
- Labels: validLabels,
- },
- },
- },
- },
- }
- for k, v := range errorCases {
- errs := ValidateReplicaSet(&v)
- if len(errs) == 0 {
- t.Errorf("expected failure for %s", k)
- }
- for i := range errs {
- field := errs[i].Field
- if !strings.HasPrefix(field, "spec.template.") &&
- field != "metadata.name" &&
- field != "metadata.namespace" &&
- field != "spec.selector" &&
- field != "spec.template" &&
- field != "GCEPersistentDisk.ReadOnly" &&
- field != "spec.replicas" &&
- field != "spec.template.labels" &&
- field != "metadata.annotations" &&
- field != "metadata.labels" &&
- field != "status.replicas" {
- t.Errorf("%s: missing prefix for: %v", k, errs[i])
- }
- }
- }
- }
- func TestValidatePodSecurityPolicy(t *testing.T) {
- validPSP := func() *extensions.PodSecurityPolicy {
- return &extensions.PodSecurityPolicy{
- ObjectMeta: api.ObjectMeta{
- Name: "foo",
- Annotations: map[string]string{},
- },
- Spec: extensions.PodSecurityPolicySpec{
- SELinux: extensions.SELinuxStrategyOptions{
- Rule: extensions.SELinuxStrategyRunAsAny,
- },
- RunAsUser: extensions.RunAsUserStrategyOptions{
- Rule: extensions.RunAsUserStrategyRunAsAny,
- },
- FSGroup: extensions.FSGroupStrategyOptions{
- Rule: extensions.FSGroupStrategyRunAsAny,
- },
- SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
- Rule: extensions.SupplementalGroupsStrategyRunAsAny,
- },
- },
- }
- }
- noUserOptions := validPSP()
- noUserOptions.Spec.RunAsUser.Rule = ""
- noSELinuxOptions := validPSP()
- noSELinuxOptions.Spec.SELinux.Rule = ""
- invalidUserStratType := validPSP()
- invalidUserStratType.Spec.RunAsUser.Rule = "invalid"
- invalidSELinuxStratType := validPSP()
- invalidSELinuxStratType.Spec.SELinux.Rule = "invalid"
- invalidUIDPSP := validPSP()
- invalidUIDPSP.Spec.RunAsUser.Rule = extensions.RunAsUserStrategyMustRunAs
- invalidUIDPSP.Spec.RunAsUser.Ranges = []extensions.IDRange{
- {Min: -1, Max: 1},
- }
- missingObjectMetaName := validPSP()
- missingObjectMetaName.ObjectMeta.Name = ""
- noFSGroupOptions := validPSP()
- noFSGroupOptions.Spec.FSGroup.Rule = ""
- invalidFSGroupStratType := validPSP()
- invalidFSGroupStratType.Spec.FSGroup.Rule = "invalid"
- noSupplementalGroupsOptions := validPSP()
- noSupplementalGroupsOptions.Spec.SupplementalGroups.Rule = ""
- invalidSupGroupStratType := validPSP()
- invalidSupGroupStratType.Spec.SupplementalGroups.Rule = "invalid"
- invalidRangeMinGreaterThanMax := validPSP()
- invalidRangeMinGreaterThanMax.Spec.FSGroup.Ranges = []extensions.IDRange{
- {Min: 2, Max: 1},
- }
- invalidRangeNegativeMin := validPSP()
- invalidRangeNegativeMin.Spec.FSGroup.Ranges = []extensions.IDRange{
- {Min: -1, Max: 10},
- }
- invalidRangeNegativeMax := validPSP()
- invalidRangeNegativeMax.Spec.FSGroup.Ranges = []extensions.IDRange{
- {Min: 1, Max: -10},
- }
- requiredCapAddAndDrop := validPSP()
- requiredCapAddAndDrop.Spec.DefaultAddCapabilities = []api.Capability{"foo"}
- requiredCapAddAndDrop.Spec.RequiredDropCapabilities = []api.Capability{"foo"}
- allowedCapListedInRequiredDrop := validPSP()
- allowedCapListedInRequiredDrop.Spec.RequiredDropCapabilities = []api.Capability{"foo"}
- allowedCapListedInRequiredDrop.Spec.AllowedCapabilities = []api.Capability{"foo"}
- invalidAppArmorDefault := validPSP()
- invalidAppArmorDefault.Annotations = map[string]string{
- apparmor.DefaultProfileAnnotationKey: "not-good",
- }
- invalidAppArmorAllowed := validPSP()
- invalidAppArmorAllowed.Annotations = map[string]string{
- apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault + ",not-good",
- }
- invalidSysctlPattern := validPSP()
- invalidSysctlPattern.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "a.*.b"
- errorCases := map[string]struct {
- psp *extensions.PodSecurityPolicy
- errorType field.ErrorType
- errorDetail string
- }{
- "no user options": {
- psp: noUserOptions,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, MustRunAsNonRoot, RunAsAny",
- },
- "no selinux options": {
- psp: noSELinuxOptions,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, RunAsAny",
- },
- "no fsgroup options": {
- psp: noFSGroupOptions,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, RunAsAny",
- },
- "no sup group options": {
- psp: noSupplementalGroupsOptions,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, RunAsAny",
- },
- "invalid user strategy type": {
- psp: invalidUserStratType,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, MustRunAsNonRoot, RunAsAny",
- },
- "invalid selinux strategy type": {
- psp: invalidSELinuxStratType,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, RunAsAny",
- },
- "invalid sup group strategy type": {
- psp: invalidSupGroupStratType,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, RunAsAny",
- },
- "invalid fs group strategy type": {
- psp: invalidFSGroupStratType,
- errorType: field.ErrorTypeNotSupported,
- errorDetail: "supported values: MustRunAs, RunAsAny",
- },
- "invalid uid": {
- psp: invalidUIDPSP,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "min cannot be negative",
- },
- "missing object meta name": {
- psp: missingObjectMetaName,
- errorType: field.ErrorTypeRequired,
- errorDetail: "name or generateName is required",
- },
- "invalid range min greater than max": {
- psp: invalidRangeMinGreaterThanMax,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "min cannot be greater than max",
- },
- "invalid range negative min": {
- psp: invalidRangeNegativeMin,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "min cannot be negative",
- },
- "invalid range negative max": {
- psp: invalidRangeNegativeMax,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "max cannot be negative",
- },
- "invalid required caps": {
- psp: requiredCapAddAndDrop,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "capability is listed in defaultAddCapabilities and requiredDropCapabilities",
- },
- "allowed cap listed in required drops": {
- psp: allowedCapListedInRequiredDrop,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "capability is listed in allowedCapabilities and requiredDropCapabilities",
- },
- "invalid AppArmor default profile": {
- psp: invalidAppArmorDefault,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "invalid AppArmor profile name: \"not-good\"",
- },
- "invalid AppArmor allowed profile": {
- psp: invalidAppArmorAllowed,
- errorType: field.ErrorTypeInvalid,
- errorDetail: "invalid AppArmor profile name: \"not-good\"",
- },
- "invalid sysctl pattern": {
- psp: invalidSysctlPattern,
- errorType: field.ErrorTypeInvalid,
- errorDetail: fmt.Sprintf("must have at most 253 characters and match regex %s", SysctlPatternFmt),
- },
- }
- for k, v := range errorCases {
- errs := ValidatePodSecurityPolicy(v.psp)
- if len(errs) == 0 {
- t.Errorf("%s expected errors but got none", k)
- continue
- }
- if errs[0].Type != v.errorType {
- t.Errorf("%s received an unexpected error type. Expected: %v got: %v", k, v.errorType, errs[0].Type)
- }
- if errs[0].Detail != v.errorDetail {
- t.Errorf("%s received an unexpected error detail. Expected %v got: %v", k, v.errorDetail, errs[0].Detail)
- }
- }
- mustRunAs := validPSP()
- mustRunAs.Spec.FSGroup.Rule = extensions.FSGroupStrategyMustRunAs
- mustRunAs.Spec.SupplementalGroups.Rule = extensions.SupplementalGroupsStrategyMustRunAs
- mustRunAs.Spec.RunAsUser.Rule = extensions.RunAsUserStrategyMustRunAs
- mustRunAs.Spec.RunAsUser.Ranges = []extensions.IDRange{
- {Min: 1, Max: 1},
- }
- mustRunAs.Spec.SELinux.Rule = extensions.SELinuxStrategyMustRunAs
- runAsNonRoot := validPSP()
- runAsNonRoot.Spec.RunAsUser.Rule = extensions.RunAsUserStrategyMustRunAsNonRoot
- caseInsensitiveAddDrop := validPSP()
- caseInsensitiveAddDrop.Spec.DefaultAddCapabilities = []api.Capability{"foo"}
- caseInsensitiveAddDrop.Spec.RequiredDropCapabilities = []api.Capability{"FOO"}
- caseInsensitiveAllowedDrop := validPSP()
- caseInsensitiveAllowedDrop.Spec.RequiredDropCapabilities = []api.Capability{"FOO"}
- caseInsensitiveAllowedDrop.Spec.AllowedCapabilities = []api.Capability{"foo"}
- validAppArmor := validPSP()
- validAppArmor.Annotations = map[string]string{
- apparmor.DefaultProfileAnnotationKey: apparmor.ProfileRuntimeDefault,
- apparmor.AllowedProfilesAnnotationKey: apparmor.ProfileRuntimeDefault + "," + apparmor.ProfileNamePrefix + "foo",
- }
- withSysctl := validPSP()
- withSysctl.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "net.*"
- successCases := map[string]struct {
- psp *extensions.PodSecurityPolicy
- }{
- "must run as": {
- psp: mustRunAs,
- },
- "run as any": {
- psp: validPSP(),
- },
- "run as non-root (user only)": {
- psp: runAsNonRoot,
- },
- "comparison for add -> drop is case sensitive": {
- psp: caseInsensitiveAddDrop,
- },
- "comparison for allowed -> drop is case sensitive": {
- psp: caseInsensitiveAllowedDrop,
- },
- "valid AppArmor annotations": {
- psp: validAppArmor,
- },
- "with network sysctls": {
- psp: withSysctl,
- },
- }
- for k, v := range successCases {
- if errs := ValidatePodSecurityPolicy(v.psp); len(errs) != 0 {
- t.Errorf("Expected success for %s, got %v", k, errs)
- }
- }
- }
- func TestValidatePSPVolumes(t *testing.T) {
- validPSP := func() *extensions.PodSecurityPolicy {
- return &extensions.PodSecurityPolicy{
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Spec: extensions.PodSecurityPolicySpec{
- SELinux: extensions.SELinuxStrategyOptions{
- Rule: extensions.SELinuxStrategyRunAsAny,
- },
- RunAsUser: extensions.RunAsUserStrategyOptions{
- Rule: extensions.RunAsUserStrategyRunAsAny,
- },
- FSGroup: extensions.FSGroupStrategyOptions{
- Rule: extensions.FSGroupStrategyRunAsAny,
- },
- SupplementalGroups: extensions.SupplementalGroupsStrategyOptions{
- Rule: extensions.SupplementalGroupsStrategyRunAsAny,
- },
- },
- }
- }
- volumes := psputil.GetAllFSTypesAsSet()
- // add in the * value since that is a pseudo type that is not included by default
- volumes.Insert(string(extensions.All))
- for _, strVolume := range volumes.List() {
- psp := validPSP()
- psp.Spec.Volumes = []extensions.FSType{extensions.FSType(strVolume)}
- errs := ValidatePodSecurityPolicy(psp)
- if len(errs) != 0 {
- t.Errorf("%s validation expected no errors but received %v", strVolume, errs)
- }
- }
- }
- func TestValidateNetworkPolicy(t *testing.T) {
- successCases := []extensions.NetworkPolicy{
- {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{},
- },
- },
- {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{
- {
- From: []extensions.NetworkPolicyPeer{},
- Ports: []extensions.NetworkPolicyPort{},
- },
- },
- },
- },
- {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{
- {
- From: []extensions.NetworkPolicyPeer{
- {
- PodSelector: &unversioned.LabelSelector{
- MatchLabels: map[string]string{"c": "d"},
- },
- },
- },
- },
- },
- },
- },
- {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{
- {
- From: []extensions.NetworkPolicyPeer{
- {
- NamespaceSelector: &unversioned.LabelSelector{
- MatchLabels: map[string]string{"c": "d"},
- },
- },
- },
- },
- },
- },
- },
- }
- // Success cases are expected to pass validation.
- for k, v := range successCases {
- if errs := ValidateNetworkPolicy(&v); len(errs) != 0 {
- t.Errorf("Expected success for %d, got %v", k, errs)
- }
- }
- invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
- errorCases := map[string]extensions.NetworkPolicy{
- "namespaceSelector and podSelector": {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{
- {
- From: []extensions.NetworkPolicyPeer{
- {
- PodSelector: &unversioned.LabelSelector{
- MatchLabels: map[string]string{"c": "d"},
- },
- NamespaceSelector: &unversioned.LabelSelector{
- MatchLabels: map[string]string{"c": "d"},
- },
- },
- },
- },
- },
- },
- },
- "invalid spec.podSelector": {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: invalidSelector,
- },
- Ingress: []extensions.NetworkPolicyIngressRule{
- {
- From: []extensions.NetworkPolicyPeer{
- {
- NamespaceSelector: &unversioned.LabelSelector{
- MatchLabels: map[string]string{"c": "d"},
- },
- },
- },
- },
- },
- },
- },
- "invalid ingress.from.podSelector": {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{},
- Ingress: []extensions.NetworkPolicyIngressRule{
- {
- From: []extensions.NetworkPolicyPeer{
- {
- PodSelector: &unversioned.LabelSelector{
- MatchLabels: invalidSelector,
- },
- },
- },
- },
- },
- },
- },
- "invalid ingress.from.namespaceSelector": {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{},
- Ingress: []extensions.NetworkPolicyIngressRule{
- {
- From: []extensions.NetworkPolicyPeer{
- {
- NamespaceSelector: &unversioned.LabelSelector{
- MatchLabels: invalidSelector,
- },
- },
- },
- },
- },
- },
- },
- }
- // Error cases are not expected to pass validation.
- for testName, networkPolicy := range errorCases {
- if errs := ValidateNetworkPolicy(&networkPolicy); len(errs) == 0 {
- t.Errorf("Expected failure for test: %s", testName)
- }
- }
- }
- func TestValidateNetworkPolicyUpdate(t *testing.T) {
- type npUpdateTest struct {
- old extensions.NetworkPolicy
- update extensions.NetworkPolicy
- }
- successCases := []npUpdateTest{
- {
- old: extensions.NetworkPolicy{
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{},
- },
- },
- update: extensions.NetworkPolicy{
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{},
- },
- },
- },
- }
- for _, successCase := range successCases {
- successCase.old.ObjectMeta.ResourceVersion = "1"
- successCase.update.ObjectMeta.ResourceVersion = "1"
- if errs := ValidateNetworkPolicyUpdate(&successCase.update, &successCase.old); len(errs) != 0 {
- t.Errorf("expected success: %v", errs)
- }
- }
- errorCases := map[string]npUpdateTest{
- "change name": {
- old: extensions.NetworkPolicy{
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{},
- Ingress: []extensions.NetworkPolicyIngressRule{},
- },
- },
- update: extensions.NetworkPolicy{
- ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{},
- Ingress: []extensions.NetworkPolicyIngressRule{},
- },
- },
- },
- "change spec": {
- old: extensions.NetworkPolicy{
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{},
- Ingress: []extensions.NetworkPolicyIngressRule{},
- },
- },
- update: extensions.NetworkPolicy{
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Spec: extensions.NetworkPolicySpec{
- PodSelector: unversioned.LabelSelector{
- MatchLabels: map[string]string{"a": "b"},
- },
- Ingress: []extensions.NetworkPolicyIngressRule{},
- },
- },
- },
- }
- for testName, errorCase := range errorCases {
- if errs := ValidateNetworkPolicyUpdate(&errorCase.update, &errorCase.old); len(errs) == 0 {
- t.Errorf("expected failure: %s", testName)
- }
- }
- }
- func TestIsValidSysctlPattern(t *testing.T) {
- valid := []string{
- "a.b.c.d",
- "a",
- "a_b",
- "a-b",
- "abc",
- "abc.def",
- "*",
- "a.*",
- "*",
- "abc*",
- "a.abc*",
- "a.b.*",
- }
- invalid := []string{
- "",
- "ä",
- "a_",
- "_",
- "_a",
- "_a._b",
- "__",
- "-",
- ".",
- "a.",
- ".a",
- "a.b.",
- "a*.b",
- "a*b",
- "*a",
- "Abc",
- func(n int) string {
- x := make([]byte, n)
- for i := range x {
- x[i] = byte('a')
- }
- return string(x)
- }(256),
- }
- for _, s := range valid {
- if !IsValidSysctlPattern(s) {
- t.Errorf("%q expected to be a valid sysctl pattern", s)
- }
- }
- for _, s := range invalid {
- if IsValidSysctlPattern(s) {
- t.Errorf("%q expected to be an invalid sysctl pattern", s)
- }
- }
- }
- func newBool(val bool) *bool {
- p := new(bool)
- *p = val
- return p
- }
- func TestValidateStorageClass(t *testing.T) {
- successCases := []extensions.StorageClass{
- {
- // empty parameters
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Provisioner: "kubernetes.io/foo-provisioner",
- Parameters: map[string]string{},
- },
- {
- // nil parameters
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Provisioner: "kubernetes.io/foo-provisioner",
- },
- {
- // some parameters
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Provisioner: "kubernetes.io/foo-provisioner",
- Parameters: map[string]string{
- "kubernetes.io/foo-parameter": "free/form/string",
- "foo-parameter": "free-form-string",
- "foo-parameter2": "{\"embedded\": \"json\", \"with\": {\"structures\":\"inside\"}}",
- },
- },
- }
- // Success cases are expected to pass validation.
- for k, v := range successCases {
- if errs := ValidateStorageClass(&v); len(errs) != 0 {
- t.Errorf("Expected success for %d, got %v", k, errs)
- }
- }
- // generate a map longer than maxProvisionerParameterSize
- longParameters := make(map[string]string)
- totalSize := 0
- for totalSize < maxProvisionerParameterSize {
- k := fmt.Sprintf("param/%d", totalSize)
- v := fmt.Sprintf("value-%d", totalSize)
- longParameters[k] = v
- totalSize = totalSize + len(k) + len(v)
- }
- errorCases := map[string]extensions.StorageClass{
- "namespace is present": {
- ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},
- Provisioner: "kubernetes.io/foo-provisioner",
- },
- "invalid provisioner": {
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Provisioner: "kubernetes.io/invalid/provisioner",
- },
- "invalid empty parameter name": {
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Provisioner: "kubernetes.io/foo",
- Parameters: map[string]string{
- "": "value",
- },
- },
- "provisioner: Required value": {
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Provisioner: "",
- },
- "too long parameters": {
- ObjectMeta: api.ObjectMeta{Name: "foo"},
- Provisioner: "kubernetes.io/foo",
- Parameters: longParameters,
- },
- }
- // Error cases are not expected to pass validation.
- for testName, storageClass := range errorCases {
- if errs := ValidateStorageClass(&storageClass); len(errs) == 0 {
- t.Errorf("Expected failure for test: %s", testName)
- }
- }
- }
|