kubelet_test.go 119 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package kubelet
  14. import (
  15. "bytes"
  16. "errors"
  17. "fmt"
  18. "io"
  19. "io/ioutil"
  20. "net"
  21. "os"
  22. "reflect"
  23. "sort"
  24. "testing"
  25. "time"
  26. cadvisorapi "github.com/google/cadvisor/info/v1"
  27. cadvisorapiv2 "github.com/google/cadvisor/info/v2"
  28. "github.com/stretchr/testify/assert"
  29. "k8s.io/kubernetes/pkg/api"
  30. "k8s.io/kubernetes/pkg/api/resource"
  31. "k8s.io/kubernetes/pkg/api/testapi"
  32. "k8s.io/kubernetes/pkg/api/unversioned"
  33. "k8s.io/kubernetes/pkg/apis/componentconfig"
  34. "k8s.io/kubernetes/pkg/capabilities"
  35. "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
  36. "k8s.io/kubernetes/pkg/client/record"
  37. "k8s.io/kubernetes/pkg/client/testing/core"
  38. cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
  39. "k8s.io/kubernetes/pkg/kubelet/cm"
  40. "k8s.io/kubernetes/pkg/kubelet/config"
  41. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  42. containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
  43. "k8s.io/kubernetes/pkg/kubelet/eviction"
  44. "k8s.io/kubernetes/pkg/kubelet/images"
  45. "k8s.io/kubernetes/pkg/kubelet/lifecycle"
  46. "k8s.io/kubernetes/pkg/kubelet/network"
  47. nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
  48. "k8s.io/kubernetes/pkg/kubelet/pleg"
  49. kubepod "k8s.io/kubernetes/pkg/kubelet/pod"
  50. podtest "k8s.io/kubernetes/pkg/kubelet/pod/testing"
  51. proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
  52. probetest "k8s.io/kubernetes/pkg/kubelet/prober/testing"
  53. "k8s.io/kubernetes/pkg/kubelet/server/stats"
  54. "k8s.io/kubernetes/pkg/kubelet/status"
  55. kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
  56. "k8s.io/kubernetes/pkg/kubelet/util/queue"
  57. kubeletvolume "k8s.io/kubernetes/pkg/kubelet/volumemanager"
  58. "k8s.io/kubernetes/pkg/runtime"
  59. "k8s.io/kubernetes/pkg/types"
  60. "k8s.io/kubernetes/pkg/util/clock"
  61. "k8s.io/kubernetes/pkg/util/diff"
  62. "k8s.io/kubernetes/pkg/util/flowcontrol"
  63. "k8s.io/kubernetes/pkg/util/mount"
  64. utilruntime "k8s.io/kubernetes/pkg/util/runtime"
  65. "k8s.io/kubernetes/pkg/util/sets"
  66. "k8s.io/kubernetes/pkg/util/term"
  67. "k8s.io/kubernetes/pkg/util/wait"
  68. "k8s.io/kubernetes/pkg/volume"
  69. _ "k8s.io/kubernetes/pkg/volume/host_path"
  70. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  71. "k8s.io/kubernetes/pkg/volume/util/volumehelper"
  72. )
  73. func init() {
  74. utilruntime.ReallyCrash = true
  75. }
  76. const (
  77. testKubeletHostname = "127.0.0.1"
  78. testReservationCPU = "200m"
  79. testReservationMemory = "100M"
  80. maxImageTagsForTest = 3
  81. // TODO(harry) any global place for these two?
  82. // Reasonable size range of all container images. 90%ile of images on dockerhub drops into this range.
  83. minImgSize int64 = 23 * 1024 * 1024
  84. maxImgSize int64 = 1000 * 1024 * 1024
  85. )
  86. type TestKubelet struct {
  87. kubelet *Kubelet
  88. fakeRuntime *containertest.FakeRuntime
  89. fakeCadvisor *cadvisortest.Mock
  90. fakeKubeClient *fake.Clientset
  91. fakeMirrorClient *podtest.FakeMirrorClient
  92. fakeClock *clock.FakeClock
  93. mounter mount.Interface
  94. volumePlugin *volumetest.FakeVolumePlugin
  95. }
  96. // newTestKubelet returns test kubelet with two images.
  97. func newTestKubelet(t *testing.T, controllerAttachDetachEnabled bool) *TestKubelet {
  98. imageList := []kubecontainer.Image{
  99. {
  100. ID: "abc",
  101. RepoTags: []string{"gcr.io/google_containers:v1", "gcr.io/google_containers:v2"},
  102. Size: 123,
  103. },
  104. {
  105. ID: "efg",
  106. RepoTags: []string{"gcr.io/google_containers:v3", "gcr.io/google_containers:v4"},
  107. Size: 456,
  108. },
  109. }
  110. return newTestKubeletWithImageList(t, imageList, controllerAttachDetachEnabled)
  111. }
  112. func newTestKubeletWithImageList(
  113. t *testing.T,
  114. imageList []kubecontainer.Image,
  115. controllerAttachDetachEnabled bool) *TestKubelet {
  116. fakeRuntime := &containertest.FakeRuntime{}
  117. fakeRuntime.RuntimeType = "test"
  118. fakeRuntime.VersionInfo = "1.5.0"
  119. fakeRuntime.ImageList = imageList
  120. fakeRecorder := &record.FakeRecorder{}
  121. fakeKubeClient := &fake.Clientset{}
  122. kubelet := &Kubelet{}
  123. kubelet.recorder = fakeRecorder
  124. kubelet.kubeClient = fakeKubeClient
  125. kubelet.os = &containertest.FakeOS{}
  126. kubelet.hostname = testKubeletHostname
  127. kubelet.nodeName = testKubeletHostname
  128. kubelet.runtimeState = newRuntimeState(maxWaitForContainerRuntime)
  129. kubelet.runtimeState.setNetworkState(nil)
  130. kubelet.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", nettest.NewFakeHost(nil), componentconfig.HairpinNone, kubelet.nonMasqueradeCIDR, 1440)
  131. if tempDir, err := ioutil.TempDir("/tmp", "kubelet_test."); err != nil {
  132. t.Fatalf("can't make a temp rootdir: %v", err)
  133. } else {
  134. kubelet.rootDirectory = tempDir
  135. }
  136. if err := os.MkdirAll(kubelet.rootDirectory, 0750); err != nil {
  137. t.Fatalf("can't mkdir(%q): %v", kubelet.rootDirectory, err)
  138. }
  139. kubelet.sourcesReady = config.NewSourcesReady(func(_ sets.String) bool { return true })
  140. kubelet.masterServiceNamespace = api.NamespaceDefault
  141. kubelet.serviceLister = testServiceLister{}
  142. kubelet.nodeLister = testNodeLister{}
  143. kubelet.nodeInfo = testNodeInfo{}
  144. kubelet.recorder = fakeRecorder
  145. if err := kubelet.setupDataDirs(); err != nil {
  146. t.Fatalf("can't initialize kubelet data dirs: %v", err)
  147. }
  148. kubelet.daemonEndpoints = &api.NodeDaemonEndpoints{}
  149. mockCadvisor := &cadvisortest.Mock{}
  150. kubelet.cadvisor = mockCadvisor
  151. fakeMirrorClient := podtest.NewFakeMirrorClient()
  152. kubelet.podManager = kubepod.NewBasicPodManager(fakeMirrorClient)
  153. kubelet.statusManager = status.NewManager(fakeKubeClient, kubelet.podManager)
  154. kubelet.containerRefManager = kubecontainer.NewRefManager()
  155. diskSpaceManager, err := newDiskSpaceManager(mockCadvisor, DiskSpacePolicy{})
  156. if err != nil {
  157. t.Fatalf("can't initialize disk space manager: %v", err)
  158. }
  159. kubelet.diskSpaceManager = diskSpaceManager
  160. kubelet.containerRuntime = fakeRuntime
  161. kubelet.runtimeCache = containertest.NewFakeRuntimeCache(kubelet.containerRuntime)
  162. kubelet.reasonCache = NewReasonCache()
  163. kubelet.podCache = containertest.NewFakeCache(kubelet.containerRuntime)
  164. kubelet.podWorkers = &fakePodWorkers{
  165. syncPodFn: kubelet.syncPod,
  166. cache: kubelet.podCache,
  167. t: t,
  168. }
  169. kubelet.probeManager = probetest.FakeManager{}
  170. kubelet.livenessManager = proberesults.NewManager()
  171. kubelet.containerManager = cm.NewStubContainerManager()
  172. fakeNodeRef := &api.ObjectReference{
  173. Kind: "Node",
  174. Name: testKubeletHostname,
  175. UID: types.UID(testKubeletHostname),
  176. Namespace: "",
  177. }
  178. fakeImageGCPolicy := images.ImageGCPolicy{
  179. HighThresholdPercent: 90,
  180. LowThresholdPercent: 80,
  181. }
  182. kubelet.imageManager, err = images.NewImageGCManager(fakeRuntime, mockCadvisor, fakeRecorder, fakeNodeRef, fakeImageGCPolicy)
  183. fakeClock := clock.NewFakeClock(time.Now())
  184. kubelet.backOff = flowcontrol.NewBackOff(time.Second, time.Minute)
  185. kubelet.backOff.Clock = fakeClock
  186. kubelet.podKillingCh = make(chan *kubecontainer.PodPair, 20)
  187. kubelet.resyncInterval = 10 * time.Second
  188. kubelet.reservation = kubetypes.Reservation{
  189. Kubernetes: api.ResourceList{
  190. api.ResourceCPU: resource.MustParse(testReservationCPU),
  191. api.ResourceMemory: resource.MustParse(testReservationMemory),
  192. },
  193. }
  194. kubelet.workQueue = queue.NewBasicWorkQueue(fakeClock)
  195. // Relist period does not affect the tests.
  196. kubelet.pleg = pleg.NewGenericPLEG(fakeRuntime, 100, time.Hour, nil, clock.RealClock{})
  197. kubelet.clock = fakeClock
  198. kubelet.setNodeStatusFuncs = kubelet.defaultNodeStatusFuncs()
  199. // TODO: Factor out "StatsProvider" from Kubelet so we don't have a cyclic dependency
  200. volumeStatsAggPeriod := time.Second * 10
  201. kubelet.resourceAnalyzer = stats.NewResourceAnalyzer(kubelet, volumeStatsAggPeriod, kubelet.containerRuntime)
  202. nodeRef := &api.ObjectReference{
  203. Kind: "Node",
  204. Name: kubelet.nodeName,
  205. UID: types.UID(kubelet.nodeName),
  206. Namespace: "",
  207. }
  208. // setup eviction manager
  209. evictionManager, evictionAdmitHandler, err := eviction.NewManager(kubelet.resourceAnalyzer, eviction.Config{}, killPodNow(kubelet.podWorkers), kubelet.imageManager, fakeRecorder, nodeRef, kubelet.clock)
  210. if err != nil {
  211. t.Fatalf("failed to initialize eviction manager: %v", err)
  212. }
  213. kubelet.evictionManager = evictionManager
  214. kubelet.AddPodAdmitHandler(evictionAdmitHandler)
  215. plug := &volumetest.FakeVolumePlugin{PluginName: "fake", Host: nil}
  216. kubelet.volumePluginMgr, err =
  217. NewInitializedVolumePluginMgr(kubelet, []volume.VolumePlugin{plug})
  218. if err != nil {
  219. t.Fatalf("failed to initialize VolumePluginMgr: %v", err)
  220. }
  221. kubelet.mounter = &mount.FakeMounter{}
  222. kubelet.volumeManager, err = kubeletvolume.NewVolumeManager(
  223. controllerAttachDetachEnabled,
  224. kubelet.hostname,
  225. kubelet.podManager,
  226. fakeKubeClient,
  227. kubelet.volumePluginMgr,
  228. fakeRuntime,
  229. kubelet.mounter,
  230. kubelet.getPodsDir(),
  231. kubelet.recorder)
  232. if err != nil {
  233. t.Fatalf("failed to initialize volume manager: %v", err)
  234. }
  235. // enable active deadline handler
  236. activeDeadlineHandler, err := newActiveDeadlineHandler(kubelet.statusManager, kubelet.recorder, kubelet.clock)
  237. if err != nil {
  238. t.Fatalf("can't initialize active deadline handler: %v", err)
  239. }
  240. kubelet.AddPodSyncLoopHandler(activeDeadlineHandler)
  241. kubelet.AddPodSyncHandler(activeDeadlineHandler)
  242. return &TestKubelet{kubelet, fakeRuntime, mockCadvisor, fakeKubeClient, fakeMirrorClient, fakeClock, nil, plug}
  243. }
  244. func newTestPods(count int) []*api.Pod {
  245. pods := make([]*api.Pod, count)
  246. for i := 0; i < count; i++ {
  247. pods[i] = &api.Pod{
  248. Spec: api.PodSpec{
  249. SecurityContext: &api.PodSecurityContext{
  250. HostNetwork: true,
  251. },
  252. },
  253. ObjectMeta: api.ObjectMeta{
  254. UID: types.UID(10000 + i),
  255. Name: fmt.Sprintf("pod%d", i),
  256. },
  257. }
  258. }
  259. return pods
  260. }
  261. var emptyPodUIDs map[types.UID]kubetypes.SyncPodType
  262. func TestSyncLoopTimeUpdate(t *testing.T) {
  263. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  264. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  265. kubelet := testKubelet.kubelet
  266. loopTime1 := kubelet.LatestLoopEntryTime()
  267. if !loopTime1.IsZero() {
  268. t.Errorf("Unexpected sync loop time: %s, expected 0", loopTime1)
  269. }
  270. // Start sync ticker.
  271. syncCh := make(chan time.Time, 1)
  272. housekeepingCh := make(chan time.Time, 1)
  273. plegCh := make(chan *pleg.PodLifecycleEvent)
  274. syncCh <- time.Now()
  275. kubelet.syncLoopIteration(make(chan kubetypes.PodUpdate), kubelet, syncCh, housekeepingCh, plegCh)
  276. loopTime2 := kubelet.LatestLoopEntryTime()
  277. if loopTime2.IsZero() {
  278. t.Errorf("Unexpected sync loop time: 0, expected non-zero value.")
  279. }
  280. syncCh <- time.Now()
  281. kubelet.syncLoopIteration(make(chan kubetypes.PodUpdate), kubelet, syncCh, housekeepingCh, plegCh)
  282. loopTime3 := kubelet.LatestLoopEntryTime()
  283. if !loopTime3.After(loopTime1) {
  284. t.Errorf("Sync Loop Time was not updated correctly. Second update timestamp should be greater than first update timestamp")
  285. }
  286. }
  287. func TestSyncLoopAbort(t *testing.T) {
  288. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  289. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  290. kubelet := testKubelet.kubelet
  291. kubelet.runtimeState.setRuntimeSync(time.Now())
  292. // The syncLoop waits on time.After(resyncInterval), set it really big so that we don't race for
  293. // the channel close
  294. kubelet.resyncInterval = time.Second * 30
  295. ch := make(chan kubetypes.PodUpdate)
  296. close(ch)
  297. // sanity check (also prevent this test from hanging in the next step)
  298. ok := kubelet.syncLoopIteration(ch, kubelet, make(chan time.Time), make(chan time.Time), make(chan *pleg.PodLifecycleEvent, 1))
  299. if ok {
  300. t.Fatalf("expected syncLoopIteration to return !ok since update chan was closed")
  301. }
  302. // this should terminate immediately; if it hangs then the syncLoopIteration isn't aborting properly
  303. kubelet.syncLoop(ch, kubelet)
  304. }
  305. func TestSyncPodsStartPod(t *testing.T) {
  306. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  307. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  308. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  309. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  310. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  311. kubelet := testKubelet.kubelet
  312. fakeRuntime := testKubelet.fakeRuntime
  313. pods := []*api.Pod{
  314. podWithUidNameNsSpec("12345678", "foo", "new", api.PodSpec{
  315. Containers: []api.Container{
  316. {Name: "bar"},
  317. },
  318. }),
  319. }
  320. kubelet.podManager.SetPods(pods)
  321. kubelet.HandlePodSyncs(pods)
  322. fakeRuntime.AssertStartedPods([]string{string(pods[0].UID)})
  323. }
  324. func TestSyncPodsDeletesWhenSourcesAreReady(t *testing.T) {
  325. ready := false
  326. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  327. fakeRuntime := testKubelet.fakeRuntime
  328. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  329. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  330. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  331. kubelet := testKubelet.kubelet
  332. kubelet.sourcesReady = config.NewSourcesReady(func(_ sets.String) bool { return ready })
  333. fakeRuntime.PodList = []*containertest.FakePod{
  334. {Pod: &kubecontainer.Pod{
  335. ID: "12345678",
  336. Name: "foo",
  337. Namespace: "new",
  338. Containers: []*kubecontainer.Container{
  339. {Name: "bar"},
  340. },
  341. }},
  342. }
  343. kubelet.HandlePodCleanups()
  344. // Sources are not ready yet. Don't remove any pods.
  345. fakeRuntime.AssertKilledPods([]string{})
  346. ready = true
  347. kubelet.HandlePodCleanups()
  348. // Sources are ready. Remove unwanted pods.
  349. fakeRuntime.AssertKilledPods([]string{"12345678"})
  350. }
  351. func TestVolumeAttachAndMountControllerDisabled(t *testing.T) {
  352. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  353. kubelet := testKubelet.kubelet
  354. pod := podWithUidNameNsSpec("12345678", "foo", "test", api.PodSpec{
  355. Volumes: []api.Volume{
  356. {
  357. Name: "vol1",
  358. VolumeSource: api.VolumeSource{
  359. GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{
  360. PDName: "fake-device",
  361. },
  362. },
  363. },
  364. },
  365. })
  366. stopCh := runVolumeManager(kubelet)
  367. defer func() {
  368. close(stopCh)
  369. }()
  370. kubelet.podManager.SetPods([]*api.Pod{pod})
  371. err := kubelet.volumeManager.WaitForAttachAndMount(pod)
  372. if err != nil {
  373. t.Errorf("Expected success: %v", err)
  374. }
  375. podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
  376. volumehelper.GetUniquePodName(pod))
  377. expectedPodVolumes := []string{"vol1"}
  378. if len(expectedPodVolumes) != len(podVolumes) {
  379. t.Errorf("Unexpected volumes. Expected %#v got %#v. Manifest was: %#v", expectedPodVolumes, podVolumes, pod)
  380. }
  381. for _, name := range expectedPodVolumes {
  382. if _, ok := podVolumes[name]; !ok {
  383. t.Errorf("api.Pod volumes map is missing key: %s. %#v", name, podVolumes)
  384. }
  385. }
  386. if testKubelet.volumePlugin.GetNewAttacherCallCount() < 1 {
  387. t.Errorf("Expected plugin NewAttacher to be called at least once")
  388. }
  389. err = volumetest.VerifyWaitForAttachCallCount(
  390. 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin)
  391. if err != nil {
  392. t.Error(err)
  393. }
  394. err = volumetest.VerifyAttachCallCount(
  395. 1 /* expectedAttachCallCount */, testKubelet.volumePlugin)
  396. if err != nil {
  397. t.Error(err)
  398. }
  399. err = volumetest.VerifyMountDeviceCallCount(
  400. 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin)
  401. if err != nil {
  402. t.Error(err)
  403. }
  404. err = volumetest.VerifySetUpCallCount(
  405. 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin)
  406. if err != nil {
  407. t.Error(err)
  408. }
  409. }
  410. func TestVolumeUnmountAndDetachControllerDisabled(t *testing.T) {
  411. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  412. kubelet := testKubelet.kubelet
  413. pod := podWithUidNameNsSpec("12345678", "foo", "test", api.PodSpec{
  414. Volumes: []api.Volume{
  415. {
  416. Name: "vol1",
  417. VolumeSource: api.VolumeSource{
  418. GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{
  419. PDName: "fake-device",
  420. },
  421. },
  422. },
  423. },
  424. })
  425. stopCh := runVolumeManager(kubelet)
  426. defer func() {
  427. close(stopCh)
  428. }()
  429. // Add pod
  430. kubelet.podManager.SetPods([]*api.Pod{pod})
  431. // Verify volumes attached
  432. err := kubelet.volumeManager.WaitForAttachAndMount(pod)
  433. if err != nil {
  434. t.Errorf("Expected success: %v", err)
  435. }
  436. podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
  437. volumehelper.GetUniquePodName(pod))
  438. expectedPodVolumes := []string{"vol1"}
  439. if len(expectedPodVolumes) != len(podVolumes) {
  440. t.Errorf("Unexpected volumes. Expected %#v got %#v. Manifest was: %#v", expectedPodVolumes, podVolumes, pod)
  441. }
  442. for _, name := range expectedPodVolumes {
  443. if _, ok := podVolumes[name]; !ok {
  444. t.Errorf("api.Pod volumes map is missing key: %s. %#v", name, podVolumes)
  445. }
  446. }
  447. if testKubelet.volumePlugin.GetNewAttacherCallCount() < 1 {
  448. t.Errorf("Expected plugin NewAttacher to be called at least once")
  449. }
  450. err = volumetest.VerifyWaitForAttachCallCount(
  451. 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin)
  452. if err != nil {
  453. t.Error(err)
  454. }
  455. err = volumetest.VerifyAttachCallCount(
  456. 1 /* expectedAttachCallCount */, testKubelet.volumePlugin)
  457. if err != nil {
  458. t.Error(err)
  459. }
  460. err = volumetest.VerifyMountDeviceCallCount(
  461. 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin)
  462. if err != nil {
  463. t.Error(err)
  464. }
  465. err = volumetest.VerifySetUpCallCount(
  466. 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin)
  467. if err != nil {
  468. t.Error(err)
  469. }
  470. // Remove pod
  471. kubelet.podManager.SetPods([]*api.Pod{})
  472. err = waitForVolumeUnmount(kubelet.volumeManager, pod)
  473. if err != nil {
  474. t.Error(err)
  475. }
  476. // Verify volumes unmounted
  477. podVolumes = kubelet.volumeManager.GetMountedVolumesForPod(
  478. volumehelper.GetUniquePodName(pod))
  479. if len(podVolumes) != 0 {
  480. t.Errorf("Expected volumes to be unmounted and detached. But some volumes are still mounted: %#v", podVolumes)
  481. }
  482. err = volumetest.VerifyTearDownCallCount(
  483. 1 /* expectedTearDownCallCount */, testKubelet.volumePlugin)
  484. if err != nil {
  485. t.Error(err)
  486. }
  487. // Verify volumes detached and no longer reported as in use
  488. err = waitForVolumeDetach(api.UniqueVolumeName("fake/vol1"), kubelet.volumeManager)
  489. if err != nil {
  490. t.Error(err)
  491. }
  492. if testKubelet.volumePlugin.GetNewDetacherCallCount() < 1 {
  493. t.Errorf("Expected plugin NewDetacher to be called at least once")
  494. }
  495. err = volumetest.VerifyDetachCallCount(
  496. 1 /* expectedDetachCallCount */, testKubelet.volumePlugin)
  497. if err != nil {
  498. t.Error(err)
  499. }
  500. }
  501. func TestVolumeAttachAndMountControllerEnabled(t *testing.T) {
  502. testKubelet := newTestKubelet(t, true /* controllerAttachDetachEnabled */)
  503. kubelet := testKubelet.kubelet
  504. kubeClient := testKubelet.fakeKubeClient
  505. kubeClient.AddReactor("get", "nodes",
  506. func(action core.Action) (bool, runtime.Object, error) {
  507. return true, &api.Node{
  508. ObjectMeta: api.ObjectMeta{Name: testKubeletHostname},
  509. Status: api.NodeStatus{
  510. VolumesAttached: []api.AttachedVolume{
  511. {
  512. Name: "fake/vol1",
  513. DevicePath: "fake/path",
  514. },
  515. }},
  516. Spec: api.NodeSpec{ExternalID: testKubeletHostname},
  517. }, nil
  518. })
  519. kubeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
  520. return true, nil, fmt.Errorf("no reaction implemented for %s", action)
  521. })
  522. pod := podWithUidNameNsSpec("12345678", "foo", "test", api.PodSpec{
  523. Volumes: []api.Volume{
  524. {
  525. Name: "vol1",
  526. VolumeSource: api.VolumeSource{
  527. GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{
  528. PDName: "fake-device",
  529. },
  530. },
  531. },
  532. },
  533. })
  534. stopCh := runVolumeManager(kubelet)
  535. defer func() {
  536. close(stopCh)
  537. }()
  538. kubelet.podManager.SetPods([]*api.Pod{pod})
  539. // Fake node status update
  540. go simulateVolumeInUseUpdate(
  541. api.UniqueVolumeName("fake/vol1"),
  542. stopCh,
  543. kubelet.volumeManager)
  544. err := kubelet.volumeManager.WaitForAttachAndMount(pod)
  545. if err != nil {
  546. t.Errorf("Expected success: %v", err)
  547. }
  548. podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
  549. volumehelper.GetUniquePodName(pod))
  550. expectedPodVolumes := []string{"vol1"}
  551. if len(expectedPodVolumes) != len(podVolumes) {
  552. t.Errorf("Unexpected volumes. Expected %#v got %#v. Manifest was: %#v", expectedPodVolumes, podVolumes, pod)
  553. }
  554. for _, name := range expectedPodVolumes {
  555. if _, ok := podVolumes[name]; !ok {
  556. t.Errorf("api.Pod volumes map is missing key: %s. %#v", name, podVolumes)
  557. }
  558. }
  559. if testKubelet.volumePlugin.GetNewAttacherCallCount() < 1 {
  560. t.Errorf("Expected plugin NewAttacher to be called at least once")
  561. }
  562. err = volumetest.VerifyWaitForAttachCallCount(
  563. 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin)
  564. if err != nil {
  565. t.Error(err)
  566. }
  567. err = volumetest.VerifyZeroAttachCalls(testKubelet.volumePlugin)
  568. if err != nil {
  569. t.Error(err)
  570. }
  571. err = volumetest.VerifyMountDeviceCallCount(
  572. 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin)
  573. if err != nil {
  574. t.Error(err)
  575. }
  576. err = volumetest.VerifySetUpCallCount(
  577. 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin)
  578. if err != nil {
  579. t.Error(err)
  580. }
  581. }
  582. func TestVolumeUnmountAndDetachControllerEnabled(t *testing.T) {
  583. testKubelet := newTestKubelet(t, true /* controllerAttachDetachEnabled */)
  584. kubelet := testKubelet.kubelet
  585. kubeClient := testKubelet.fakeKubeClient
  586. kubeClient.AddReactor("get", "nodes",
  587. func(action core.Action) (bool, runtime.Object, error) {
  588. return true, &api.Node{
  589. ObjectMeta: api.ObjectMeta{Name: testKubeletHostname},
  590. Status: api.NodeStatus{
  591. VolumesAttached: []api.AttachedVolume{
  592. {
  593. Name: "fake/vol1",
  594. DevicePath: "fake/path",
  595. },
  596. }},
  597. Spec: api.NodeSpec{ExternalID: testKubeletHostname},
  598. }, nil
  599. })
  600. kubeClient.AddReactor("*", "*", func(action core.Action) (bool, runtime.Object, error) {
  601. return true, nil, fmt.Errorf("no reaction implemented for %s", action)
  602. })
  603. pod := podWithUidNameNsSpec("12345678", "foo", "test", api.PodSpec{
  604. Volumes: []api.Volume{
  605. {
  606. Name: "vol1",
  607. VolumeSource: api.VolumeSource{
  608. GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{
  609. PDName: "fake-device",
  610. },
  611. },
  612. },
  613. },
  614. })
  615. stopCh := runVolumeManager(kubelet)
  616. defer func() {
  617. close(stopCh)
  618. }()
  619. // Add pod
  620. kubelet.podManager.SetPods([]*api.Pod{pod})
  621. // Fake node status update
  622. go simulateVolumeInUseUpdate(
  623. api.UniqueVolumeName("fake/vol1"),
  624. stopCh,
  625. kubelet.volumeManager)
  626. // Verify volumes attached
  627. err := kubelet.volumeManager.WaitForAttachAndMount(pod)
  628. if err != nil {
  629. t.Errorf("Expected success: %v", err)
  630. }
  631. podVolumes := kubelet.volumeManager.GetMountedVolumesForPod(
  632. volumehelper.GetUniquePodName(pod))
  633. expectedPodVolumes := []string{"vol1"}
  634. if len(expectedPodVolumes) != len(podVolumes) {
  635. t.Errorf("Unexpected volumes. Expected %#v got %#v. Manifest was: %#v", expectedPodVolumes, podVolumes, pod)
  636. }
  637. for _, name := range expectedPodVolumes {
  638. if _, ok := podVolumes[name]; !ok {
  639. t.Errorf("api.Pod volumes map is missing key: %s. %#v", name, podVolumes)
  640. }
  641. }
  642. if testKubelet.volumePlugin.GetNewAttacherCallCount() < 1 {
  643. t.Errorf("Expected plugin NewAttacher to be called at least once")
  644. }
  645. err = volumetest.VerifyWaitForAttachCallCount(
  646. 1 /* expectedWaitForAttachCallCount */, testKubelet.volumePlugin)
  647. if err != nil {
  648. t.Error(err)
  649. }
  650. err = volumetest.VerifyZeroAttachCalls(testKubelet.volumePlugin)
  651. if err != nil {
  652. t.Error(err)
  653. }
  654. err = volumetest.VerifyMountDeviceCallCount(
  655. 1 /* expectedMountDeviceCallCount */, testKubelet.volumePlugin)
  656. if err != nil {
  657. t.Error(err)
  658. }
  659. err = volumetest.VerifySetUpCallCount(
  660. 1 /* expectedSetUpCallCount */, testKubelet.volumePlugin)
  661. if err != nil {
  662. t.Error(err)
  663. }
  664. // Remove pod
  665. kubelet.podManager.SetPods([]*api.Pod{})
  666. err = waitForVolumeUnmount(kubelet.volumeManager, pod)
  667. if err != nil {
  668. t.Error(err)
  669. }
  670. // Verify volumes unmounted
  671. podVolumes = kubelet.volumeManager.GetMountedVolumesForPod(
  672. volumehelper.GetUniquePodName(pod))
  673. if len(podVolumes) != 0 {
  674. t.Errorf("Expected volumes to be unmounted and detached. But some volumes are still mounted: %#v", podVolumes)
  675. }
  676. err = volumetest.VerifyTearDownCallCount(
  677. 1 /* expectedTearDownCallCount */, testKubelet.volumePlugin)
  678. if err != nil {
  679. t.Error(err)
  680. }
  681. // Verify volumes detached and no longer reported as in use
  682. err = waitForVolumeDetach(api.UniqueVolumeName("fake/vol1"), kubelet.volumeManager)
  683. if err != nil {
  684. t.Error(err)
  685. }
  686. if testKubelet.volumePlugin.GetNewDetacherCallCount() < 1 {
  687. t.Errorf("Expected plugin NewDetacher to be called at least once")
  688. }
  689. err = volumetest.VerifyZeroDetachCallCount(testKubelet.volumePlugin)
  690. if err != nil {
  691. t.Error(err)
  692. }
  693. }
  694. type stubVolume struct {
  695. path string
  696. volume.MetricsNil
  697. }
  698. func (f *stubVolume) GetPath() string {
  699. return f.path
  700. }
  701. func (f *stubVolume) GetAttributes() volume.Attributes {
  702. return volume.Attributes{}
  703. }
  704. func (f *stubVolume) SetUp(fsGroup *int64) error {
  705. return nil
  706. }
  707. func (f *stubVolume) SetUpAt(dir string, fsGroup *int64) error {
  708. return nil
  709. }
  710. func TestMakeVolumeMounts(t *testing.T) {
  711. container := api.Container{
  712. VolumeMounts: []api.VolumeMount{
  713. {
  714. MountPath: "/etc/hosts",
  715. Name: "disk",
  716. ReadOnly: false,
  717. },
  718. {
  719. MountPath: "/mnt/path3",
  720. Name: "disk",
  721. ReadOnly: true,
  722. },
  723. {
  724. MountPath: "/mnt/path4",
  725. Name: "disk4",
  726. ReadOnly: false,
  727. },
  728. {
  729. MountPath: "/mnt/path5",
  730. Name: "disk5",
  731. ReadOnly: false,
  732. },
  733. },
  734. }
  735. podVolumes := kubecontainer.VolumeMap{
  736. "disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
  737. "disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/host"}},
  738. "disk5": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/var/lib/kubelet/podID/volumes/empty/disk5"}},
  739. }
  740. pod := api.Pod{
  741. Spec: api.PodSpec{
  742. SecurityContext: &api.PodSecurityContext{
  743. HostNetwork: true,
  744. },
  745. },
  746. }
  747. mounts, _ := makeMounts(&pod, "/pod", &container, "fakepodname", "", "", podVolumes)
  748. expectedMounts := []kubecontainer.Mount{
  749. {
  750. Name: "disk",
  751. ContainerPath: "/etc/hosts",
  752. HostPath: "/mnt/disk",
  753. ReadOnly: false,
  754. SELinuxRelabel: false,
  755. },
  756. {
  757. Name: "disk",
  758. ContainerPath: "/mnt/path3",
  759. HostPath: "/mnt/disk",
  760. ReadOnly: true,
  761. SELinuxRelabel: false,
  762. },
  763. {
  764. Name: "disk4",
  765. ContainerPath: "/mnt/path4",
  766. HostPath: "/mnt/host",
  767. ReadOnly: false,
  768. SELinuxRelabel: false,
  769. },
  770. {
  771. Name: "disk5",
  772. ContainerPath: "/mnt/path5",
  773. HostPath: "/var/lib/kubelet/podID/volumes/empty/disk5",
  774. ReadOnly: false,
  775. SELinuxRelabel: false,
  776. },
  777. }
  778. if !reflect.DeepEqual(mounts, expectedMounts) {
  779. t.Errorf("Unexpected mounts: Expected %#v got %#v. Container was: %#v", expectedMounts, mounts, container)
  780. }
  781. }
  782. type fakeContainerCommandRunner struct {
  783. // what was passed in
  784. Cmd []string
  785. ID kubecontainer.ContainerID
  786. PodID types.UID
  787. E error
  788. Stdin io.Reader
  789. Stdout io.WriteCloser
  790. Stderr io.WriteCloser
  791. TTY bool
  792. Port uint16
  793. Stream io.ReadWriteCloser
  794. // what to return
  795. StdoutData string
  796. StderrData string
  797. }
  798. func (f *fakeContainerCommandRunner) ExecInContainer(id kubecontainer.ContainerID, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan term.Size) error {
  799. // record params
  800. f.Cmd = cmd
  801. f.ID = id
  802. f.Stdin = in
  803. f.Stdout = out
  804. f.Stderr = err
  805. f.TTY = tty
  806. // Copy stdout/stderr data
  807. fmt.Fprint(out, f.StdoutData)
  808. fmt.Fprint(out, f.StderrData)
  809. return f.E
  810. }
  811. func (f *fakeContainerCommandRunner) PortForward(pod *kubecontainer.Pod, port uint16, stream io.ReadWriteCloser) error {
  812. f.PodID = pod.ID
  813. f.Port = port
  814. f.Stream = stream
  815. return nil
  816. }
  817. func TestRunInContainerNoSuchPod(t *testing.T) {
  818. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  819. kubelet := testKubelet.kubelet
  820. fakeRuntime := testKubelet.fakeRuntime
  821. fakeRuntime.PodList = []*containertest.FakePod{}
  822. podName := "podFoo"
  823. podNamespace := "nsFoo"
  824. containerName := "containerFoo"
  825. output, err := kubelet.RunInContainer(
  826. kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{Name: podName, Namespace: podNamespace}}),
  827. "",
  828. containerName,
  829. []string{"ls"})
  830. if output != nil {
  831. t.Errorf("unexpected non-nil command: %v", output)
  832. }
  833. if err == nil {
  834. t.Error("unexpected non-error")
  835. }
  836. }
  837. func TestRunInContainer(t *testing.T) {
  838. for _, testError := range []error{nil, errors.New("foo")} {
  839. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  840. kubelet := testKubelet.kubelet
  841. fakeRuntime := testKubelet.fakeRuntime
  842. fakeCommandRunner := fakeContainerCommandRunner{
  843. E: testError,
  844. StdoutData: "foo",
  845. StderrData: "bar",
  846. }
  847. kubelet.runner = &fakeCommandRunner
  848. containerID := kubecontainer.ContainerID{Type: "test", ID: "abc1234"}
  849. fakeRuntime.PodList = []*containertest.FakePod{
  850. {Pod: &kubecontainer.Pod{
  851. ID: "12345678",
  852. Name: "podFoo",
  853. Namespace: "nsFoo",
  854. Containers: []*kubecontainer.Container{
  855. {Name: "containerFoo",
  856. ID: containerID,
  857. },
  858. },
  859. }},
  860. }
  861. cmd := []string{"ls"}
  862. actualOutput, err := kubelet.RunInContainer("podFoo_nsFoo", "", "containerFoo", cmd)
  863. if fakeCommandRunner.ID != containerID {
  864. t.Errorf("(testError=%v) unexpected Name: %s", testError, fakeCommandRunner.ID)
  865. }
  866. if !reflect.DeepEqual(fakeCommandRunner.Cmd, cmd) {
  867. t.Errorf("(testError=%v) unexpected command: %s", testError, fakeCommandRunner.Cmd)
  868. }
  869. // this isn't 100% foolproof as a bug in a real ContainerCommandRunner where it fails to copy to stdout/stderr wouldn't be caught by this test
  870. if "foobar" != string(actualOutput) {
  871. t.Errorf("(testError=%v) unexpected output %q", testError, actualOutput)
  872. }
  873. if e, a := fmt.Sprintf("%v", testError), fmt.Sprintf("%v", err); e != a {
  874. t.Errorf("(testError=%v) error: expected %s, got %s", testError, e, a)
  875. }
  876. }
  877. }
  878. func TestDNSConfigurationParams(t *testing.T) {
  879. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  880. kubelet := testKubelet.kubelet
  881. clusterNS := "203.0.113.1"
  882. kubelet.clusterDomain = "kubernetes.io"
  883. kubelet.clusterDNS = net.ParseIP(clusterNS)
  884. pods := newTestPods(2)
  885. pods[0].Spec.DNSPolicy = api.DNSClusterFirst
  886. pods[1].Spec.DNSPolicy = api.DNSDefault
  887. options := make([]*kubecontainer.RunContainerOptions, 2)
  888. for i, pod := range pods {
  889. var err error
  890. options[i], err = kubelet.GenerateRunContainerOptions(pod, &api.Container{}, "")
  891. if err != nil {
  892. t.Fatalf("failed to generate container options: %v", err)
  893. }
  894. }
  895. if len(options[0].DNS) != 1 || options[0].DNS[0] != clusterNS {
  896. t.Errorf("expected nameserver %s, got %+v", clusterNS, options[0].DNS)
  897. }
  898. if len(options[0].DNSSearch) == 0 || options[0].DNSSearch[0] != ".svc."+kubelet.clusterDomain {
  899. t.Errorf("expected search %s, got %+v", ".svc."+kubelet.clusterDomain, options[0].DNSSearch)
  900. }
  901. if len(options[1].DNS) != 1 || options[1].DNS[0] != "127.0.0.1" {
  902. t.Errorf("expected nameserver 127.0.0.1, got %+v", options[1].DNS)
  903. }
  904. if len(options[1].DNSSearch) != 1 || options[1].DNSSearch[0] != "." {
  905. t.Errorf("expected search \".\", got %+v", options[1].DNSSearch)
  906. }
  907. kubelet.resolverConfig = "/etc/resolv.conf"
  908. for i, pod := range pods {
  909. var err error
  910. options[i], err = kubelet.GenerateRunContainerOptions(pod, &api.Container{}, "")
  911. if err != nil {
  912. t.Fatalf("failed to generate container options: %v", err)
  913. }
  914. }
  915. t.Logf("nameservers %+v", options[1].DNS)
  916. if len(options[0].DNS) != 1 {
  917. t.Errorf("expected cluster nameserver only, got %+v", options[0].DNS)
  918. } else if options[0].DNS[0] != clusterNS {
  919. t.Errorf("expected nameserver %s, got %v", clusterNS, options[0].DNS[0])
  920. }
  921. if len(options[0].DNSSearch) != len(options[1].DNSSearch)+3 {
  922. t.Errorf("expected prepend of cluster domain, got %+v", options[0].DNSSearch)
  923. } else if options[0].DNSSearch[0] != ".svc."+kubelet.clusterDomain {
  924. t.Errorf("expected domain %s, got %s", ".svc."+kubelet.clusterDomain, options[0].DNSSearch)
  925. }
  926. }
  927. type testServiceLister struct {
  928. services []api.Service
  929. }
  930. func (ls testServiceLister) List() (api.ServiceList, error) {
  931. return api.ServiceList{
  932. Items: ls.services,
  933. }, nil
  934. }
  935. type testNodeLister struct {
  936. nodes []api.Node
  937. }
  938. type testNodeInfo struct {
  939. nodes []api.Node
  940. }
  941. func (ls testNodeInfo) GetNodeInfo(id string) (*api.Node, error) {
  942. for _, node := range ls.nodes {
  943. if node.Name == id {
  944. return &node, nil
  945. }
  946. }
  947. return nil, fmt.Errorf("Node with name: %s does not exist", id)
  948. }
  949. func (ls testNodeLister) List() (api.NodeList, error) {
  950. return api.NodeList{
  951. Items: ls.nodes,
  952. }, nil
  953. }
  954. type envs []kubecontainer.EnvVar
  955. func (e envs) Len() int {
  956. return len(e)
  957. }
  958. func (e envs) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
  959. func (e envs) Less(i, j int) bool { return e[i].Name < e[j].Name }
  960. func buildService(name, namespace, clusterIP, protocol string, port int) api.Service {
  961. return api.Service{
  962. ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace},
  963. Spec: api.ServiceSpec{
  964. Ports: []api.ServicePort{{
  965. Protocol: api.Protocol(protocol),
  966. Port: int32(port),
  967. }},
  968. ClusterIP: clusterIP,
  969. },
  970. }
  971. }
  972. func TestMakeEnvironmentVariables(t *testing.T) {
  973. services := []api.Service{
  974. buildService("kubernetes", api.NamespaceDefault, "1.2.3.1", "TCP", 8081),
  975. buildService("test", "test1", "1.2.3.3", "TCP", 8083),
  976. buildService("kubernetes", "test2", "1.2.3.4", "TCP", 8084),
  977. buildService("test", "test2", "1.2.3.5", "TCP", 8085),
  978. buildService("test", "test2", "None", "TCP", 8085),
  979. buildService("test", "test2", "", "TCP", 8085),
  980. buildService("kubernetes", "kubernetes", "1.2.3.6", "TCP", 8086),
  981. buildService("not-special", "kubernetes", "1.2.3.8", "TCP", 8088),
  982. buildService("not-special", "kubernetes", "None", "TCP", 8088),
  983. buildService("not-special", "kubernetes", "", "TCP", 8088),
  984. }
  985. testCases := []struct {
  986. name string // the name of the test case
  987. ns string // the namespace to generate environment for
  988. container *api.Container // the container to use
  989. masterServiceNs string // the namespace to read master service info from
  990. nilLister bool // whether the lister should be nil
  991. expectedEnvs []kubecontainer.EnvVar // a set of expected environment vars
  992. }{
  993. {
  994. name: "api server = Y, kubelet = Y",
  995. ns: "test1",
  996. container: &api.Container{
  997. Env: []api.EnvVar{
  998. {Name: "FOO", Value: "BAR"},
  999. {Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
  1000. {Name: "TEST_SERVICE_PORT", Value: "8083"},
  1001. {Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
  1002. {Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
  1003. {Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
  1004. {Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
  1005. {Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
  1006. },
  1007. },
  1008. masterServiceNs: api.NamespaceDefault,
  1009. nilLister: false,
  1010. expectedEnvs: []kubecontainer.EnvVar{
  1011. {Name: "FOO", Value: "BAR"},
  1012. {Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
  1013. {Name: "TEST_SERVICE_PORT", Value: "8083"},
  1014. {Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
  1015. {Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
  1016. {Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
  1017. {Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
  1018. {Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
  1019. {Name: "KUBERNETES_SERVICE_PORT", Value: "8081"},
  1020. {Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.1"},
  1021. {Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.1:8081"},
  1022. {Name: "KUBERNETES_PORT_8081_TCP", Value: "tcp://1.2.3.1:8081"},
  1023. {Name: "KUBERNETES_PORT_8081_TCP_PROTO", Value: "tcp"},
  1024. {Name: "KUBERNETES_PORT_8081_TCP_PORT", Value: "8081"},
  1025. {Name: "KUBERNETES_PORT_8081_TCP_ADDR", Value: "1.2.3.1"},
  1026. },
  1027. },
  1028. {
  1029. name: "api server = Y, kubelet = N",
  1030. ns: "test1",
  1031. container: &api.Container{
  1032. Env: []api.EnvVar{
  1033. {Name: "FOO", Value: "BAR"},
  1034. {Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
  1035. {Name: "TEST_SERVICE_PORT", Value: "8083"},
  1036. {Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
  1037. {Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
  1038. {Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
  1039. {Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
  1040. {Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
  1041. },
  1042. },
  1043. masterServiceNs: api.NamespaceDefault,
  1044. nilLister: true,
  1045. expectedEnvs: []kubecontainer.EnvVar{
  1046. {Name: "FOO", Value: "BAR"},
  1047. {Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
  1048. {Name: "TEST_SERVICE_PORT", Value: "8083"},
  1049. {Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
  1050. {Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
  1051. {Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
  1052. {Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
  1053. {Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
  1054. },
  1055. },
  1056. {
  1057. name: "api server = N; kubelet = Y",
  1058. ns: "test1",
  1059. container: &api.Container{
  1060. Env: []api.EnvVar{
  1061. {Name: "FOO", Value: "BAZ"},
  1062. },
  1063. },
  1064. masterServiceNs: api.NamespaceDefault,
  1065. nilLister: false,
  1066. expectedEnvs: []kubecontainer.EnvVar{
  1067. {Name: "FOO", Value: "BAZ"},
  1068. {Name: "TEST_SERVICE_HOST", Value: "1.2.3.3"},
  1069. {Name: "TEST_SERVICE_PORT", Value: "8083"},
  1070. {Name: "TEST_PORT", Value: "tcp://1.2.3.3:8083"},
  1071. {Name: "TEST_PORT_8083_TCP", Value: "tcp://1.2.3.3:8083"},
  1072. {Name: "TEST_PORT_8083_TCP_PROTO", Value: "tcp"},
  1073. {Name: "TEST_PORT_8083_TCP_PORT", Value: "8083"},
  1074. {Name: "TEST_PORT_8083_TCP_ADDR", Value: "1.2.3.3"},
  1075. {Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.1"},
  1076. {Name: "KUBERNETES_SERVICE_PORT", Value: "8081"},
  1077. {Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.1:8081"},
  1078. {Name: "KUBERNETES_PORT_8081_TCP", Value: "tcp://1.2.3.1:8081"},
  1079. {Name: "KUBERNETES_PORT_8081_TCP_PROTO", Value: "tcp"},
  1080. {Name: "KUBERNETES_PORT_8081_TCP_PORT", Value: "8081"},
  1081. {Name: "KUBERNETES_PORT_8081_TCP_ADDR", Value: "1.2.3.1"},
  1082. },
  1083. },
  1084. {
  1085. name: "master service in pod ns",
  1086. ns: "test2",
  1087. container: &api.Container{
  1088. Env: []api.EnvVar{
  1089. {Name: "FOO", Value: "ZAP"},
  1090. },
  1091. },
  1092. masterServiceNs: "kubernetes",
  1093. nilLister: false,
  1094. expectedEnvs: []kubecontainer.EnvVar{
  1095. {Name: "FOO", Value: "ZAP"},
  1096. {Name: "TEST_SERVICE_HOST", Value: "1.2.3.5"},
  1097. {Name: "TEST_SERVICE_PORT", Value: "8085"},
  1098. {Name: "TEST_PORT", Value: "tcp://1.2.3.5:8085"},
  1099. {Name: "TEST_PORT_8085_TCP", Value: "tcp://1.2.3.5:8085"},
  1100. {Name: "TEST_PORT_8085_TCP_PROTO", Value: "tcp"},
  1101. {Name: "TEST_PORT_8085_TCP_PORT", Value: "8085"},
  1102. {Name: "TEST_PORT_8085_TCP_ADDR", Value: "1.2.3.5"},
  1103. {Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.4"},
  1104. {Name: "KUBERNETES_SERVICE_PORT", Value: "8084"},
  1105. {Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.4:8084"},
  1106. {Name: "KUBERNETES_PORT_8084_TCP", Value: "tcp://1.2.3.4:8084"},
  1107. {Name: "KUBERNETES_PORT_8084_TCP_PROTO", Value: "tcp"},
  1108. {Name: "KUBERNETES_PORT_8084_TCP_PORT", Value: "8084"},
  1109. {Name: "KUBERNETES_PORT_8084_TCP_ADDR", Value: "1.2.3.4"},
  1110. },
  1111. },
  1112. {
  1113. name: "pod in master service ns",
  1114. ns: "kubernetes",
  1115. container: &api.Container{},
  1116. masterServiceNs: "kubernetes",
  1117. nilLister: false,
  1118. expectedEnvs: []kubecontainer.EnvVar{
  1119. {Name: "NOT_SPECIAL_SERVICE_HOST", Value: "1.2.3.8"},
  1120. {Name: "NOT_SPECIAL_SERVICE_PORT", Value: "8088"},
  1121. {Name: "NOT_SPECIAL_PORT", Value: "tcp://1.2.3.8:8088"},
  1122. {Name: "NOT_SPECIAL_PORT_8088_TCP", Value: "tcp://1.2.3.8:8088"},
  1123. {Name: "NOT_SPECIAL_PORT_8088_TCP_PROTO", Value: "tcp"},
  1124. {Name: "NOT_SPECIAL_PORT_8088_TCP_PORT", Value: "8088"},
  1125. {Name: "NOT_SPECIAL_PORT_8088_TCP_ADDR", Value: "1.2.3.8"},
  1126. {Name: "KUBERNETES_SERVICE_HOST", Value: "1.2.3.6"},
  1127. {Name: "KUBERNETES_SERVICE_PORT", Value: "8086"},
  1128. {Name: "KUBERNETES_PORT", Value: "tcp://1.2.3.6:8086"},
  1129. {Name: "KUBERNETES_PORT_8086_TCP", Value: "tcp://1.2.3.6:8086"},
  1130. {Name: "KUBERNETES_PORT_8086_TCP_PROTO", Value: "tcp"},
  1131. {Name: "KUBERNETES_PORT_8086_TCP_PORT", Value: "8086"},
  1132. {Name: "KUBERNETES_PORT_8086_TCP_ADDR", Value: "1.2.3.6"},
  1133. },
  1134. },
  1135. {
  1136. name: "downward api pod",
  1137. ns: "downward-api",
  1138. container: &api.Container{
  1139. Env: []api.EnvVar{
  1140. {
  1141. Name: "POD_NAME",
  1142. ValueFrom: &api.EnvVarSource{
  1143. FieldRef: &api.ObjectFieldSelector{
  1144. APIVersion: testapi.Default.GroupVersion().String(),
  1145. FieldPath: "metadata.name",
  1146. },
  1147. },
  1148. },
  1149. {
  1150. Name: "POD_NAMESPACE",
  1151. ValueFrom: &api.EnvVarSource{
  1152. FieldRef: &api.ObjectFieldSelector{
  1153. APIVersion: testapi.Default.GroupVersion().String(),
  1154. FieldPath: "metadata.namespace",
  1155. },
  1156. },
  1157. },
  1158. {
  1159. Name: "POD_NODE_NAME",
  1160. ValueFrom: &api.EnvVarSource{
  1161. FieldRef: &api.ObjectFieldSelector{
  1162. APIVersion: testapi.Default.GroupVersion().String(),
  1163. FieldPath: "spec.nodeName",
  1164. },
  1165. },
  1166. },
  1167. {
  1168. Name: "POD_SERVICE_ACCOUNT_NAME",
  1169. ValueFrom: &api.EnvVarSource{
  1170. FieldRef: &api.ObjectFieldSelector{
  1171. APIVersion: testapi.Default.GroupVersion().String(),
  1172. FieldPath: "spec.serviceAccountName",
  1173. },
  1174. },
  1175. },
  1176. {
  1177. Name: "POD_IP",
  1178. ValueFrom: &api.EnvVarSource{
  1179. FieldRef: &api.ObjectFieldSelector{
  1180. APIVersion: testapi.Default.GroupVersion().String(),
  1181. FieldPath: "status.podIP",
  1182. },
  1183. },
  1184. },
  1185. },
  1186. },
  1187. masterServiceNs: "nothing",
  1188. nilLister: true,
  1189. expectedEnvs: []kubecontainer.EnvVar{
  1190. {Name: "POD_NAME", Value: "dapi-test-pod-name"},
  1191. {Name: "POD_NAMESPACE", Value: "downward-api"},
  1192. {Name: "POD_NODE_NAME", Value: "node-name"},
  1193. {Name: "POD_SERVICE_ACCOUNT_NAME", Value: "special"},
  1194. {Name: "POD_IP", Value: "1.2.3.4"},
  1195. },
  1196. },
  1197. {
  1198. name: "env expansion",
  1199. ns: "test1",
  1200. container: &api.Container{
  1201. Env: []api.EnvVar{
  1202. {
  1203. Name: "TEST_LITERAL",
  1204. Value: "test-test-test",
  1205. },
  1206. {
  1207. Name: "POD_NAME",
  1208. ValueFrom: &api.EnvVarSource{
  1209. FieldRef: &api.ObjectFieldSelector{
  1210. APIVersion: testapi.Default.GroupVersion().String(),
  1211. FieldPath: "metadata.name",
  1212. },
  1213. },
  1214. },
  1215. {
  1216. Name: "OUT_OF_ORDER_TEST",
  1217. Value: "$(OUT_OF_ORDER_TARGET)",
  1218. },
  1219. {
  1220. Name: "OUT_OF_ORDER_TARGET",
  1221. Value: "FOO",
  1222. },
  1223. {
  1224. Name: "EMPTY_VAR",
  1225. },
  1226. {
  1227. Name: "EMPTY_TEST",
  1228. Value: "foo-$(EMPTY_VAR)",
  1229. },
  1230. {
  1231. Name: "POD_NAME_TEST2",
  1232. Value: "test2-$(POD_NAME)",
  1233. },
  1234. {
  1235. Name: "POD_NAME_TEST3",
  1236. Value: "$(POD_NAME_TEST2)-3",
  1237. },
  1238. {
  1239. Name: "LITERAL_TEST",
  1240. Value: "literal-$(TEST_LITERAL)",
  1241. },
  1242. {
  1243. Name: "SERVICE_VAR_TEST",
  1244. Value: "$(TEST_SERVICE_HOST):$(TEST_SERVICE_PORT)",
  1245. },
  1246. {
  1247. Name: "TEST_UNDEFINED",
  1248. Value: "$(UNDEFINED_VAR)",
  1249. },
  1250. },
  1251. },
  1252. masterServiceNs: "nothing",
  1253. nilLister: false,
  1254. expectedEnvs: []kubecontainer.EnvVar{
  1255. {
  1256. Name: "TEST_LITERAL",
  1257. Value: "test-test-test",
  1258. },
  1259. {
  1260. Name: "POD_NAME",
  1261. Value: "dapi-test-pod-name",
  1262. },
  1263. {
  1264. Name: "POD_NAME_TEST2",
  1265. Value: "test2-dapi-test-pod-name",
  1266. },
  1267. {
  1268. Name: "POD_NAME_TEST3",
  1269. Value: "test2-dapi-test-pod-name-3",
  1270. },
  1271. {
  1272. Name: "LITERAL_TEST",
  1273. Value: "literal-test-test-test",
  1274. },
  1275. {
  1276. Name: "TEST_SERVICE_HOST",
  1277. Value: "1.2.3.3",
  1278. },
  1279. {
  1280. Name: "TEST_SERVICE_PORT",
  1281. Value: "8083",
  1282. },
  1283. {
  1284. Name: "TEST_PORT",
  1285. Value: "tcp://1.2.3.3:8083",
  1286. },
  1287. {
  1288. Name: "TEST_PORT_8083_TCP",
  1289. Value: "tcp://1.2.3.3:8083",
  1290. },
  1291. {
  1292. Name: "TEST_PORT_8083_TCP_PROTO",
  1293. Value: "tcp",
  1294. },
  1295. {
  1296. Name: "TEST_PORT_8083_TCP_PORT",
  1297. Value: "8083",
  1298. },
  1299. {
  1300. Name: "TEST_PORT_8083_TCP_ADDR",
  1301. Value: "1.2.3.3",
  1302. },
  1303. {
  1304. Name: "SERVICE_VAR_TEST",
  1305. Value: "1.2.3.3:8083",
  1306. },
  1307. {
  1308. Name: "OUT_OF_ORDER_TEST",
  1309. Value: "$(OUT_OF_ORDER_TARGET)",
  1310. },
  1311. {
  1312. Name: "OUT_OF_ORDER_TARGET",
  1313. Value: "FOO",
  1314. },
  1315. {
  1316. Name: "TEST_UNDEFINED",
  1317. Value: "$(UNDEFINED_VAR)",
  1318. },
  1319. {
  1320. Name: "EMPTY_VAR",
  1321. },
  1322. {
  1323. Name: "EMPTY_TEST",
  1324. Value: "foo-",
  1325. },
  1326. },
  1327. },
  1328. }
  1329. for i, tc := range testCases {
  1330. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  1331. kl := testKubelet.kubelet
  1332. kl.masterServiceNamespace = tc.masterServiceNs
  1333. if tc.nilLister {
  1334. kl.serviceLister = nil
  1335. } else {
  1336. kl.serviceLister = testServiceLister{services}
  1337. }
  1338. testPod := &api.Pod{
  1339. ObjectMeta: api.ObjectMeta{
  1340. Namespace: tc.ns,
  1341. Name: "dapi-test-pod-name",
  1342. },
  1343. Spec: api.PodSpec{
  1344. ServiceAccountName: "special",
  1345. NodeName: "node-name",
  1346. },
  1347. }
  1348. podIP := "1.2.3.4"
  1349. result, err := kl.makeEnvironmentVariables(testPod, tc.container, podIP)
  1350. if err != nil {
  1351. t.Errorf("[%v] Unexpected error: %v", tc.name, err)
  1352. }
  1353. sort.Sort(envs(result))
  1354. sort.Sort(envs(tc.expectedEnvs))
  1355. if !reflect.DeepEqual(result, tc.expectedEnvs) {
  1356. t.Errorf("%d: [%v] Unexpected env entries; expected {%v}, got {%v}", i, tc.name, tc.expectedEnvs, result)
  1357. }
  1358. }
  1359. }
  1360. func waitingState(cName string) api.ContainerStatus {
  1361. return api.ContainerStatus{
  1362. Name: cName,
  1363. State: api.ContainerState{
  1364. Waiting: &api.ContainerStateWaiting{},
  1365. },
  1366. }
  1367. }
  1368. func waitingStateWithLastTermination(cName string) api.ContainerStatus {
  1369. return api.ContainerStatus{
  1370. Name: cName,
  1371. State: api.ContainerState{
  1372. Waiting: &api.ContainerStateWaiting{},
  1373. },
  1374. LastTerminationState: api.ContainerState{
  1375. Terminated: &api.ContainerStateTerminated{
  1376. ExitCode: 0,
  1377. },
  1378. },
  1379. }
  1380. }
  1381. func runningState(cName string) api.ContainerStatus {
  1382. return api.ContainerStatus{
  1383. Name: cName,
  1384. State: api.ContainerState{
  1385. Running: &api.ContainerStateRunning{},
  1386. },
  1387. }
  1388. }
  1389. func stoppedState(cName string) api.ContainerStatus {
  1390. return api.ContainerStatus{
  1391. Name: cName,
  1392. State: api.ContainerState{
  1393. Terminated: &api.ContainerStateTerminated{},
  1394. },
  1395. }
  1396. }
  1397. func succeededState(cName string) api.ContainerStatus {
  1398. return api.ContainerStatus{
  1399. Name: cName,
  1400. State: api.ContainerState{
  1401. Terminated: &api.ContainerStateTerminated{
  1402. ExitCode: 0,
  1403. },
  1404. },
  1405. }
  1406. }
  1407. func failedState(cName string) api.ContainerStatus {
  1408. return api.ContainerStatus{
  1409. Name: cName,
  1410. State: api.ContainerState{
  1411. Terminated: &api.ContainerStateTerminated{
  1412. ExitCode: -1,
  1413. },
  1414. },
  1415. }
  1416. }
  1417. func TestPodPhaseWithRestartAlways(t *testing.T) {
  1418. desiredState := api.PodSpec{
  1419. NodeName: "machine",
  1420. Containers: []api.Container{
  1421. {Name: "containerA"},
  1422. {Name: "containerB"},
  1423. },
  1424. RestartPolicy: api.RestartPolicyAlways,
  1425. }
  1426. tests := []struct {
  1427. pod *api.Pod
  1428. status api.PodPhase
  1429. test string
  1430. }{
  1431. {&api.Pod{Spec: desiredState, Status: api.PodStatus{}}, api.PodPending, "waiting"},
  1432. {
  1433. &api.Pod{
  1434. Spec: desiredState,
  1435. Status: api.PodStatus{
  1436. ContainerStatuses: []api.ContainerStatus{
  1437. runningState("containerA"),
  1438. runningState("containerB"),
  1439. },
  1440. },
  1441. },
  1442. api.PodRunning,
  1443. "all running",
  1444. },
  1445. {
  1446. &api.Pod{
  1447. Spec: desiredState,
  1448. Status: api.PodStatus{
  1449. ContainerStatuses: []api.ContainerStatus{
  1450. stoppedState("containerA"),
  1451. stoppedState("containerB"),
  1452. },
  1453. },
  1454. },
  1455. api.PodRunning,
  1456. "all stopped with restart always",
  1457. },
  1458. {
  1459. &api.Pod{
  1460. Spec: desiredState,
  1461. Status: api.PodStatus{
  1462. ContainerStatuses: []api.ContainerStatus{
  1463. runningState("containerA"),
  1464. stoppedState("containerB"),
  1465. },
  1466. },
  1467. },
  1468. api.PodRunning,
  1469. "mixed state #1 with restart always",
  1470. },
  1471. {
  1472. &api.Pod{
  1473. Spec: desiredState,
  1474. Status: api.PodStatus{
  1475. ContainerStatuses: []api.ContainerStatus{
  1476. runningState("containerA"),
  1477. },
  1478. },
  1479. },
  1480. api.PodPending,
  1481. "mixed state #2 with restart always",
  1482. },
  1483. {
  1484. &api.Pod{
  1485. Spec: desiredState,
  1486. Status: api.PodStatus{
  1487. ContainerStatuses: []api.ContainerStatus{
  1488. runningState("containerA"),
  1489. waitingState("containerB"),
  1490. },
  1491. },
  1492. },
  1493. api.PodPending,
  1494. "mixed state #3 with restart always",
  1495. },
  1496. {
  1497. &api.Pod{
  1498. Spec: desiredState,
  1499. Status: api.PodStatus{
  1500. ContainerStatuses: []api.ContainerStatus{
  1501. runningState("containerA"),
  1502. waitingStateWithLastTermination("containerB"),
  1503. },
  1504. },
  1505. },
  1506. api.PodRunning,
  1507. "backoff crashloop container with restart always",
  1508. },
  1509. }
  1510. for _, test := range tests {
  1511. if status := GetPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status {
  1512. t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
  1513. }
  1514. }
  1515. }
  1516. func TestPodPhaseWithRestartNever(t *testing.T) {
  1517. desiredState := api.PodSpec{
  1518. NodeName: "machine",
  1519. Containers: []api.Container{
  1520. {Name: "containerA"},
  1521. {Name: "containerB"},
  1522. },
  1523. RestartPolicy: api.RestartPolicyNever,
  1524. }
  1525. tests := []struct {
  1526. pod *api.Pod
  1527. status api.PodPhase
  1528. test string
  1529. }{
  1530. {&api.Pod{Spec: desiredState, Status: api.PodStatus{}}, api.PodPending, "waiting"},
  1531. {
  1532. &api.Pod{
  1533. Spec: desiredState,
  1534. Status: api.PodStatus{
  1535. ContainerStatuses: []api.ContainerStatus{
  1536. runningState("containerA"),
  1537. runningState("containerB"),
  1538. },
  1539. },
  1540. },
  1541. api.PodRunning,
  1542. "all running with restart never",
  1543. },
  1544. {
  1545. &api.Pod{
  1546. Spec: desiredState,
  1547. Status: api.PodStatus{
  1548. ContainerStatuses: []api.ContainerStatus{
  1549. succeededState("containerA"),
  1550. succeededState("containerB"),
  1551. },
  1552. },
  1553. },
  1554. api.PodSucceeded,
  1555. "all succeeded with restart never",
  1556. },
  1557. {
  1558. &api.Pod{
  1559. Spec: desiredState,
  1560. Status: api.PodStatus{
  1561. ContainerStatuses: []api.ContainerStatus{
  1562. failedState("containerA"),
  1563. failedState("containerB"),
  1564. },
  1565. },
  1566. },
  1567. api.PodFailed,
  1568. "all failed with restart never",
  1569. },
  1570. {
  1571. &api.Pod{
  1572. Spec: desiredState,
  1573. Status: api.PodStatus{
  1574. ContainerStatuses: []api.ContainerStatus{
  1575. runningState("containerA"),
  1576. succeededState("containerB"),
  1577. },
  1578. },
  1579. },
  1580. api.PodRunning,
  1581. "mixed state #1 with restart never",
  1582. },
  1583. {
  1584. &api.Pod{
  1585. Spec: desiredState,
  1586. Status: api.PodStatus{
  1587. ContainerStatuses: []api.ContainerStatus{
  1588. runningState("containerA"),
  1589. },
  1590. },
  1591. },
  1592. api.PodPending,
  1593. "mixed state #2 with restart never",
  1594. },
  1595. {
  1596. &api.Pod{
  1597. Spec: desiredState,
  1598. Status: api.PodStatus{
  1599. ContainerStatuses: []api.ContainerStatus{
  1600. runningState("containerA"),
  1601. waitingState("containerB"),
  1602. },
  1603. },
  1604. },
  1605. api.PodPending,
  1606. "mixed state #3 with restart never",
  1607. },
  1608. }
  1609. for _, test := range tests {
  1610. if status := GetPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status {
  1611. t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
  1612. }
  1613. }
  1614. }
  1615. func TestPodPhaseWithRestartOnFailure(t *testing.T) {
  1616. desiredState := api.PodSpec{
  1617. NodeName: "machine",
  1618. Containers: []api.Container{
  1619. {Name: "containerA"},
  1620. {Name: "containerB"},
  1621. },
  1622. RestartPolicy: api.RestartPolicyOnFailure,
  1623. }
  1624. tests := []struct {
  1625. pod *api.Pod
  1626. status api.PodPhase
  1627. test string
  1628. }{
  1629. {&api.Pod{Spec: desiredState, Status: api.PodStatus{}}, api.PodPending, "waiting"},
  1630. {
  1631. &api.Pod{
  1632. Spec: desiredState,
  1633. Status: api.PodStatus{
  1634. ContainerStatuses: []api.ContainerStatus{
  1635. runningState("containerA"),
  1636. runningState("containerB"),
  1637. },
  1638. },
  1639. },
  1640. api.PodRunning,
  1641. "all running with restart onfailure",
  1642. },
  1643. {
  1644. &api.Pod{
  1645. Spec: desiredState,
  1646. Status: api.PodStatus{
  1647. ContainerStatuses: []api.ContainerStatus{
  1648. succeededState("containerA"),
  1649. succeededState("containerB"),
  1650. },
  1651. },
  1652. },
  1653. api.PodSucceeded,
  1654. "all succeeded with restart onfailure",
  1655. },
  1656. {
  1657. &api.Pod{
  1658. Spec: desiredState,
  1659. Status: api.PodStatus{
  1660. ContainerStatuses: []api.ContainerStatus{
  1661. failedState("containerA"),
  1662. failedState("containerB"),
  1663. },
  1664. },
  1665. },
  1666. api.PodRunning,
  1667. "all failed with restart never",
  1668. },
  1669. {
  1670. &api.Pod{
  1671. Spec: desiredState,
  1672. Status: api.PodStatus{
  1673. ContainerStatuses: []api.ContainerStatus{
  1674. runningState("containerA"),
  1675. succeededState("containerB"),
  1676. },
  1677. },
  1678. },
  1679. api.PodRunning,
  1680. "mixed state #1 with restart onfailure",
  1681. },
  1682. {
  1683. &api.Pod{
  1684. Spec: desiredState,
  1685. Status: api.PodStatus{
  1686. ContainerStatuses: []api.ContainerStatus{
  1687. runningState("containerA"),
  1688. },
  1689. },
  1690. },
  1691. api.PodPending,
  1692. "mixed state #2 with restart onfailure",
  1693. },
  1694. {
  1695. &api.Pod{
  1696. Spec: desiredState,
  1697. Status: api.PodStatus{
  1698. ContainerStatuses: []api.ContainerStatus{
  1699. runningState("containerA"),
  1700. waitingState("containerB"),
  1701. },
  1702. },
  1703. },
  1704. api.PodPending,
  1705. "mixed state #3 with restart onfailure",
  1706. },
  1707. {
  1708. &api.Pod{
  1709. Spec: desiredState,
  1710. Status: api.PodStatus{
  1711. ContainerStatuses: []api.ContainerStatus{
  1712. runningState("containerA"),
  1713. waitingStateWithLastTermination("containerB"),
  1714. },
  1715. },
  1716. },
  1717. api.PodRunning,
  1718. "backoff crashloop container with restart onfailure",
  1719. },
  1720. }
  1721. for _, test := range tests {
  1722. if status := GetPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status {
  1723. t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status)
  1724. }
  1725. }
  1726. }
  1727. func TestExecInContainerNoSuchPod(t *testing.T) {
  1728. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  1729. kubelet := testKubelet.kubelet
  1730. fakeRuntime := testKubelet.fakeRuntime
  1731. fakeCommandRunner := fakeContainerCommandRunner{}
  1732. kubelet.runner = &fakeCommandRunner
  1733. fakeRuntime.PodList = []*containertest.FakePod{}
  1734. podName := "podFoo"
  1735. podNamespace := "nsFoo"
  1736. containerID := "containerFoo"
  1737. err := kubelet.ExecInContainer(
  1738. kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{Name: podName, Namespace: podNamespace}}),
  1739. "",
  1740. containerID,
  1741. []string{"ls"},
  1742. nil,
  1743. nil,
  1744. nil,
  1745. false,
  1746. nil,
  1747. )
  1748. if err == nil {
  1749. t.Fatal("unexpected non-error")
  1750. }
  1751. if !fakeCommandRunner.ID.IsEmpty() {
  1752. t.Fatal("unexpected invocation of runner.ExecInContainer")
  1753. }
  1754. }
  1755. func TestExecInContainerNoSuchContainer(t *testing.T) {
  1756. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  1757. kubelet := testKubelet.kubelet
  1758. fakeRuntime := testKubelet.fakeRuntime
  1759. fakeCommandRunner := fakeContainerCommandRunner{}
  1760. kubelet.runner = &fakeCommandRunner
  1761. podName := "podFoo"
  1762. podNamespace := "nsFoo"
  1763. containerID := "containerFoo"
  1764. fakeRuntime.PodList = []*containertest.FakePod{
  1765. {Pod: &kubecontainer.Pod{
  1766. ID: "12345678",
  1767. Name: podName,
  1768. Namespace: podNamespace,
  1769. Containers: []*kubecontainer.Container{
  1770. {Name: "bar",
  1771. ID: kubecontainer.ContainerID{Type: "test", ID: "barID"}},
  1772. },
  1773. }},
  1774. }
  1775. err := kubelet.ExecInContainer(
  1776. kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{
  1777. UID: "12345678",
  1778. Name: podName,
  1779. Namespace: podNamespace,
  1780. }}),
  1781. "",
  1782. containerID,
  1783. []string{"ls"},
  1784. nil,
  1785. nil,
  1786. nil,
  1787. false,
  1788. nil,
  1789. )
  1790. if err == nil {
  1791. t.Fatal("unexpected non-error")
  1792. }
  1793. if !fakeCommandRunner.ID.IsEmpty() {
  1794. t.Fatal("unexpected invocation of runner.ExecInContainer")
  1795. }
  1796. }
  1797. type fakeReadWriteCloser struct{}
  1798. func (f *fakeReadWriteCloser) Write(data []byte) (int, error) {
  1799. return 0, nil
  1800. }
  1801. func (f *fakeReadWriteCloser) Read(data []byte) (int, error) {
  1802. return 0, nil
  1803. }
  1804. func (f *fakeReadWriteCloser) Close() error {
  1805. return nil
  1806. }
  1807. func TestExecInContainer(t *testing.T) {
  1808. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  1809. kubelet := testKubelet.kubelet
  1810. fakeRuntime := testKubelet.fakeRuntime
  1811. fakeCommandRunner := fakeContainerCommandRunner{}
  1812. kubelet.runner = &fakeCommandRunner
  1813. podName := "podFoo"
  1814. podNamespace := "nsFoo"
  1815. containerID := "containerFoo"
  1816. command := []string{"ls"}
  1817. stdin := &bytes.Buffer{}
  1818. stdout := &fakeReadWriteCloser{}
  1819. stderr := &fakeReadWriteCloser{}
  1820. tty := true
  1821. fakeRuntime.PodList = []*containertest.FakePod{
  1822. {Pod: &kubecontainer.Pod{
  1823. ID: "12345678",
  1824. Name: podName,
  1825. Namespace: podNamespace,
  1826. Containers: []*kubecontainer.Container{
  1827. {Name: containerID,
  1828. ID: kubecontainer.ContainerID{Type: "test", ID: containerID},
  1829. },
  1830. },
  1831. }},
  1832. }
  1833. err := kubelet.ExecInContainer(
  1834. kubecontainer.GetPodFullName(podWithUidNameNs("12345678", podName, podNamespace)),
  1835. "",
  1836. containerID,
  1837. []string{"ls"},
  1838. stdin,
  1839. stdout,
  1840. stderr,
  1841. tty,
  1842. nil,
  1843. )
  1844. if err != nil {
  1845. t.Fatalf("unexpected error: %s", err)
  1846. }
  1847. if e, a := containerID, fakeCommandRunner.ID.ID; e != a {
  1848. t.Fatalf("container name: expected %q, got %q", e, a)
  1849. }
  1850. if e, a := command, fakeCommandRunner.Cmd; !reflect.DeepEqual(e, a) {
  1851. t.Fatalf("command: expected '%v', got '%v'", e, a)
  1852. }
  1853. if e, a := stdin, fakeCommandRunner.Stdin; e != a {
  1854. t.Fatalf("stdin: expected %#v, got %#v", e, a)
  1855. }
  1856. if e, a := stdout, fakeCommandRunner.Stdout; e != a {
  1857. t.Fatalf("stdout: expected %#v, got %#v", e, a)
  1858. }
  1859. if e, a := stderr, fakeCommandRunner.Stderr; e != a {
  1860. t.Fatalf("stderr: expected %#v, got %#v", e, a)
  1861. }
  1862. if e, a := tty, fakeCommandRunner.TTY; e != a {
  1863. t.Fatalf("tty: expected %t, got %t", e, a)
  1864. }
  1865. }
  1866. func TestPortForwardNoSuchPod(t *testing.T) {
  1867. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  1868. kubelet := testKubelet.kubelet
  1869. fakeRuntime := testKubelet.fakeRuntime
  1870. fakeRuntime.PodList = []*containertest.FakePod{}
  1871. fakeCommandRunner := fakeContainerCommandRunner{}
  1872. kubelet.runner = &fakeCommandRunner
  1873. podName := "podFoo"
  1874. podNamespace := "nsFoo"
  1875. var port uint16 = 5000
  1876. err := kubelet.PortForward(
  1877. kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{Name: podName, Namespace: podNamespace}}),
  1878. "",
  1879. port,
  1880. nil,
  1881. )
  1882. if err == nil {
  1883. t.Fatal("unexpected non-error")
  1884. }
  1885. if !fakeCommandRunner.ID.IsEmpty() {
  1886. t.Fatal("unexpected invocation of runner.PortForward")
  1887. }
  1888. }
  1889. func TestPortForward(t *testing.T) {
  1890. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  1891. kubelet := testKubelet.kubelet
  1892. fakeRuntime := testKubelet.fakeRuntime
  1893. podName := "podFoo"
  1894. podNamespace := "nsFoo"
  1895. podID := types.UID("12345678")
  1896. fakeRuntime.PodList = []*containertest.FakePod{
  1897. {Pod: &kubecontainer.Pod{
  1898. ID: podID,
  1899. Name: podName,
  1900. Namespace: podNamespace,
  1901. Containers: []*kubecontainer.Container{
  1902. {
  1903. Name: "foo",
  1904. ID: kubecontainer.ContainerID{Type: "test", ID: "containerFoo"},
  1905. },
  1906. },
  1907. }},
  1908. }
  1909. fakeCommandRunner := fakeContainerCommandRunner{}
  1910. kubelet.runner = &fakeCommandRunner
  1911. var port uint16 = 5000
  1912. stream := &fakeReadWriteCloser{}
  1913. err := kubelet.PortForward(
  1914. kubecontainer.GetPodFullName(&api.Pod{ObjectMeta: api.ObjectMeta{
  1915. UID: "12345678",
  1916. Name: podName,
  1917. Namespace: podNamespace,
  1918. }}),
  1919. "",
  1920. port,
  1921. stream,
  1922. )
  1923. if err != nil {
  1924. t.Fatalf("unexpected error: %s", err)
  1925. }
  1926. if e, a := podID, fakeCommandRunner.PodID; e != a {
  1927. t.Fatalf("container id: expected %q, got %q", e, a)
  1928. }
  1929. if e, a := port, fakeCommandRunner.Port; e != a {
  1930. t.Fatalf("port: expected %v, got %v", e, a)
  1931. }
  1932. if e, a := stream, fakeCommandRunner.Stream; e != a {
  1933. t.Fatalf("stream: expected %v, got %v", e, a)
  1934. }
  1935. }
  1936. // Tests that identify the host port conflicts are detected correctly.
  1937. func TestGetHostPortConflicts(t *testing.T) {
  1938. pods := []*api.Pod{
  1939. {Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}},
  1940. {Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 81}}}}}},
  1941. {Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 82}}}}}},
  1942. {Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 83}}}}}},
  1943. }
  1944. // Pods should not cause any conflict.
  1945. if hasHostPortConflicts(pods) {
  1946. t.Errorf("expected no conflicts, Got conflicts")
  1947. }
  1948. expected := &api.Pod{
  1949. Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 81}}}}},
  1950. }
  1951. // The new pod should cause conflict and be reported.
  1952. pods = append(pods, expected)
  1953. if !hasHostPortConflicts(pods) {
  1954. t.Errorf("expected conflict, Got no conflicts")
  1955. }
  1956. }
  1957. // Tests that we handle port conflicts correctly by setting the failed status in status map.
  1958. func TestHandlePortConflicts(t *testing.T) {
  1959. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  1960. kl := testKubelet.kubelet
  1961. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  1962. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  1963. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  1964. kl.nodeLister = testNodeLister{nodes: []api.Node{
  1965. {
  1966. ObjectMeta: api.ObjectMeta{Name: kl.nodeName},
  1967. Status: api.NodeStatus{
  1968. Allocatable: api.ResourceList{
  1969. api.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  1970. },
  1971. },
  1972. },
  1973. }}
  1974. kl.nodeInfo = testNodeInfo{nodes: []api.Node{
  1975. {
  1976. ObjectMeta: api.ObjectMeta{Name: kl.nodeName},
  1977. Status: api.NodeStatus{
  1978. Allocatable: api.ResourceList{
  1979. api.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  1980. },
  1981. },
  1982. },
  1983. }}
  1984. spec := api.PodSpec{NodeName: kl.nodeName, Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}
  1985. pods := []*api.Pod{
  1986. podWithUidNameNsSpec("123456789", "newpod", "foo", spec),
  1987. podWithUidNameNsSpec("987654321", "oldpod", "foo", spec),
  1988. }
  1989. // Make sure the Pods are in the reverse order of creation time.
  1990. pods[1].CreationTimestamp = unversioned.NewTime(time.Now())
  1991. pods[0].CreationTimestamp = unversioned.NewTime(time.Now().Add(1 * time.Second))
  1992. // The newer pod should be rejected.
  1993. notfittingPod := pods[0]
  1994. fittingPod := pods[1]
  1995. kl.HandlePodAdditions(pods)
  1996. // Check pod status stored in the status map.
  1997. // notfittingPod should be Failed
  1998. status, found := kl.statusManager.GetPodStatus(notfittingPod.UID)
  1999. if !found {
  2000. t.Fatalf("status of pod %q is not found in the status map", notfittingPod.UID)
  2001. }
  2002. if status.Phase != api.PodFailed {
  2003. t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
  2004. }
  2005. // fittingPod should be Pending
  2006. status, found = kl.statusManager.GetPodStatus(fittingPod.UID)
  2007. if !found {
  2008. t.Fatalf("status of pod %q is not found in the status map", fittingPod.UID)
  2009. }
  2010. if status.Phase != api.PodPending {
  2011. t.Fatalf("expected pod status %q. Got %q.", api.PodPending, status.Phase)
  2012. }
  2013. }
  2014. // Tests that we handle host name conflicts correctly by setting the failed status in status map.
  2015. func TestHandleHostNameConflicts(t *testing.T) {
  2016. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2017. kl := testKubelet.kubelet
  2018. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2019. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2020. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2021. kl.nodeLister = testNodeLister{nodes: []api.Node{
  2022. {
  2023. ObjectMeta: api.ObjectMeta{Name: "127.0.0.1"},
  2024. Status: api.NodeStatus{
  2025. Allocatable: api.ResourceList{
  2026. api.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  2027. },
  2028. },
  2029. },
  2030. }}
  2031. kl.nodeInfo = testNodeInfo{nodes: []api.Node{
  2032. {
  2033. ObjectMeta: api.ObjectMeta{Name: "127.0.0.1"},
  2034. Status: api.NodeStatus{
  2035. Allocatable: api.ResourceList{
  2036. api.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  2037. },
  2038. },
  2039. },
  2040. }}
  2041. // default NodeName in test is 127.0.0.1
  2042. pods := []*api.Pod{
  2043. podWithUidNameNsSpec("123456789", "notfittingpod", "foo", api.PodSpec{NodeName: "127.0.0.2"}),
  2044. podWithUidNameNsSpec("987654321", "fittingpod", "foo", api.PodSpec{NodeName: "127.0.0.1"}),
  2045. }
  2046. notfittingPod := pods[0]
  2047. fittingPod := pods[1]
  2048. kl.HandlePodAdditions(pods)
  2049. // Check pod status stored in the status map.
  2050. // notfittingPod should be Failed
  2051. status, found := kl.statusManager.GetPodStatus(notfittingPod.UID)
  2052. if !found {
  2053. t.Fatalf("status of pod %q is not found in the status map", notfittingPod.UID)
  2054. }
  2055. if status.Phase != api.PodFailed {
  2056. t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
  2057. }
  2058. // fittingPod should be Pending
  2059. status, found = kl.statusManager.GetPodStatus(fittingPod.UID)
  2060. if !found {
  2061. t.Fatalf("status of pod %q is not found in the status map", fittingPod.UID)
  2062. }
  2063. if status.Phase != api.PodPending {
  2064. t.Fatalf("expected pod status %q. Got %q.", api.PodPending, status.Phase)
  2065. }
  2066. }
  2067. // Tests that we handle not matching labels selector correctly by setting the failed status in status map.
  2068. func TestHandleNodeSelector(t *testing.T) {
  2069. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2070. kl := testKubelet.kubelet
  2071. nodes := []api.Node{
  2072. {
  2073. ObjectMeta: api.ObjectMeta{Name: testKubeletHostname, Labels: map[string]string{"key": "B"}},
  2074. Status: api.NodeStatus{
  2075. Allocatable: api.ResourceList{
  2076. api.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  2077. },
  2078. },
  2079. },
  2080. }
  2081. kl.nodeLister = testNodeLister{nodes: nodes}
  2082. kl.nodeInfo = testNodeInfo{nodes: nodes}
  2083. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2084. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2085. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2086. pods := []*api.Pod{
  2087. podWithUidNameNsSpec("123456789", "podA", "foo", api.PodSpec{NodeSelector: map[string]string{"key": "A"}}),
  2088. podWithUidNameNsSpec("987654321", "podB", "foo", api.PodSpec{NodeSelector: map[string]string{"key": "B"}}),
  2089. }
  2090. // The first pod should be rejected.
  2091. notfittingPod := pods[0]
  2092. fittingPod := pods[1]
  2093. kl.HandlePodAdditions(pods)
  2094. // Check pod status stored in the status map.
  2095. // notfittingPod should be Failed
  2096. status, found := kl.statusManager.GetPodStatus(notfittingPod.UID)
  2097. if !found {
  2098. t.Fatalf("status of pod %q is not found in the status map", notfittingPod.UID)
  2099. }
  2100. if status.Phase != api.PodFailed {
  2101. t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
  2102. }
  2103. // fittingPod should be Pending
  2104. status, found = kl.statusManager.GetPodStatus(fittingPod.UID)
  2105. if !found {
  2106. t.Fatalf("status of pod %q is not found in the status map", fittingPod.UID)
  2107. }
  2108. if status.Phase != api.PodPending {
  2109. t.Fatalf("expected pod status %q. Got %q.", api.PodPending, status.Phase)
  2110. }
  2111. }
  2112. // Tests that we handle exceeded resources correctly by setting the failed status in status map.
  2113. func TestHandleMemExceeded(t *testing.T) {
  2114. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2115. kl := testKubelet.kubelet
  2116. nodes := []api.Node{
  2117. {ObjectMeta: api.ObjectMeta{Name: testKubeletHostname},
  2118. Status: api.NodeStatus{Capacity: api.ResourceList{}, Allocatable: api.ResourceList{
  2119. api.ResourceCPU: *resource.NewMilliQuantity(10, resource.DecimalSI),
  2120. api.ResourceMemory: *resource.NewQuantity(100, resource.BinarySI),
  2121. api.ResourcePods: *resource.NewQuantity(40, resource.DecimalSI),
  2122. }}},
  2123. }
  2124. kl.nodeLister = testNodeLister{nodes: nodes}
  2125. kl.nodeInfo = testNodeInfo{nodes: nodes}
  2126. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2127. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2128. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2129. spec := api.PodSpec{NodeName: kl.nodeName,
  2130. Containers: []api.Container{{Resources: api.ResourceRequirements{
  2131. Requests: api.ResourceList{
  2132. "memory": resource.MustParse("90"),
  2133. },
  2134. }}}}
  2135. pods := []*api.Pod{
  2136. podWithUidNameNsSpec("123456789", "newpod", "foo", spec),
  2137. podWithUidNameNsSpec("987654321", "oldpod", "foo", spec),
  2138. }
  2139. // Make sure the Pods are in the reverse order of creation time.
  2140. pods[1].CreationTimestamp = unversioned.NewTime(time.Now())
  2141. pods[0].CreationTimestamp = unversioned.NewTime(time.Now().Add(1 * time.Second))
  2142. // The newer pod should be rejected.
  2143. notfittingPod := pods[0]
  2144. fittingPod := pods[1]
  2145. kl.HandlePodAdditions(pods)
  2146. // Check pod status stored in the status map.
  2147. // notfittingPod should be Failed
  2148. status, found := kl.statusManager.GetPodStatus(notfittingPod.UID)
  2149. if !found {
  2150. t.Fatalf("status of pod %q is not found in the status map", notfittingPod.UID)
  2151. }
  2152. if status.Phase != api.PodFailed {
  2153. t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
  2154. }
  2155. // fittingPod should be Pending
  2156. status, found = kl.statusManager.GetPodStatus(fittingPod.UID)
  2157. if !found {
  2158. t.Fatalf("status of pod %q is not found in the status map", fittingPod.UID)
  2159. }
  2160. if status.Phase != api.PodPending {
  2161. t.Fatalf("expected pod status %q. Got %q.", api.PodPending, status.Phase)
  2162. }
  2163. }
  2164. // TODO(filipg): This test should be removed once StatusSyncer can do garbage collection without external signal.
  2165. func TestPurgingObsoleteStatusMapEntries(t *testing.T) {
  2166. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2167. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2168. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2169. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2170. versionInfo := &cadvisorapi.VersionInfo{
  2171. KernelVersion: "3.16.0-0.bpo.4-amd64",
  2172. ContainerOsVersion: "Debian GNU/Linux 7 (wheezy)",
  2173. DockerVersion: "1.5.0",
  2174. }
  2175. testKubelet.fakeCadvisor.On("VersionInfo").Return(versionInfo, nil)
  2176. kl := testKubelet.kubelet
  2177. pods := []*api.Pod{
  2178. {ObjectMeta: api.ObjectMeta{Name: "pod1", UID: "1234"}, Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}},
  2179. {ObjectMeta: api.ObjectMeta{Name: "pod2", UID: "4567"}, Spec: api.PodSpec{Containers: []api.Container{{Ports: []api.ContainerPort{{HostPort: 80}}}}}},
  2180. }
  2181. podToTest := pods[1]
  2182. // Run once to populate the status map.
  2183. kl.HandlePodAdditions(pods)
  2184. if _, found := kl.statusManager.GetPodStatus(podToTest.UID); !found {
  2185. t.Fatalf("expected to have status cached for pod2")
  2186. }
  2187. // Sync with empty pods so that the entry in status map will be removed.
  2188. kl.podManager.SetPods([]*api.Pod{})
  2189. kl.HandlePodCleanups()
  2190. if _, found := kl.statusManager.GetPodStatus(podToTest.UID); found {
  2191. t.Fatalf("expected to not have status cached for pod2")
  2192. }
  2193. }
  2194. func TestValidateContainerLogStatus(t *testing.T) {
  2195. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2196. kubelet := testKubelet.kubelet
  2197. containerName := "x"
  2198. testCases := []struct {
  2199. statuses []api.ContainerStatus
  2200. success bool
  2201. }{
  2202. {
  2203. statuses: []api.ContainerStatus{
  2204. {
  2205. Name: containerName,
  2206. State: api.ContainerState{
  2207. Running: &api.ContainerStateRunning{},
  2208. },
  2209. LastTerminationState: api.ContainerState{
  2210. Terminated: &api.ContainerStateTerminated{},
  2211. },
  2212. },
  2213. },
  2214. success: true,
  2215. },
  2216. {
  2217. statuses: []api.ContainerStatus{
  2218. {
  2219. Name: containerName,
  2220. State: api.ContainerState{
  2221. Running: &api.ContainerStateRunning{},
  2222. },
  2223. },
  2224. },
  2225. success: true,
  2226. },
  2227. {
  2228. statuses: []api.ContainerStatus{
  2229. {
  2230. Name: containerName,
  2231. State: api.ContainerState{
  2232. Terminated: &api.ContainerStateTerminated{},
  2233. },
  2234. },
  2235. },
  2236. success: true,
  2237. },
  2238. {
  2239. statuses: []api.ContainerStatus{
  2240. {
  2241. Name: containerName,
  2242. State: api.ContainerState{
  2243. Waiting: &api.ContainerStateWaiting{},
  2244. },
  2245. },
  2246. },
  2247. success: false,
  2248. },
  2249. {
  2250. statuses: []api.ContainerStatus{
  2251. {
  2252. Name: containerName,
  2253. State: api.ContainerState{Waiting: &api.ContainerStateWaiting{Reason: "ErrImagePull"}},
  2254. },
  2255. },
  2256. success: false,
  2257. },
  2258. {
  2259. statuses: []api.ContainerStatus{
  2260. {
  2261. Name: containerName,
  2262. State: api.ContainerState{Waiting: &api.ContainerStateWaiting{Reason: "ErrImagePullBackOff"}},
  2263. },
  2264. },
  2265. success: false,
  2266. },
  2267. }
  2268. for i, tc := range testCases {
  2269. _, err := kubelet.validateContainerLogStatus("podName", &api.PodStatus{
  2270. ContainerStatuses: tc.statuses,
  2271. }, containerName, false)
  2272. if tc.success {
  2273. if err != nil {
  2274. t.Errorf("[case %d]: unexpected failure - %v", i, err)
  2275. }
  2276. } else if err == nil {
  2277. t.Errorf("[case %d]: unexpected success", i)
  2278. }
  2279. }
  2280. if _, err := kubelet.validateContainerLogStatus("podName", &api.PodStatus{
  2281. ContainerStatuses: testCases[0].statuses,
  2282. }, "blah", false); err == nil {
  2283. t.Errorf("expected error with invalid container name")
  2284. }
  2285. if _, err := kubelet.validateContainerLogStatus("podName", &api.PodStatus{
  2286. ContainerStatuses: testCases[0].statuses,
  2287. }, containerName, true); err != nil {
  2288. t.Errorf("unexpected error with for previous terminated container - %v", err)
  2289. }
  2290. if _, err := kubelet.validateContainerLogStatus("podName", &api.PodStatus{
  2291. ContainerStatuses: testCases[0].statuses,
  2292. }, containerName, false); err != nil {
  2293. t.Errorf("unexpected error with for most recent container - %v", err)
  2294. }
  2295. if _, err := kubelet.validateContainerLogStatus("podName", &api.PodStatus{
  2296. ContainerStatuses: testCases[1].statuses,
  2297. }, containerName, true); err == nil {
  2298. t.Errorf("expected error with for previous terminated container")
  2299. }
  2300. if _, err := kubelet.validateContainerLogStatus("podName", &api.PodStatus{
  2301. ContainerStatuses: testCases[1].statuses,
  2302. }, containerName, false); err != nil {
  2303. t.Errorf("unexpected error with for most recent container")
  2304. }
  2305. }
  2306. // updateDiskSpacePolicy creates a new DiskSpaceManager with a new policy. This new manager along
  2307. // with the mock FsInfo values added to Cadvisor should make the kubelet report that it has
  2308. // sufficient disk space or it is out of disk, depending on the capacity, availability and
  2309. // threshold values.
  2310. func updateDiskSpacePolicy(kubelet *Kubelet, mockCadvisor *cadvisortest.Mock, rootCap, dockerCap, rootAvail, dockerAvail uint64, rootThreshold, dockerThreshold int) error {
  2311. dockerimagesFsInfo := cadvisorapiv2.FsInfo{Capacity: rootCap * mb, Available: rootAvail * mb}
  2312. rootFsInfo := cadvisorapiv2.FsInfo{Capacity: dockerCap * mb, Available: dockerAvail * mb}
  2313. mockCadvisor.On("ImagesFsInfo").Return(dockerimagesFsInfo, nil)
  2314. mockCadvisor.On("RootFsInfo").Return(rootFsInfo, nil)
  2315. dsp := DiskSpacePolicy{DockerFreeDiskMB: rootThreshold, RootFreeDiskMB: dockerThreshold}
  2316. diskSpaceManager, err := newDiskSpaceManager(mockCadvisor, dsp)
  2317. if err != nil {
  2318. return err
  2319. }
  2320. kubelet.diskSpaceManager = diskSpaceManager
  2321. return nil
  2322. }
  2323. func TestCreateMirrorPod(t *testing.T) {
  2324. for _, updateType := range []kubetypes.SyncPodType{kubetypes.SyncPodCreate, kubetypes.SyncPodUpdate} {
  2325. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2326. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2327. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2328. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2329. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2330. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2331. kl := testKubelet.kubelet
  2332. manager := testKubelet.fakeMirrorClient
  2333. pod := podWithUidNameNs("12345678", "bar", "foo")
  2334. pod.Annotations[kubetypes.ConfigSourceAnnotationKey] = "file"
  2335. pods := []*api.Pod{pod}
  2336. kl.podManager.SetPods(pods)
  2337. err := kl.syncPod(syncPodOptions{
  2338. pod: pod,
  2339. podStatus: &kubecontainer.PodStatus{},
  2340. updateType: updateType,
  2341. })
  2342. if err != nil {
  2343. t.Errorf("unexpected error: %v", err)
  2344. }
  2345. podFullName := kubecontainer.GetPodFullName(pod)
  2346. if !manager.HasPod(podFullName) {
  2347. t.Errorf("expected mirror pod %q to be created", podFullName)
  2348. }
  2349. if manager.NumOfPods() != 1 || !manager.HasPod(podFullName) {
  2350. t.Errorf("expected one mirror pod %q, got %v", podFullName, manager.GetPods())
  2351. }
  2352. }
  2353. }
  2354. func TestDeleteOutdatedMirrorPod(t *testing.T) {
  2355. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2356. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2357. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2358. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2359. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2360. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2361. kl := testKubelet.kubelet
  2362. manager := testKubelet.fakeMirrorClient
  2363. pod := podWithUidNameNsSpec("12345678", "foo", "ns", api.PodSpec{
  2364. Containers: []api.Container{
  2365. {Name: "1234", Image: "foo"},
  2366. },
  2367. })
  2368. pod.Annotations[kubetypes.ConfigSourceAnnotationKey] = "file"
  2369. // Mirror pod has an outdated spec.
  2370. mirrorPod := podWithUidNameNsSpec("11111111", "foo", "ns", api.PodSpec{
  2371. Containers: []api.Container{
  2372. {Name: "1234", Image: "bar"},
  2373. },
  2374. })
  2375. mirrorPod.Annotations[kubetypes.ConfigSourceAnnotationKey] = "api"
  2376. mirrorPod.Annotations[kubetypes.ConfigMirrorAnnotationKey] = "mirror"
  2377. pods := []*api.Pod{pod, mirrorPod}
  2378. kl.podManager.SetPods(pods)
  2379. err := kl.syncPod(syncPodOptions{
  2380. pod: pod,
  2381. mirrorPod: mirrorPod,
  2382. podStatus: &kubecontainer.PodStatus{},
  2383. updateType: kubetypes.SyncPodUpdate,
  2384. })
  2385. if err != nil {
  2386. t.Errorf("unexpected error: %v", err)
  2387. }
  2388. name := kubecontainer.GetPodFullName(pod)
  2389. creates, deletes := manager.GetCounts(name)
  2390. if creates != 1 || deletes != 1 {
  2391. t.Errorf("expected 1 creation and 1 deletion of %q, got %d, %d", name, creates, deletes)
  2392. }
  2393. }
  2394. func TestDeleteOrphanedMirrorPods(t *testing.T) {
  2395. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2396. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2397. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2398. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2399. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2400. kl := testKubelet.kubelet
  2401. manager := testKubelet.fakeMirrorClient
  2402. orphanPods := []*api.Pod{
  2403. {
  2404. ObjectMeta: api.ObjectMeta{
  2405. UID: "12345678",
  2406. Name: "pod1",
  2407. Namespace: "ns",
  2408. Annotations: map[string]string{
  2409. kubetypes.ConfigSourceAnnotationKey: "api",
  2410. kubetypes.ConfigMirrorAnnotationKey: "mirror",
  2411. },
  2412. },
  2413. },
  2414. {
  2415. ObjectMeta: api.ObjectMeta{
  2416. UID: "12345679",
  2417. Name: "pod2",
  2418. Namespace: "ns",
  2419. Annotations: map[string]string{
  2420. kubetypes.ConfigSourceAnnotationKey: "api",
  2421. kubetypes.ConfigMirrorAnnotationKey: "mirror",
  2422. },
  2423. },
  2424. },
  2425. }
  2426. kl.podManager.SetPods(orphanPods)
  2427. // Sync with an empty pod list to delete all mirror pods.
  2428. kl.HandlePodCleanups()
  2429. if manager.NumOfPods() != 0 {
  2430. t.Errorf("expected zero mirror pods, got %v", manager.GetPods())
  2431. }
  2432. for _, pod := range orphanPods {
  2433. name := kubecontainer.GetPodFullName(pod)
  2434. creates, deletes := manager.GetCounts(name)
  2435. if creates != 0 || deletes != 1 {
  2436. t.Errorf("expected 0 creation and one deletion of %q, got %d, %d", name, creates, deletes)
  2437. }
  2438. }
  2439. }
  2440. func TestGetContainerInfoForMirrorPods(t *testing.T) {
  2441. // pods contain one static and one mirror pod with the same name but
  2442. // different UIDs.
  2443. pods := []*api.Pod{
  2444. {
  2445. ObjectMeta: api.ObjectMeta{
  2446. UID: "1234",
  2447. Name: "qux",
  2448. Namespace: "ns",
  2449. Annotations: map[string]string{
  2450. kubetypes.ConfigSourceAnnotationKey: "file",
  2451. },
  2452. },
  2453. Spec: api.PodSpec{
  2454. Containers: []api.Container{
  2455. {Name: "foo"},
  2456. },
  2457. },
  2458. },
  2459. {
  2460. ObjectMeta: api.ObjectMeta{
  2461. UID: "5678",
  2462. Name: "qux",
  2463. Namespace: "ns",
  2464. Annotations: map[string]string{
  2465. kubetypes.ConfigSourceAnnotationKey: "api",
  2466. kubetypes.ConfigMirrorAnnotationKey: "mirror",
  2467. },
  2468. },
  2469. Spec: api.PodSpec{
  2470. Containers: []api.Container{
  2471. {Name: "foo"},
  2472. },
  2473. },
  2474. },
  2475. }
  2476. containerID := "ab2cdf"
  2477. containerPath := fmt.Sprintf("/docker/%v", containerID)
  2478. containerInfo := cadvisorapi.ContainerInfo{
  2479. ContainerReference: cadvisorapi.ContainerReference{
  2480. Name: containerPath,
  2481. },
  2482. }
  2483. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2484. fakeRuntime := testKubelet.fakeRuntime
  2485. mockCadvisor := testKubelet.fakeCadvisor
  2486. cadvisorReq := &cadvisorapi.ContainerInfoRequest{}
  2487. mockCadvisor.On("DockerContainer", containerID, cadvisorReq).Return(containerInfo, nil)
  2488. kubelet := testKubelet.kubelet
  2489. fakeRuntime.PodList = []*containertest.FakePod{
  2490. {Pod: &kubecontainer.Pod{
  2491. ID: "1234",
  2492. Name: "qux",
  2493. Namespace: "ns",
  2494. Containers: []*kubecontainer.Container{
  2495. {
  2496. Name: "foo",
  2497. ID: kubecontainer.ContainerID{Type: "test", ID: containerID},
  2498. },
  2499. },
  2500. }},
  2501. }
  2502. kubelet.podManager.SetPods(pods)
  2503. // Use the mirror pod UID to retrieve the stats.
  2504. stats, err := kubelet.GetContainerInfo("qux_ns", "5678", "foo", cadvisorReq)
  2505. if err != nil {
  2506. t.Errorf("unexpected error: %v", err)
  2507. }
  2508. if stats == nil {
  2509. t.Fatalf("stats should not be nil")
  2510. }
  2511. mockCadvisor.AssertExpectations(t)
  2512. }
  2513. func TestHostNetworkAllowed(t *testing.T) {
  2514. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2515. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2516. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2517. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2518. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2519. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2520. kubelet := testKubelet.kubelet
  2521. capabilities.SetForTests(capabilities.Capabilities{
  2522. PrivilegedSources: capabilities.PrivilegedSources{
  2523. HostNetworkSources: []string{kubetypes.ApiserverSource, kubetypes.FileSource},
  2524. },
  2525. })
  2526. pod := podWithUidNameNsSpec("12345678", "foo", "new", api.PodSpec{
  2527. Containers: []api.Container{
  2528. {Name: "foo"},
  2529. },
  2530. SecurityContext: &api.PodSecurityContext{
  2531. HostNetwork: true,
  2532. },
  2533. })
  2534. pod.Annotations[kubetypes.ConfigSourceAnnotationKey] = kubetypes.FileSource
  2535. kubelet.podManager.SetPods([]*api.Pod{pod})
  2536. err := kubelet.syncPod(syncPodOptions{
  2537. pod: pod,
  2538. podStatus: &kubecontainer.PodStatus{},
  2539. updateType: kubetypes.SyncPodUpdate,
  2540. })
  2541. if err != nil {
  2542. t.Errorf("expected pod infra creation to succeed: %v", err)
  2543. }
  2544. }
  2545. func TestHostNetworkDisallowed(t *testing.T) {
  2546. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2547. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2548. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2549. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2550. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2551. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2552. kubelet := testKubelet.kubelet
  2553. capabilities.SetForTests(capabilities.Capabilities{
  2554. PrivilegedSources: capabilities.PrivilegedSources{
  2555. HostNetworkSources: []string{},
  2556. },
  2557. })
  2558. pod := podWithUidNameNsSpec("12345678", "foo", "new", api.PodSpec{
  2559. Containers: []api.Container{
  2560. {Name: "foo"},
  2561. },
  2562. SecurityContext: &api.PodSecurityContext{
  2563. HostNetwork: true,
  2564. },
  2565. })
  2566. pod.Annotations[kubetypes.ConfigSourceAnnotationKey] = kubetypes.FileSource
  2567. err := kubelet.syncPod(syncPodOptions{
  2568. pod: pod,
  2569. podStatus: &kubecontainer.PodStatus{},
  2570. updateType: kubetypes.SyncPodUpdate,
  2571. })
  2572. if err == nil {
  2573. t.Errorf("expected pod infra creation to fail")
  2574. }
  2575. }
  2576. func TestPrivilegeContainerAllowed(t *testing.T) {
  2577. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2578. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2579. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2580. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2581. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2582. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2583. kubelet := testKubelet.kubelet
  2584. capabilities.SetForTests(capabilities.Capabilities{
  2585. AllowPrivileged: true,
  2586. })
  2587. privileged := true
  2588. pod := podWithUidNameNsSpec("12345678", "foo", "new", api.PodSpec{
  2589. Containers: []api.Container{
  2590. {Name: "foo", SecurityContext: &api.SecurityContext{Privileged: &privileged}},
  2591. },
  2592. })
  2593. kubelet.podManager.SetPods([]*api.Pod{pod})
  2594. err := kubelet.syncPod(syncPodOptions{
  2595. pod: pod,
  2596. podStatus: &kubecontainer.PodStatus{},
  2597. updateType: kubetypes.SyncPodUpdate,
  2598. })
  2599. if err != nil {
  2600. t.Errorf("expected pod infra creation to succeed: %v", err)
  2601. }
  2602. }
  2603. func TestPrivilegedContainerDisallowed(t *testing.T) {
  2604. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2605. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2606. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2607. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2608. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2609. kubelet := testKubelet.kubelet
  2610. capabilities.SetForTests(capabilities.Capabilities{
  2611. AllowPrivileged: false,
  2612. })
  2613. privileged := true
  2614. pod := podWithUidNameNsSpec("12345678", "foo", "new", api.PodSpec{
  2615. Containers: []api.Container{
  2616. {Name: "foo", SecurityContext: &api.SecurityContext{Privileged: &privileged}},
  2617. },
  2618. })
  2619. err := kubelet.syncPod(syncPodOptions{
  2620. pod: pod,
  2621. podStatus: &kubecontainer.PodStatus{},
  2622. updateType: kubetypes.SyncPodUpdate,
  2623. })
  2624. if err == nil {
  2625. t.Errorf("expected pod infra creation to fail")
  2626. }
  2627. }
  2628. func TestFilterOutTerminatedPods(t *testing.T) {
  2629. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2630. kubelet := testKubelet.kubelet
  2631. pods := newTestPods(5)
  2632. pods[0].Status.Phase = api.PodFailed
  2633. pods[1].Status.Phase = api.PodSucceeded
  2634. pods[2].Status.Phase = api.PodRunning
  2635. pods[3].Status.Phase = api.PodPending
  2636. expected := []*api.Pod{pods[2], pods[3], pods[4]}
  2637. kubelet.podManager.SetPods(pods)
  2638. actual := kubelet.filterOutTerminatedPods(pods)
  2639. if !reflect.DeepEqual(expected, actual) {
  2640. t.Errorf("expected %#v, got %#v", expected, actual)
  2641. }
  2642. }
  2643. func TestMakePortMappings(t *testing.T) {
  2644. port := func(name string, protocol api.Protocol, containerPort, hostPort int32, ip string) api.ContainerPort {
  2645. return api.ContainerPort{
  2646. Name: name,
  2647. Protocol: protocol,
  2648. ContainerPort: containerPort,
  2649. HostPort: hostPort,
  2650. HostIP: ip,
  2651. }
  2652. }
  2653. portMapping := func(name string, protocol api.Protocol, containerPort, hostPort int, ip string) kubecontainer.PortMapping {
  2654. return kubecontainer.PortMapping{
  2655. Name: name,
  2656. Protocol: protocol,
  2657. ContainerPort: containerPort,
  2658. HostPort: hostPort,
  2659. HostIP: ip,
  2660. }
  2661. }
  2662. tests := []struct {
  2663. container *api.Container
  2664. expectedPortMappings []kubecontainer.PortMapping
  2665. }{
  2666. {
  2667. &api.Container{
  2668. Name: "fooContainer",
  2669. Ports: []api.ContainerPort{
  2670. port("", api.ProtocolTCP, 80, 8080, "127.0.0.1"),
  2671. port("", api.ProtocolTCP, 443, 4343, "192.168.0.1"),
  2672. port("foo", api.ProtocolUDP, 555, 5555, ""),
  2673. // Duplicated, should be ignored.
  2674. port("foo", api.ProtocolUDP, 888, 8888, ""),
  2675. // Duplicated, should be ignored.
  2676. port("", api.ProtocolTCP, 80, 8888, ""),
  2677. },
  2678. },
  2679. []kubecontainer.PortMapping{
  2680. portMapping("fooContainer-TCP:80", api.ProtocolTCP, 80, 8080, "127.0.0.1"),
  2681. portMapping("fooContainer-TCP:443", api.ProtocolTCP, 443, 4343, "192.168.0.1"),
  2682. portMapping("fooContainer-foo", api.ProtocolUDP, 555, 5555, ""),
  2683. },
  2684. },
  2685. }
  2686. for i, tt := range tests {
  2687. actual := makePortMappings(tt.container)
  2688. if !reflect.DeepEqual(tt.expectedPortMappings, actual) {
  2689. t.Errorf("%d: Expected: %#v, saw: %#v", i, tt.expectedPortMappings, actual)
  2690. }
  2691. }
  2692. }
  2693. func TestSyncPodsSetStatusToFailedForPodsThatRunTooLong(t *testing.T) {
  2694. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2695. fakeRuntime := testKubelet.fakeRuntime
  2696. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2697. kubelet := testKubelet.kubelet
  2698. now := unversioned.Now()
  2699. startTime := unversioned.NewTime(now.Time.Add(-1 * time.Minute))
  2700. exceededActiveDeadlineSeconds := int64(30)
  2701. pods := []*api.Pod{
  2702. {
  2703. ObjectMeta: api.ObjectMeta{
  2704. UID: "12345678",
  2705. Name: "bar",
  2706. Namespace: "new",
  2707. },
  2708. Spec: api.PodSpec{
  2709. Containers: []api.Container{
  2710. {Name: "foo"},
  2711. },
  2712. ActiveDeadlineSeconds: &exceededActiveDeadlineSeconds,
  2713. },
  2714. Status: api.PodStatus{
  2715. StartTime: &startTime,
  2716. },
  2717. },
  2718. }
  2719. fakeRuntime.PodList = []*containertest.FakePod{
  2720. {Pod: &kubecontainer.Pod{
  2721. ID: "12345678",
  2722. Name: "bar",
  2723. Namespace: "new",
  2724. Containers: []*kubecontainer.Container{
  2725. {Name: "foo"},
  2726. },
  2727. }},
  2728. }
  2729. // Let the pod worker sets the status to fail after this sync.
  2730. kubelet.HandlePodUpdates(pods)
  2731. status, found := kubelet.statusManager.GetPodStatus(pods[0].UID)
  2732. if !found {
  2733. t.Errorf("expected to found status for pod %q", pods[0].UID)
  2734. }
  2735. if status.Phase != api.PodFailed {
  2736. t.Fatalf("expected pod status %q, got %q.", api.PodFailed, status.Phase)
  2737. }
  2738. }
  2739. func TestSyncPodsDoesNotSetPodsThatDidNotRunTooLongToFailed(t *testing.T) {
  2740. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2741. fakeRuntime := testKubelet.fakeRuntime
  2742. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2743. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2744. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2745. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2746. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2747. kubelet := testKubelet.kubelet
  2748. now := unversioned.Now()
  2749. startTime := unversioned.NewTime(now.Time.Add(-1 * time.Minute))
  2750. exceededActiveDeadlineSeconds := int64(300)
  2751. pods := []*api.Pod{
  2752. {
  2753. ObjectMeta: api.ObjectMeta{
  2754. UID: "12345678",
  2755. Name: "bar",
  2756. Namespace: "new",
  2757. },
  2758. Spec: api.PodSpec{
  2759. Containers: []api.Container{
  2760. {Name: "foo"},
  2761. },
  2762. ActiveDeadlineSeconds: &exceededActiveDeadlineSeconds,
  2763. },
  2764. Status: api.PodStatus{
  2765. StartTime: &startTime,
  2766. },
  2767. },
  2768. }
  2769. fakeRuntime.PodList = []*containertest.FakePod{
  2770. {Pod: &kubecontainer.Pod{
  2771. ID: "12345678",
  2772. Name: "bar",
  2773. Namespace: "new",
  2774. Containers: []*kubecontainer.Container{
  2775. {Name: "foo"},
  2776. },
  2777. }},
  2778. }
  2779. kubelet.podManager.SetPods(pods)
  2780. kubelet.HandlePodUpdates(pods)
  2781. status, found := kubelet.statusManager.GetPodStatus(pods[0].UID)
  2782. if !found {
  2783. t.Errorf("expected to found status for pod %q", pods[0].UID)
  2784. }
  2785. if status.Phase == api.PodFailed {
  2786. t.Fatalf("expected pod status to not be %q", status.Phase)
  2787. }
  2788. }
  2789. func podWithUidNameNs(uid types.UID, name, namespace string) *api.Pod {
  2790. return &api.Pod{
  2791. ObjectMeta: api.ObjectMeta{
  2792. UID: uid,
  2793. Name: name,
  2794. Namespace: namespace,
  2795. Annotations: map[string]string{},
  2796. },
  2797. }
  2798. }
  2799. func podWithUidNameNsSpec(uid types.UID, name, namespace string, spec api.PodSpec) *api.Pod {
  2800. pod := podWithUidNameNs(uid, name, namespace)
  2801. pod.Spec = spec
  2802. return pod
  2803. }
  2804. func TestDeletePodDirsForDeletedPods(t *testing.T) {
  2805. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2806. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2807. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2808. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2809. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2810. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2811. kl := testKubelet.kubelet
  2812. pods := []*api.Pod{
  2813. podWithUidNameNs("12345678", "pod1", "ns"),
  2814. podWithUidNameNs("12345679", "pod2", "ns"),
  2815. }
  2816. kl.podManager.SetPods(pods)
  2817. // Sync to create pod directories.
  2818. kl.HandlePodSyncs(kl.podManager.GetPods())
  2819. for i := range pods {
  2820. if !dirExists(kl.getPodDir(pods[i].UID)) {
  2821. t.Errorf("expected directory to exist for pod %d", i)
  2822. }
  2823. }
  2824. // Pod 1 has been deleted and no longer exists.
  2825. kl.podManager.SetPods([]*api.Pod{pods[0]})
  2826. kl.HandlePodCleanups()
  2827. if !dirExists(kl.getPodDir(pods[0].UID)) {
  2828. t.Errorf("expected directory to exist for pod 0")
  2829. }
  2830. if dirExists(kl.getPodDir(pods[1].UID)) {
  2831. t.Errorf("expected directory to be deleted for pod 1")
  2832. }
  2833. }
  2834. func syncAndVerifyPodDir(t *testing.T, testKubelet *TestKubelet, pods []*api.Pod, podsToCheck []*api.Pod, shouldExist bool) {
  2835. kl := testKubelet.kubelet
  2836. kl.podManager.SetPods(pods)
  2837. kl.HandlePodSyncs(pods)
  2838. kl.HandlePodCleanups()
  2839. for i, pod := range podsToCheck {
  2840. exist := dirExists(kl.getPodDir(pod.UID))
  2841. if shouldExist && !exist {
  2842. t.Errorf("expected directory to exist for pod %d", i)
  2843. } else if !shouldExist && exist {
  2844. t.Errorf("expected directory to be removed for pod %d", i)
  2845. }
  2846. }
  2847. }
  2848. func TestDoesNotDeletePodDirsForTerminatedPods(t *testing.T) {
  2849. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2850. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2851. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2852. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2853. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2854. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2855. kl := testKubelet.kubelet
  2856. pods := []*api.Pod{
  2857. podWithUidNameNs("12345678", "pod1", "ns"),
  2858. podWithUidNameNs("12345679", "pod2", "ns"),
  2859. podWithUidNameNs("12345680", "pod3", "ns"),
  2860. }
  2861. syncAndVerifyPodDir(t, testKubelet, pods, pods, true)
  2862. // Pod 1 failed, and pod 2 succeeded. None of the pod directories should be
  2863. // deleted.
  2864. kl.statusManager.SetPodStatus(pods[1], api.PodStatus{Phase: api.PodFailed})
  2865. kl.statusManager.SetPodStatus(pods[2], api.PodStatus{Phase: api.PodSucceeded})
  2866. syncAndVerifyPodDir(t, testKubelet, pods, pods, true)
  2867. }
  2868. func TestDoesNotDeletePodDirsIfContainerIsRunning(t *testing.T) {
  2869. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2870. testKubelet.fakeCadvisor.On("Start").Return(nil)
  2871. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2872. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2873. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2874. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2875. runningPod := &kubecontainer.Pod{
  2876. ID: "12345678",
  2877. Name: "pod1",
  2878. Namespace: "ns",
  2879. }
  2880. apiPod := podWithUidNameNs(runningPod.ID, runningPod.Name, runningPod.Namespace)
  2881. // Sync once to create pod directory; confirm that the pod directory has
  2882. // already been created.
  2883. pods := []*api.Pod{apiPod}
  2884. syncAndVerifyPodDir(t, testKubelet, pods, []*api.Pod{apiPod}, true)
  2885. // Pretend the pod is deleted from apiserver, but is still active on the node.
  2886. // The pod directory should not be removed.
  2887. pods = []*api.Pod{}
  2888. testKubelet.fakeRuntime.PodList = []*containertest.FakePod{{runningPod, ""}}
  2889. syncAndVerifyPodDir(t, testKubelet, pods, []*api.Pod{apiPod}, true)
  2890. // The pod is deleted and also not active on the node. The pod directory
  2891. // should be removed.
  2892. pods = []*api.Pod{}
  2893. testKubelet.fakeRuntime.PodList = []*containertest.FakePod{}
  2894. syncAndVerifyPodDir(t, testKubelet, pods, []*api.Pod{apiPod}, false)
  2895. }
  2896. func TestGetPodsToSync(t *testing.T) {
  2897. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2898. kubelet := testKubelet.kubelet
  2899. clock := testKubelet.fakeClock
  2900. pods := newTestPods(5)
  2901. exceededActiveDeadlineSeconds := int64(30)
  2902. notYetActiveDeadlineSeconds := int64(120)
  2903. startTime := unversioned.NewTime(clock.Now())
  2904. pods[0].Status.StartTime = &startTime
  2905. pods[0].Spec.ActiveDeadlineSeconds = &exceededActiveDeadlineSeconds
  2906. pods[1].Status.StartTime = &startTime
  2907. pods[1].Spec.ActiveDeadlineSeconds = &notYetActiveDeadlineSeconds
  2908. pods[2].Status.StartTime = &startTime
  2909. pods[2].Spec.ActiveDeadlineSeconds = &exceededActiveDeadlineSeconds
  2910. kubelet.podManager.SetPods(pods)
  2911. kubelet.workQueue.Enqueue(pods[2].UID, 0)
  2912. kubelet.workQueue.Enqueue(pods[3].UID, 30*time.Second)
  2913. kubelet.workQueue.Enqueue(pods[4].UID, 2*time.Minute)
  2914. clock.Step(1 * time.Minute)
  2915. expectedPods := []*api.Pod{pods[0], pods[2], pods[3]}
  2916. podsToSync := kubelet.getPodsToSync()
  2917. if len(podsToSync) == len(expectedPods) {
  2918. for _, expect := range expectedPods {
  2919. var found bool
  2920. for _, got := range podsToSync {
  2921. if expect.UID == got.UID {
  2922. found = true
  2923. break
  2924. }
  2925. }
  2926. if !found {
  2927. t.Errorf("expected pod not found: %#v", expect)
  2928. }
  2929. }
  2930. } else {
  2931. t.Errorf("expected %d pods to sync, got %d", len(expectedPods), len(podsToSync))
  2932. }
  2933. }
  2934. func TestGenerateAPIPodStatusWithSortedContainers(t *testing.T) {
  2935. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  2936. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  2937. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  2938. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2939. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  2940. kubelet := testKubelet.kubelet
  2941. numContainers := 10
  2942. expectedOrder := []string{}
  2943. cStatuses := []*kubecontainer.ContainerStatus{}
  2944. specContainerList := []api.Container{}
  2945. for i := 0; i < numContainers; i++ {
  2946. id := fmt.Sprintf("%v", i)
  2947. containerName := fmt.Sprintf("%vcontainer", id)
  2948. expectedOrder = append(expectedOrder, containerName)
  2949. cStatus := &kubecontainer.ContainerStatus{
  2950. ID: kubecontainer.BuildContainerID("test", id),
  2951. Name: containerName,
  2952. }
  2953. // Rearrange container statuses
  2954. if i%2 == 0 {
  2955. cStatuses = append(cStatuses, cStatus)
  2956. } else {
  2957. cStatuses = append([]*kubecontainer.ContainerStatus{cStatus}, cStatuses...)
  2958. }
  2959. specContainerList = append(specContainerList, api.Container{Name: containerName})
  2960. }
  2961. pod := podWithUidNameNs("uid1", "foo", "test")
  2962. pod.Spec = api.PodSpec{
  2963. Containers: specContainerList,
  2964. }
  2965. status := &kubecontainer.PodStatus{
  2966. ID: pod.UID,
  2967. Name: pod.Name,
  2968. Namespace: pod.Namespace,
  2969. ContainerStatuses: cStatuses,
  2970. }
  2971. for i := 0; i < 5; i++ {
  2972. apiStatus := kubelet.generateAPIPodStatus(pod, status)
  2973. for i, c := range apiStatus.ContainerStatuses {
  2974. if expectedOrder[i] != c.Name {
  2975. t.Fatalf("Container status not sorted, expected %v at index %d, but found %v", expectedOrder[i], i, c.Name)
  2976. }
  2977. }
  2978. }
  2979. }
  2980. func verifyContainerStatuses(statuses []api.ContainerStatus, state, lastTerminationState map[string]api.ContainerState) error {
  2981. for _, s := range statuses {
  2982. if !reflect.DeepEqual(s.State, state[s.Name]) {
  2983. return fmt.Errorf("unexpected state: %s", diff.ObjectDiff(state[s.Name], s.State))
  2984. }
  2985. if !reflect.DeepEqual(s.LastTerminationState, lastTerminationState[s.Name]) {
  2986. return fmt.Errorf("unexpected last termination state %s", diff.ObjectDiff(
  2987. lastTerminationState[s.Name], s.LastTerminationState))
  2988. }
  2989. }
  2990. return nil
  2991. }
  2992. // Test generateAPIPodStatus with different reason cache and old api pod status.
  2993. func TestGenerateAPIPodStatusWithReasonCache(t *testing.T) {
  2994. // The following waiting reason and message are generated in convertStatusToAPIStatus()
  2995. startWaitingReason := "ContainerCreating"
  2996. initWaitingReason := "PodInitializing"
  2997. testTimestamp := time.Unix(123456789, 987654321)
  2998. testErrorReason := fmt.Errorf("test-error")
  2999. emptyContainerID := (&kubecontainer.ContainerID{}).String()
  3000. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  3001. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  3002. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  3003. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  3004. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  3005. kubelet := testKubelet.kubelet
  3006. pod := podWithUidNameNs("12345678", "foo", "new")
  3007. pod.Spec = api.PodSpec{RestartPolicy: api.RestartPolicyOnFailure}
  3008. podStatus := &kubecontainer.PodStatus{
  3009. ID: pod.UID,
  3010. Name: pod.Name,
  3011. Namespace: pod.Namespace,
  3012. }
  3013. tests := []struct {
  3014. containers []api.Container
  3015. statuses []*kubecontainer.ContainerStatus
  3016. reasons map[string]error
  3017. oldStatuses []api.ContainerStatus
  3018. expectedState map[string]api.ContainerState
  3019. // Only set expectedInitState when it is different from expectedState
  3020. expectedInitState map[string]api.ContainerState
  3021. expectedLastTerminationState map[string]api.ContainerState
  3022. }{
  3023. // For container with no historical record, State should be Waiting, LastTerminationState should be retrieved from
  3024. // old status from apiserver.
  3025. {
  3026. containers: []api.Container{{Name: "without-old-record"}, {Name: "with-old-record"}},
  3027. statuses: []*kubecontainer.ContainerStatus{},
  3028. reasons: map[string]error{},
  3029. oldStatuses: []api.ContainerStatus{{
  3030. Name: "with-old-record",
  3031. LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{}},
  3032. }},
  3033. expectedState: map[string]api.ContainerState{
  3034. "without-old-record": {Waiting: &api.ContainerStateWaiting{
  3035. Reason: startWaitingReason,
  3036. }},
  3037. "with-old-record": {Waiting: &api.ContainerStateWaiting{
  3038. Reason: startWaitingReason,
  3039. }},
  3040. },
  3041. expectedInitState: map[string]api.ContainerState{
  3042. "without-old-record": {Waiting: &api.ContainerStateWaiting{
  3043. Reason: initWaitingReason,
  3044. }},
  3045. "with-old-record": {Waiting: &api.ContainerStateWaiting{
  3046. Reason: initWaitingReason,
  3047. }},
  3048. },
  3049. expectedLastTerminationState: map[string]api.ContainerState{
  3050. "with-old-record": {Terminated: &api.ContainerStateTerminated{}},
  3051. },
  3052. },
  3053. // For running container, State should be Running, LastTerminationState should be retrieved from latest terminated status.
  3054. {
  3055. containers: []api.Container{{Name: "running"}},
  3056. statuses: []*kubecontainer.ContainerStatus{
  3057. {
  3058. Name: "running",
  3059. State: kubecontainer.ContainerStateRunning,
  3060. StartedAt: testTimestamp,
  3061. },
  3062. {
  3063. Name: "running",
  3064. State: kubecontainer.ContainerStateExited,
  3065. ExitCode: 1,
  3066. },
  3067. },
  3068. reasons: map[string]error{},
  3069. oldStatuses: []api.ContainerStatus{},
  3070. expectedState: map[string]api.ContainerState{
  3071. "running": {Running: &api.ContainerStateRunning{
  3072. StartedAt: unversioned.NewTime(testTimestamp),
  3073. }},
  3074. },
  3075. expectedLastTerminationState: map[string]api.ContainerState{
  3076. "running": {Terminated: &api.ContainerStateTerminated{
  3077. ExitCode: 1,
  3078. ContainerID: emptyContainerID,
  3079. }},
  3080. },
  3081. },
  3082. // For terminated container:
  3083. // * If there is no recent start error record, State should be Terminated, LastTerminationState should be retrieved from
  3084. // second latest terminated status;
  3085. // * If there is recent start error record, State should be Waiting, LastTerminationState should be retrieved from latest
  3086. // terminated status;
  3087. // * If ExitCode = 0, restart policy is RestartPolicyOnFailure, the container shouldn't be restarted. No matter there is
  3088. // recent start error or not, State should be Terminated, LastTerminationState should be retrieved from second latest
  3089. // terminated status.
  3090. {
  3091. containers: []api.Container{{Name: "without-reason"}, {Name: "with-reason"}},
  3092. statuses: []*kubecontainer.ContainerStatus{
  3093. {
  3094. Name: "without-reason",
  3095. State: kubecontainer.ContainerStateExited,
  3096. ExitCode: 1,
  3097. },
  3098. {
  3099. Name: "with-reason",
  3100. State: kubecontainer.ContainerStateExited,
  3101. ExitCode: 2,
  3102. },
  3103. {
  3104. Name: "without-reason",
  3105. State: kubecontainer.ContainerStateExited,
  3106. ExitCode: 3,
  3107. },
  3108. {
  3109. Name: "with-reason",
  3110. State: kubecontainer.ContainerStateExited,
  3111. ExitCode: 4,
  3112. },
  3113. {
  3114. Name: "succeed",
  3115. State: kubecontainer.ContainerStateExited,
  3116. ExitCode: 0,
  3117. },
  3118. {
  3119. Name: "succeed",
  3120. State: kubecontainer.ContainerStateExited,
  3121. ExitCode: 5,
  3122. },
  3123. },
  3124. reasons: map[string]error{"with-reason": testErrorReason, "succeed": testErrorReason},
  3125. oldStatuses: []api.ContainerStatus{},
  3126. expectedState: map[string]api.ContainerState{
  3127. "without-reason": {Terminated: &api.ContainerStateTerminated{
  3128. ExitCode: 1,
  3129. ContainerID: emptyContainerID,
  3130. }},
  3131. "with-reason": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}},
  3132. "succeed": {Terminated: &api.ContainerStateTerminated{
  3133. ExitCode: 0,
  3134. ContainerID: emptyContainerID,
  3135. }},
  3136. },
  3137. expectedLastTerminationState: map[string]api.ContainerState{
  3138. "without-reason": {Terminated: &api.ContainerStateTerminated{
  3139. ExitCode: 3,
  3140. ContainerID: emptyContainerID,
  3141. }},
  3142. "with-reason": {Terminated: &api.ContainerStateTerminated{
  3143. ExitCode: 2,
  3144. ContainerID: emptyContainerID,
  3145. }},
  3146. "succeed": {Terminated: &api.ContainerStateTerminated{
  3147. ExitCode: 5,
  3148. ContainerID: emptyContainerID,
  3149. }},
  3150. },
  3151. },
  3152. }
  3153. for i, test := range tests {
  3154. kubelet.reasonCache = NewReasonCache()
  3155. for n, e := range test.reasons {
  3156. kubelet.reasonCache.add(pod.UID, n, e, "")
  3157. }
  3158. pod.Spec.Containers = test.containers
  3159. pod.Status.ContainerStatuses = test.oldStatuses
  3160. podStatus.ContainerStatuses = test.statuses
  3161. apiStatus := kubelet.generateAPIPodStatus(pod, podStatus)
  3162. assert.NoError(t, verifyContainerStatuses(apiStatus.ContainerStatuses, test.expectedState, test.expectedLastTerminationState), "case %d", i)
  3163. }
  3164. // Everything should be the same for init containers
  3165. for i, test := range tests {
  3166. kubelet.reasonCache = NewReasonCache()
  3167. for n, e := range test.reasons {
  3168. kubelet.reasonCache.add(pod.UID, n, e, "")
  3169. }
  3170. pod.Spec.InitContainers = test.containers
  3171. pod.Status.InitContainerStatuses = test.oldStatuses
  3172. podStatus.ContainerStatuses = test.statuses
  3173. apiStatus := kubelet.generateAPIPodStatus(pod, podStatus)
  3174. expectedState := test.expectedState
  3175. if test.expectedInitState != nil {
  3176. expectedState = test.expectedInitState
  3177. }
  3178. assert.NoError(t, verifyContainerStatuses(apiStatus.InitContainerStatuses, expectedState, test.expectedLastTerminationState), "case %d", i)
  3179. }
  3180. }
  3181. // Test generateAPIPodStatus with different restart policies.
  3182. func TestGenerateAPIPodStatusWithDifferentRestartPolicies(t *testing.T) {
  3183. testErrorReason := fmt.Errorf("test-error")
  3184. emptyContainerID := (&kubecontainer.ContainerID{}).String()
  3185. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  3186. testKubelet.fakeCadvisor.On("VersionInfo").Return(&cadvisorapi.VersionInfo{}, nil)
  3187. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  3188. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  3189. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  3190. kubelet := testKubelet.kubelet
  3191. pod := podWithUidNameNs("12345678", "foo", "new")
  3192. containers := []api.Container{{Name: "succeed"}, {Name: "failed"}}
  3193. podStatus := &kubecontainer.PodStatus{
  3194. ID: pod.UID,
  3195. Name: pod.Name,
  3196. Namespace: pod.Namespace,
  3197. ContainerStatuses: []*kubecontainer.ContainerStatus{
  3198. {
  3199. Name: "succeed",
  3200. State: kubecontainer.ContainerStateExited,
  3201. ExitCode: 0,
  3202. },
  3203. {
  3204. Name: "failed",
  3205. State: kubecontainer.ContainerStateExited,
  3206. ExitCode: 1,
  3207. },
  3208. {
  3209. Name: "succeed",
  3210. State: kubecontainer.ContainerStateExited,
  3211. ExitCode: 2,
  3212. },
  3213. {
  3214. Name: "failed",
  3215. State: kubecontainer.ContainerStateExited,
  3216. ExitCode: 3,
  3217. },
  3218. },
  3219. }
  3220. kubelet.reasonCache.add(pod.UID, "succeed", testErrorReason, "")
  3221. kubelet.reasonCache.add(pod.UID, "failed", testErrorReason, "")
  3222. for c, test := range []struct {
  3223. restartPolicy api.RestartPolicy
  3224. expectedState map[string]api.ContainerState
  3225. expectedLastTerminationState map[string]api.ContainerState
  3226. // Only set expectedInitState when it is different from expectedState
  3227. expectedInitState map[string]api.ContainerState
  3228. // Only set expectedInitLastTerminationState when it is different from expectedLastTerminationState
  3229. expectedInitLastTerminationState map[string]api.ContainerState
  3230. }{
  3231. {
  3232. restartPolicy: api.RestartPolicyNever,
  3233. expectedState: map[string]api.ContainerState{
  3234. "succeed": {Terminated: &api.ContainerStateTerminated{
  3235. ExitCode: 0,
  3236. ContainerID: emptyContainerID,
  3237. }},
  3238. "failed": {Terminated: &api.ContainerStateTerminated{
  3239. ExitCode: 1,
  3240. ContainerID: emptyContainerID,
  3241. }},
  3242. },
  3243. expectedLastTerminationState: map[string]api.ContainerState{
  3244. "succeed": {Terminated: &api.ContainerStateTerminated{
  3245. ExitCode: 2,
  3246. ContainerID: emptyContainerID,
  3247. }},
  3248. "failed": {Terminated: &api.ContainerStateTerminated{
  3249. ExitCode: 3,
  3250. ContainerID: emptyContainerID,
  3251. }},
  3252. },
  3253. },
  3254. {
  3255. restartPolicy: api.RestartPolicyOnFailure,
  3256. expectedState: map[string]api.ContainerState{
  3257. "succeed": {Terminated: &api.ContainerStateTerminated{
  3258. ExitCode: 0,
  3259. ContainerID: emptyContainerID,
  3260. }},
  3261. "failed": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}},
  3262. },
  3263. expectedLastTerminationState: map[string]api.ContainerState{
  3264. "succeed": {Terminated: &api.ContainerStateTerminated{
  3265. ExitCode: 2,
  3266. ContainerID: emptyContainerID,
  3267. }},
  3268. "failed": {Terminated: &api.ContainerStateTerminated{
  3269. ExitCode: 1,
  3270. ContainerID: emptyContainerID,
  3271. }},
  3272. },
  3273. },
  3274. {
  3275. restartPolicy: api.RestartPolicyAlways,
  3276. expectedState: map[string]api.ContainerState{
  3277. "succeed": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}},
  3278. "failed": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}},
  3279. },
  3280. expectedLastTerminationState: map[string]api.ContainerState{
  3281. "succeed": {Terminated: &api.ContainerStateTerminated{
  3282. ExitCode: 0,
  3283. ContainerID: emptyContainerID,
  3284. }},
  3285. "failed": {Terminated: &api.ContainerStateTerminated{
  3286. ExitCode: 1,
  3287. ContainerID: emptyContainerID,
  3288. }},
  3289. },
  3290. // If the init container is terminated with exit code 0, it won't be restarted even when the
  3291. // restart policy is RestartAlways.
  3292. expectedInitState: map[string]api.ContainerState{
  3293. "succeed": {Terminated: &api.ContainerStateTerminated{
  3294. ExitCode: 0,
  3295. ContainerID: emptyContainerID,
  3296. }},
  3297. "failed": {Waiting: &api.ContainerStateWaiting{Reason: testErrorReason.Error()}},
  3298. },
  3299. expectedInitLastTerminationState: map[string]api.ContainerState{
  3300. "succeed": {Terminated: &api.ContainerStateTerminated{
  3301. ExitCode: 2,
  3302. ContainerID: emptyContainerID,
  3303. }},
  3304. "failed": {Terminated: &api.ContainerStateTerminated{
  3305. ExitCode: 1,
  3306. ContainerID: emptyContainerID,
  3307. }},
  3308. },
  3309. },
  3310. } {
  3311. pod.Spec.RestartPolicy = test.restartPolicy
  3312. // Test normal containers
  3313. pod.Spec.Containers = containers
  3314. apiStatus := kubelet.generateAPIPodStatus(pod, podStatus)
  3315. expectedState, expectedLastTerminationState := test.expectedState, test.expectedLastTerminationState
  3316. assert.NoError(t, verifyContainerStatuses(apiStatus.ContainerStatuses, expectedState, expectedLastTerminationState), "case %d", c)
  3317. pod.Spec.Containers = nil
  3318. // Test init containers
  3319. pod.Spec.InitContainers = containers
  3320. apiStatus = kubelet.generateAPIPodStatus(pod, podStatus)
  3321. if test.expectedInitState != nil {
  3322. expectedState = test.expectedInitState
  3323. }
  3324. if test.expectedInitLastTerminationState != nil {
  3325. expectedLastTerminationState = test.expectedInitLastTerminationState
  3326. }
  3327. assert.NoError(t, verifyContainerStatuses(apiStatus.InitContainerStatuses, expectedState, expectedLastTerminationState), "case %d", c)
  3328. pod.Spec.InitContainers = nil
  3329. }
  3330. }
  3331. // testPodAdmitHandler is a lifecycle.PodAdmitHandler for testing.
  3332. type testPodAdmitHandler struct {
  3333. // list of pods to reject.
  3334. podsToReject []*api.Pod
  3335. }
  3336. // Admit rejects all pods in the podsToReject list with a matching UID.
  3337. func (a *testPodAdmitHandler) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAdmitResult {
  3338. for _, podToReject := range a.podsToReject {
  3339. if podToReject.UID == attrs.Pod.UID {
  3340. return lifecycle.PodAdmitResult{Admit: false, Reason: "Rejected", Message: "Pod is rejected"}
  3341. }
  3342. }
  3343. return lifecycle.PodAdmitResult{Admit: true}
  3344. }
  3345. // Test verifies that the kubelet invokes an admission handler during HandlePodAdditions.
  3346. func TestHandlePodAdditionsInvokesPodAdmitHandlers(t *testing.T) {
  3347. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  3348. kl := testKubelet.kubelet
  3349. kl.nodeLister = testNodeLister{nodes: []api.Node{
  3350. {
  3351. ObjectMeta: api.ObjectMeta{Name: kl.nodeName},
  3352. Status: api.NodeStatus{
  3353. Allocatable: api.ResourceList{
  3354. api.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  3355. },
  3356. },
  3357. },
  3358. }}
  3359. kl.nodeInfo = testNodeInfo{nodes: []api.Node{
  3360. {
  3361. ObjectMeta: api.ObjectMeta{Name: kl.nodeName},
  3362. Status: api.NodeStatus{
  3363. Allocatable: api.ResourceList{
  3364. api.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  3365. },
  3366. },
  3367. },
  3368. }}
  3369. testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorapi.MachineInfo{}, nil)
  3370. testKubelet.fakeCadvisor.On("ImagesFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  3371. testKubelet.fakeCadvisor.On("RootFsInfo").Return(cadvisorapiv2.FsInfo{}, nil)
  3372. pods := []*api.Pod{
  3373. {
  3374. ObjectMeta: api.ObjectMeta{
  3375. UID: "123456789",
  3376. Name: "podA",
  3377. Namespace: "foo",
  3378. },
  3379. },
  3380. {
  3381. ObjectMeta: api.ObjectMeta{
  3382. UID: "987654321",
  3383. Name: "podB",
  3384. Namespace: "foo",
  3385. },
  3386. },
  3387. }
  3388. podToReject := pods[0]
  3389. podToAdmit := pods[1]
  3390. podsToReject := []*api.Pod{podToReject}
  3391. kl.AddPodAdmitHandler(&testPodAdmitHandler{podsToReject: podsToReject})
  3392. kl.HandlePodAdditions(pods)
  3393. // Check pod status stored in the status map.
  3394. // podToReject should be Failed
  3395. status, found := kl.statusManager.GetPodStatus(podToReject.UID)
  3396. if !found {
  3397. t.Fatalf("status of pod %q is not found in the status map", podToReject.UID)
  3398. }
  3399. if status.Phase != api.PodFailed {
  3400. t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
  3401. }
  3402. // podToAdmit should be Pending
  3403. status, found = kl.statusManager.GetPodStatus(podToAdmit.UID)
  3404. if !found {
  3405. t.Fatalf("status of pod %q is not found in the status map", podToAdmit.UID)
  3406. }
  3407. if status.Phase != api.PodPending {
  3408. t.Fatalf("expected pod status %q. Got %q.", api.PodPending, status.Phase)
  3409. }
  3410. }
  3411. // testPodSyncLoopHandler is a lifecycle.PodSyncLoopHandler that is used for testing.
  3412. type testPodSyncLoopHandler struct {
  3413. // list of pods to sync
  3414. podsToSync []*api.Pod
  3415. }
  3416. // ShouldSync evaluates if the pod should be synced from the kubelet.
  3417. func (a *testPodSyncLoopHandler) ShouldSync(pod *api.Pod) bool {
  3418. for _, podToSync := range a.podsToSync {
  3419. if podToSync.UID == pod.UID {
  3420. return true
  3421. }
  3422. }
  3423. return false
  3424. }
  3425. // TestGetPodsToSyncInvokesPodSyncLoopHandlers ensures that the get pods to sync routine invokes the handler.
  3426. func TestGetPodsToSyncInvokesPodSyncLoopHandlers(t *testing.T) {
  3427. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  3428. kubelet := testKubelet.kubelet
  3429. pods := newTestPods(5)
  3430. podUIDs := []types.UID{}
  3431. for _, pod := range pods {
  3432. podUIDs = append(podUIDs, pod.UID)
  3433. }
  3434. podsToSync := []*api.Pod{pods[0]}
  3435. kubelet.AddPodSyncLoopHandler(&testPodSyncLoopHandler{podsToSync})
  3436. kubelet.podManager.SetPods(pods)
  3437. expectedPodsUID := []types.UID{pods[0].UID}
  3438. podsToSync = kubelet.getPodsToSync()
  3439. if len(podsToSync) == len(expectedPodsUID) {
  3440. var rightNum int
  3441. for _, podUID := range expectedPodsUID {
  3442. for _, podToSync := range podsToSync {
  3443. if podToSync.UID == podUID {
  3444. rightNum++
  3445. break
  3446. }
  3447. }
  3448. }
  3449. if rightNum != len(expectedPodsUID) {
  3450. // Just for report error
  3451. podsToSyncUID := []types.UID{}
  3452. for _, podToSync := range podsToSync {
  3453. podsToSyncUID = append(podsToSyncUID, podToSync.UID)
  3454. }
  3455. t.Errorf("expected pods %v to sync, got %v", expectedPodsUID, podsToSyncUID)
  3456. }
  3457. } else {
  3458. t.Errorf("expected %d pods to sync, got %d", 3, len(podsToSync))
  3459. }
  3460. }
  3461. // testPodSyncHandler is a lifecycle.PodSyncHandler that is used for testing.
  3462. type testPodSyncHandler struct {
  3463. // list of pods to evict.
  3464. podsToEvict []*api.Pod
  3465. // the reason for the eviction
  3466. reason string
  3467. // the message for the eviction
  3468. message string
  3469. }
  3470. // ShouldEvict evaluates if the pod should be evicted from the kubelet.
  3471. func (a *testPodSyncHandler) ShouldEvict(pod *api.Pod) lifecycle.ShouldEvictResponse {
  3472. for _, podToEvict := range a.podsToEvict {
  3473. if podToEvict.UID == pod.UID {
  3474. return lifecycle.ShouldEvictResponse{Evict: true, Reason: a.reason, Message: a.message}
  3475. }
  3476. }
  3477. return lifecycle.ShouldEvictResponse{Evict: false}
  3478. }
  3479. // TestGenerateAPIPodStatusInvokesPodSyncHandlers invokes the handlers and reports the proper status
  3480. func TestGenerateAPIPodStatusInvokesPodSyncHandlers(t *testing.T) {
  3481. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  3482. kubelet := testKubelet.kubelet
  3483. pod := newTestPods(1)[0]
  3484. podsToEvict := []*api.Pod{pod}
  3485. kubelet.AddPodSyncHandler(&testPodSyncHandler{podsToEvict, "Evicted", "because"})
  3486. status := &kubecontainer.PodStatus{
  3487. ID: pod.UID,
  3488. Name: pod.Name,
  3489. Namespace: pod.Namespace,
  3490. }
  3491. apiStatus := kubelet.generateAPIPodStatus(pod, status)
  3492. if apiStatus.Phase != api.PodFailed {
  3493. t.Fatalf("Expected phase %v, but got %v", api.PodFailed, apiStatus.Phase)
  3494. }
  3495. if apiStatus.Reason != "Evicted" {
  3496. t.Fatalf("Expected reason %v, but got %v", "Evicted", apiStatus.Reason)
  3497. }
  3498. if apiStatus.Message != "because" {
  3499. t.Fatalf("Expected message %v, but got %v", "because", apiStatus.Message)
  3500. }
  3501. }
  3502. func TestSyncPodKillPod(t *testing.T) {
  3503. testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
  3504. kl := testKubelet.kubelet
  3505. pod := &api.Pod{
  3506. ObjectMeta: api.ObjectMeta{
  3507. UID: "12345678",
  3508. Name: "bar",
  3509. Namespace: "foo",
  3510. },
  3511. }
  3512. pods := []*api.Pod{pod}
  3513. kl.podManager.SetPods(pods)
  3514. gracePeriodOverride := int64(0)
  3515. err := kl.syncPod(syncPodOptions{
  3516. pod: pod,
  3517. podStatus: &kubecontainer.PodStatus{},
  3518. updateType: kubetypes.SyncPodKill,
  3519. killPodOptions: &KillPodOptions{
  3520. PodStatusFunc: func(p *api.Pod, podStatus *kubecontainer.PodStatus) api.PodStatus {
  3521. return api.PodStatus{
  3522. Phase: api.PodFailed,
  3523. Reason: "reason",
  3524. Message: "message",
  3525. }
  3526. },
  3527. PodTerminationGracePeriodSecondsOverride: &gracePeriodOverride,
  3528. },
  3529. })
  3530. if err != nil {
  3531. t.Errorf("unexpected error: %v", err)
  3532. }
  3533. // Check pod status stored in the status map.
  3534. status, found := kl.statusManager.GetPodStatus(pod.UID)
  3535. if !found {
  3536. t.Fatalf("status of pod %q is not found in the status map", pod.UID)
  3537. }
  3538. if status.Phase != api.PodFailed {
  3539. t.Fatalf("expected pod status %q. Got %q.", api.PodFailed, status.Phase)
  3540. }
  3541. }
  3542. func waitForVolumeUnmount(
  3543. volumeManager kubeletvolume.VolumeManager,
  3544. pod *api.Pod) error {
  3545. var podVolumes kubecontainer.VolumeMap
  3546. err := retryWithExponentialBackOff(
  3547. time.Duration(50*time.Millisecond),
  3548. func() (bool, error) {
  3549. // Verify volumes detached
  3550. podVolumes = volumeManager.GetMountedVolumesForPod(
  3551. volumehelper.GetUniquePodName(pod))
  3552. if len(podVolumes) != 0 {
  3553. return false, nil
  3554. }
  3555. return true, nil
  3556. },
  3557. )
  3558. if err != nil {
  3559. return fmt.Errorf(
  3560. "Expected volumes to be unmounted. But some volumes are still mounted: %#v", podVolumes)
  3561. }
  3562. return nil
  3563. }
  3564. func waitForVolumeDetach(
  3565. volumeName api.UniqueVolumeName,
  3566. volumeManager kubeletvolume.VolumeManager) error {
  3567. attachedVolumes := []api.UniqueVolumeName{}
  3568. err := retryWithExponentialBackOff(
  3569. time.Duration(50*time.Millisecond),
  3570. func() (bool, error) {
  3571. // Verify volumes detached
  3572. volumeAttached := volumeManager.VolumeIsAttached(volumeName)
  3573. return !volumeAttached, nil
  3574. },
  3575. )
  3576. if err != nil {
  3577. return fmt.Errorf(
  3578. "Expected volumes to be detached. But some volumes are still attached: %#v", attachedVolumes)
  3579. }
  3580. return nil
  3581. }
  3582. func retryWithExponentialBackOff(initialDuration time.Duration, fn wait.ConditionFunc) error {
  3583. backoff := wait.Backoff{
  3584. Duration: initialDuration,
  3585. Factor: 3,
  3586. Jitter: 0,
  3587. Steps: 6,
  3588. }
  3589. return wait.ExponentialBackoff(backoff, fn)
  3590. }
  3591. func simulateVolumeInUseUpdate(
  3592. volumeName api.UniqueVolumeName,
  3593. stopCh <-chan struct{},
  3594. volumeManager kubeletvolume.VolumeManager) {
  3595. ticker := time.NewTicker(100 * time.Millisecond)
  3596. defer ticker.Stop()
  3597. for {
  3598. select {
  3599. case <-ticker.C:
  3600. volumeManager.MarkVolumesAsReportedInUse(
  3601. []api.UniqueVolumeName{volumeName})
  3602. case <-stopCh:
  3603. return
  3604. }
  3605. }
  3606. }
  3607. func runVolumeManager(kubelet *Kubelet) chan struct{} {
  3608. stopCh := make(chan struct{})
  3609. go kubelet.volumeManager.Run(kubelet.sourcesReady, stopCh)
  3610. return stopCh
  3611. }