docker_manager_test.go 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570
  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 dockertools
  14. import (
  15. "fmt"
  16. "io/ioutil"
  17. "net"
  18. "net/http"
  19. "os"
  20. "path"
  21. "reflect"
  22. "regexp"
  23. goruntime "runtime"
  24. "sort"
  25. "strconv"
  26. "strings"
  27. "testing"
  28. "time"
  29. dockertypes "github.com/docker/engine-api/types"
  30. dockercontainer "github.com/docker/engine-api/types/container"
  31. dockerstrslice "github.com/docker/engine-api/types/strslice"
  32. "github.com/golang/mock/gomock"
  33. cadvisorapi "github.com/google/cadvisor/info/v1"
  34. "github.com/stretchr/testify/assert"
  35. "k8s.io/kubernetes/pkg/api"
  36. "k8s.io/kubernetes/pkg/api/testapi"
  37. "k8s.io/kubernetes/pkg/apis/componentconfig"
  38. "k8s.io/kubernetes/pkg/client/record"
  39. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  40. containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
  41. "k8s.io/kubernetes/pkg/kubelet/events"
  42. "k8s.io/kubernetes/pkg/kubelet/images"
  43. "k8s.io/kubernetes/pkg/kubelet/network"
  44. "k8s.io/kubernetes/pkg/kubelet/network/mock_network"
  45. nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
  46. proberesults "k8s.io/kubernetes/pkg/kubelet/prober/results"
  47. "k8s.io/kubernetes/pkg/kubelet/types"
  48. "k8s.io/kubernetes/pkg/runtime"
  49. "k8s.io/kubernetes/pkg/security/apparmor"
  50. kubetypes "k8s.io/kubernetes/pkg/types"
  51. "k8s.io/kubernetes/pkg/util/clock"
  52. uexec "k8s.io/kubernetes/pkg/util/exec"
  53. "k8s.io/kubernetes/pkg/util/flowcontrol"
  54. "k8s.io/kubernetes/pkg/util/intstr"
  55. "k8s.io/kubernetes/pkg/util/sets"
  56. utilstrings "k8s.io/kubernetes/pkg/util/strings"
  57. )
  58. type fakeHTTP struct {
  59. url string
  60. err error
  61. }
  62. func (f *fakeHTTP) Get(url string) (*http.Response, error) {
  63. f.url = url
  64. return nil, f.err
  65. }
  66. // fakeRuntimeHelper implementes kubecontainer.RuntimeHelper inter
  67. // faces for testing purposes.
  68. type fakeRuntimeHelper struct{}
  69. var _ kubecontainer.RuntimeHelper = &fakeRuntimeHelper{}
  70. var testPodContainerDir string
  71. func (f *fakeRuntimeHelper) GenerateRunContainerOptions(pod *api.Pod, container *api.Container, podIP string) (*kubecontainer.RunContainerOptions, error) {
  72. var opts kubecontainer.RunContainerOptions
  73. var err error
  74. if len(container.TerminationMessagePath) != 0 {
  75. testPodContainerDir, err = ioutil.TempDir("", "fooPodContainerDir")
  76. if err != nil {
  77. return nil, err
  78. }
  79. opts.PodContainerDir = testPodContainerDir
  80. }
  81. return &opts, nil
  82. }
  83. func (f *fakeRuntimeHelper) GetClusterDNS(pod *api.Pod) ([]string, []string, error) {
  84. return nil, nil, fmt.Errorf("not implemented")
  85. }
  86. // This is not used by docker runtime.
  87. func (f *fakeRuntimeHelper) GeneratePodHostNameAndDomain(pod *api.Pod) (string, string, error) {
  88. return "", "", nil
  89. }
  90. func (f *fakeRuntimeHelper) GetPodDir(kubetypes.UID) string {
  91. return ""
  92. }
  93. func (f *fakeRuntimeHelper) GetExtraSupplementalGroupsForPod(pod *api.Pod) []int64 {
  94. return nil
  95. }
  96. func createTestDockerManager(fakeHTTPClient *fakeHTTP, fakeDocker *FakeDockerClient) (*DockerManager, *FakeDockerClient) {
  97. if fakeHTTPClient == nil {
  98. fakeHTTPClient = &fakeHTTP{}
  99. }
  100. if fakeDocker == nil {
  101. fakeDocker = NewFakeDockerClient()
  102. }
  103. fakeRecorder := &record.FakeRecorder{}
  104. containerRefManager := kubecontainer.NewRefManager()
  105. networkPlugin, _ := network.InitNetworkPlugin(
  106. []network.NetworkPlugin{},
  107. "",
  108. nettest.NewFakeHost(nil),
  109. componentconfig.HairpinNone,
  110. "10.0.0.0/8",
  111. network.UseDefaultMTU)
  112. dockerManager := NewFakeDockerManager(
  113. fakeDocker,
  114. fakeRecorder,
  115. proberesults.NewManager(),
  116. containerRefManager,
  117. &cadvisorapi.MachineInfo{},
  118. "",
  119. 0, 0, "",
  120. &containertest.FakeOS{},
  121. networkPlugin,
  122. &fakeRuntimeHelper{},
  123. fakeHTTPClient,
  124. flowcontrol.NewBackOff(time.Second, 300*time.Second))
  125. return dockerManager, fakeDocker
  126. }
  127. func newTestDockerManagerWithHTTPClient(fakeHTTPClient *fakeHTTP) (*DockerManager, *FakeDockerClient) {
  128. return createTestDockerManager(fakeHTTPClient, nil)
  129. }
  130. func newTestDockerManagerWithVersion(version, apiVersion string) (*DockerManager, *FakeDockerClient) {
  131. fakeDocker := NewFakeDockerClientWithVersion(version, apiVersion)
  132. return createTestDockerManager(nil, fakeDocker)
  133. }
  134. func newTestDockerManager() (*DockerManager, *FakeDockerClient) {
  135. return createTestDockerManager(nil, nil)
  136. }
  137. func matchString(t *testing.T, pattern, str string) bool {
  138. match, err := regexp.MatchString(pattern, str)
  139. if err != nil {
  140. t.Logf("unexpected error: %v", err)
  141. }
  142. return match
  143. }
  144. func TestSetEntrypointAndCommand(t *testing.T) {
  145. cases := []struct {
  146. name string
  147. container *api.Container
  148. envs []kubecontainer.EnvVar
  149. expected *dockertypes.ContainerCreateConfig
  150. }{
  151. {
  152. name: "none",
  153. container: &api.Container{},
  154. expected: &dockertypes.ContainerCreateConfig{
  155. Config: &dockercontainer.Config{},
  156. },
  157. },
  158. {
  159. name: "command",
  160. container: &api.Container{
  161. Command: []string{"foo", "bar"},
  162. },
  163. expected: &dockertypes.ContainerCreateConfig{
  164. Config: &dockercontainer.Config{
  165. Entrypoint: dockerstrslice.StrSlice([]string{"foo", "bar"}),
  166. },
  167. },
  168. },
  169. {
  170. name: "command expanded",
  171. container: &api.Container{
  172. Command: []string{"foo", "$(VAR_TEST)", "$(VAR_TEST2)"},
  173. },
  174. envs: []kubecontainer.EnvVar{
  175. {
  176. Name: "VAR_TEST",
  177. Value: "zoo",
  178. },
  179. {
  180. Name: "VAR_TEST2",
  181. Value: "boo",
  182. },
  183. },
  184. expected: &dockertypes.ContainerCreateConfig{
  185. Config: &dockercontainer.Config{
  186. Entrypoint: dockerstrslice.StrSlice([]string{"foo", "zoo", "boo"}),
  187. },
  188. },
  189. },
  190. {
  191. name: "args",
  192. container: &api.Container{
  193. Args: []string{"foo", "bar"},
  194. },
  195. expected: &dockertypes.ContainerCreateConfig{
  196. Config: &dockercontainer.Config{
  197. Cmd: []string{"foo", "bar"},
  198. },
  199. },
  200. },
  201. {
  202. name: "args expanded",
  203. container: &api.Container{
  204. Args: []string{"zap", "$(VAR_TEST)", "$(VAR_TEST2)"},
  205. },
  206. envs: []kubecontainer.EnvVar{
  207. {
  208. Name: "VAR_TEST",
  209. Value: "hap",
  210. },
  211. {
  212. Name: "VAR_TEST2",
  213. Value: "trap",
  214. },
  215. },
  216. expected: &dockertypes.ContainerCreateConfig{
  217. Config: &dockercontainer.Config{
  218. Cmd: dockerstrslice.StrSlice([]string{"zap", "hap", "trap"}),
  219. },
  220. },
  221. },
  222. {
  223. name: "both",
  224. container: &api.Container{
  225. Command: []string{"foo"},
  226. Args: []string{"bar", "baz"},
  227. },
  228. expected: &dockertypes.ContainerCreateConfig{
  229. Config: &dockercontainer.Config{
  230. Entrypoint: dockerstrslice.StrSlice([]string{"foo"}),
  231. Cmd: dockerstrslice.StrSlice([]string{"bar", "baz"}),
  232. },
  233. },
  234. },
  235. {
  236. name: "both expanded",
  237. container: &api.Container{
  238. Command: []string{"$(VAR_TEST2)--$(VAR_TEST)", "foo", "$(VAR_TEST3)"},
  239. Args: []string{"foo", "$(VAR_TEST)", "$(VAR_TEST2)"},
  240. },
  241. envs: []kubecontainer.EnvVar{
  242. {
  243. Name: "VAR_TEST",
  244. Value: "zoo",
  245. },
  246. {
  247. Name: "VAR_TEST2",
  248. Value: "boo",
  249. },
  250. {
  251. Name: "VAR_TEST3",
  252. Value: "roo",
  253. },
  254. },
  255. expected: &dockertypes.ContainerCreateConfig{
  256. Config: &dockercontainer.Config{
  257. Entrypoint: dockerstrslice.StrSlice([]string{"boo--zoo", "foo", "roo"}),
  258. Cmd: dockerstrslice.StrSlice([]string{"foo", "zoo", "boo"}),
  259. },
  260. },
  261. },
  262. }
  263. for _, tc := range cases {
  264. opts := &kubecontainer.RunContainerOptions{
  265. Envs: tc.envs,
  266. }
  267. actualOpts := dockertypes.ContainerCreateConfig{
  268. Config: &dockercontainer.Config{},
  269. }
  270. setEntrypointAndCommand(tc.container, opts, actualOpts)
  271. if e, a := tc.expected.Config.Entrypoint, actualOpts.Config.Entrypoint; !api.Semantic.DeepEqual(e, a) {
  272. t.Errorf("%v: unexpected entrypoint: expected %v, got %v", tc.name, e, a)
  273. }
  274. if e, a := tc.expected.Config.Cmd, actualOpts.Config.Cmd; !api.Semantic.DeepEqual(e, a) {
  275. t.Errorf("%v: unexpected command: expected %v, got %v", tc.name, e, a)
  276. }
  277. }
  278. }
  279. // verifyPods returns true if the two pod slices are equal.
  280. func verifyPods(a, b []*kubecontainer.Pod) bool {
  281. if len(a) != len(b) {
  282. return false
  283. }
  284. // Sort the containers within a pod.
  285. for i := range a {
  286. sort.Sort(containersByID(a[i].Containers))
  287. }
  288. for i := range b {
  289. sort.Sort(containersByID(b[i].Containers))
  290. }
  291. // Sort the pods by UID.
  292. sort.Sort(podsByID(a))
  293. sort.Sort(podsByID(b))
  294. return reflect.DeepEqual(a, b)
  295. }
  296. func TestGetPods(t *testing.T) {
  297. manager, fakeDocker := newTestDockerManager()
  298. dockerContainers := []*FakeContainer{
  299. {
  300. ID: "1111",
  301. Name: "/k8s_foo_qux_new_1234_42",
  302. },
  303. {
  304. ID: "2222",
  305. Name: "/k8s_bar_qux_new_1234_42",
  306. },
  307. {
  308. ID: "3333",
  309. Name: "/k8s_bar_jlk_wen_5678_42",
  310. },
  311. }
  312. // Convert the docker containers. This does not affect the test coverage
  313. // because the conversion is tested separately in convert_test.go
  314. containers := make([]*kubecontainer.Container, len(dockerContainers))
  315. for i := range containers {
  316. c, err := toRuntimeContainer(&dockertypes.Container{
  317. ID: dockerContainers[i].ID,
  318. Names: []string{dockerContainers[i].Name},
  319. })
  320. if err != nil {
  321. t.Fatalf("unexpected error %v", err)
  322. }
  323. containers[i] = c
  324. }
  325. expected := []*kubecontainer.Pod{
  326. {
  327. ID: kubetypes.UID("1234"),
  328. Name: "qux",
  329. Namespace: "new",
  330. Containers: []*kubecontainer.Container{containers[0], containers[1]},
  331. },
  332. {
  333. ID: kubetypes.UID("5678"),
  334. Name: "jlk",
  335. Namespace: "wen",
  336. Containers: []*kubecontainer.Container{containers[2]},
  337. },
  338. }
  339. fakeDocker.SetFakeRunningContainers(dockerContainers)
  340. actual, err := manager.GetPods(false)
  341. if err != nil {
  342. t.Fatalf("unexpected error %v", err)
  343. }
  344. if !verifyPods(expected, actual) {
  345. t.Errorf("expected %#v, got %#v", expected, actual)
  346. }
  347. }
  348. func TestListImages(t *testing.T) {
  349. manager, fakeDocker := newTestDockerManager()
  350. dockerImages := []dockertypes.Image{{ID: "1111"}, {ID: "2222"}, {ID: "3333"}}
  351. expected := sets.NewString([]string{"1111", "2222", "3333"}...)
  352. fakeDocker.Images = dockerImages
  353. actualImages, err := manager.ListImages()
  354. if err != nil {
  355. t.Fatalf("unexpected error %v", err)
  356. }
  357. actual := sets.NewString()
  358. for _, i := range actualImages {
  359. actual.Insert(i.ID)
  360. }
  361. // We can compare the two sets directly because util.StringSet.List()
  362. // returns a "sorted" list.
  363. if !reflect.DeepEqual(expected.List(), actual.List()) {
  364. t.Errorf("expected %#v, got %#v", expected.List(), actual.List())
  365. }
  366. }
  367. func TestDeleteImage(t *testing.T) {
  368. manager, fakeDocker := newTestDockerManager()
  369. fakeDocker.Image = &dockertypes.ImageInspect{ID: "1111", RepoTags: []string{"foo"}}
  370. manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
  371. fakeDocker.AssertCallDetails([]calledDetail{{name: "inspect_image"}, {name: "remove_image",
  372. arguments: []interface{}{"1111", dockertypes.ImageRemoveOptions{PruneChildren: true}}}})
  373. }
  374. func TestDeleteImageWithMultipleTags(t *testing.T) {
  375. manager, fakeDocker := newTestDockerManager()
  376. fakeDocker.Image = &dockertypes.ImageInspect{ID: "1111", RepoTags: []string{"foo", "bar"}}
  377. manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
  378. fakeDocker.AssertCallDetails([]calledDetail{{name: "inspect_image"},
  379. {name: "remove_image", arguments: []interface{}{"foo", dockertypes.ImageRemoveOptions{PruneChildren: true}}},
  380. {name: "remove_image", arguments: []interface{}{"bar", dockertypes.ImageRemoveOptions{PruneChildren: true}}}})
  381. }
  382. func TestKillContainerInPod(t *testing.T) {
  383. manager, fakeDocker := newTestDockerManager()
  384. pod := &api.Pod{
  385. ObjectMeta: api.ObjectMeta{
  386. UID: "12345678",
  387. Name: "qux",
  388. Namespace: "new",
  389. },
  390. Spec: api.PodSpec{Containers: []api.Container{{Name: "foo"}, {Name: "bar"}}},
  391. }
  392. containers := []*FakeContainer{
  393. {
  394. ID: "1111",
  395. Name: "/k8s_foo_qux_new_1234_42",
  396. },
  397. {
  398. ID: "2222",
  399. Name: "/k8s_bar_qux_new_1234_42",
  400. },
  401. }
  402. containerToKill := containers[0]
  403. containerToSpare := containers[1]
  404. fakeDocker.SetFakeRunningContainers(containers)
  405. if err := manager.KillContainerInPod(kubecontainer.ContainerID{}, &pod.Spec.Containers[0], pod, "test kill container in pod.", nil); err != nil {
  406. t.Errorf("unexpected error: %v", err)
  407. }
  408. // Assert the container has been stopped.
  409. if err := fakeDocker.AssertStopped([]string{containerToKill.ID}); err != nil {
  410. t.Errorf("container was not stopped correctly: %v", err)
  411. }
  412. // Assert the container has been spared.
  413. if err := fakeDocker.AssertStopped([]string{containerToSpare.ID}); err == nil {
  414. t.Errorf("container unexpectedly stopped: %v", containerToSpare.ID)
  415. }
  416. }
  417. func TestKillContainerInPodWithPreStop(t *testing.T) {
  418. manager, fakeDocker := newTestDockerManager()
  419. fakeDocker.ExecInspect = &dockertypes.ContainerExecInspect{
  420. Running: false,
  421. ExitCode: 0,
  422. }
  423. expectedCmd := []string{"foo.sh", "bar"}
  424. pod := &api.Pod{
  425. ObjectMeta: api.ObjectMeta{
  426. UID: "12345678",
  427. Name: "qux",
  428. Namespace: "new",
  429. },
  430. Spec: api.PodSpec{
  431. Containers: []api.Container{
  432. {
  433. Name: "foo",
  434. Lifecycle: &api.Lifecycle{
  435. PreStop: &api.Handler{
  436. Exec: &api.ExecAction{
  437. Command: expectedCmd,
  438. },
  439. },
  440. },
  441. },
  442. {Name: "bar"}}},
  443. }
  444. podString, err := runtime.Encode(testapi.Default.Codec(), pod)
  445. if err != nil {
  446. t.Errorf("unexpected error: %v", err)
  447. }
  448. containers := []*FakeContainer{
  449. {
  450. ID: "1111",
  451. Name: "/k8s_foo_qux_new_1234_42",
  452. Config: &dockercontainer.Config{
  453. Labels: map[string]string{
  454. kubernetesPodLabel: string(podString),
  455. types.KubernetesContainerNameLabel: "foo",
  456. },
  457. },
  458. },
  459. {
  460. ID: "2222",
  461. Name: "/k8s_bar_qux_new_1234_42",
  462. },
  463. }
  464. containerToKill := containers[0]
  465. fakeDocker.SetFakeRunningContainers(containers)
  466. if err := manager.KillContainerInPod(kubecontainer.ContainerID{}, &pod.Spec.Containers[0], pod, "test kill container with preStop.", nil); err != nil {
  467. t.Errorf("unexpected error: %v", err)
  468. }
  469. // Assert the container has been stopped.
  470. if err := fakeDocker.AssertStopped([]string{containerToKill.ID}); err != nil {
  471. t.Errorf("container was not stopped correctly: %v", err)
  472. }
  473. verifyCalls(t, fakeDocker, []string{"list", "inspect_container", "create_exec", "start_exec", "stop"})
  474. if !reflect.DeepEqual(expectedCmd, fakeDocker.execCmd) {
  475. t.Errorf("expected: %v, got %v", expectedCmd, fakeDocker.execCmd)
  476. }
  477. }
  478. func TestKillContainerInPodWithError(t *testing.T) {
  479. manager, fakeDocker := newTestDockerManager()
  480. pod := &api.Pod{
  481. ObjectMeta: api.ObjectMeta{
  482. UID: "12345678",
  483. Name: "qux",
  484. Namespace: "new",
  485. },
  486. Spec: api.PodSpec{Containers: []api.Container{{Name: "foo"}, {Name: "bar"}}},
  487. }
  488. containers := []*FakeContainer{
  489. {
  490. ID: "1111",
  491. Name: "/k8s_foo_qux_new_1234_42",
  492. },
  493. {
  494. ID: "2222",
  495. Name: "/k8s_bar_qux_new_1234_42",
  496. },
  497. }
  498. fakeDocker.SetFakeRunningContainers(containers)
  499. fakeDocker.InjectError("stop", fmt.Errorf("sample error"))
  500. if err := manager.KillContainerInPod(kubecontainer.ContainerID{}, &pod.Spec.Containers[0], pod, "test kill container with error.", nil); err == nil {
  501. t.Errorf("expected error, found nil")
  502. }
  503. }
  504. func TestIsAExitError(t *testing.T) {
  505. var err error
  506. err = &dockerExitError{nil}
  507. _, ok := err.(uexec.ExitError)
  508. if !ok {
  509. t.Error("couldn't cast dockerExitError to exec.ExitError")
  510. }
  511. }
  512. func generatePodInfraContainerHash(pod *api.Pod) uint64 {
  513. var ports []api.ContainerPort
  514. if pod.Spec.SecurityContext == nil || !pod.Spec.SecurityContext.HostNetwork {
  515. for _, container := range pod.Spec.Containers {
  516. ports = append(ports, container.Ports...)
  517. }
  518. }
  519. container := &api.Container{
  520. Name: PodInfraContainerName,
  521. Image: "",
  522. Ports: ports,
  523. ImagePullPolicy: podInfraContainerImagePullPolicy,
  524. }
  525. return kubecontainer.HashContainer(container)
  526. }
  527. // runSyncPod is a helper function to retrieve the running pods from the fake
  528. // docker client and runs SyncPod for the given pod.
  529. func runSyncPod(t *testing.T, dm *DockerManager, fakeDocker *FakeDockerClient, pod *api.Pod, backOff *flowcontrol.Backoff, expectErr bool) kubecontainer.PodSyncResult {
  530. podStatus, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
  531. if err != nil {
  532. t.Errorf("unexpected error: %v", err)
  533. }
  534. fakeDocker.ClearCalls()
  535. if backOff == nil {
  536. backOff = flowcontrol.NewBackOff(time.Second, time.Minute)
  537. }
  538. // api.PodStatus is not used in SyncPod now, pass in an empty one.
  539. result := dm.SyncPod(pod, api.PodStatus{}, podStatus, []api.Secret{}, backOff)
  540. err = result.Error()
  541. if err != nil && !expectErr {
  542. t.Errorf("unexpected error: %v", err)
  543. } else if err == nil && expectErr {
  544. t.Errorf("expected error didn't occur")
  545. }
  546. return result
  547. }
  548. func TestSyncPodCreateNetAndContainer(t *testing.T) {
  549. dm, fakeDocker := newTestDockerManager()
  550. dm.podInfraContainerImage = "pod_infra_image"
  551. pod := &api.Pod{
  552. ObjectMeta: api.ObjectMeta{
  553. UID: "12345678",
  554. Name: "foo",
  555. Namespace: "new",
  556. },
  557. Spec: api.PodSpec{
  558. Containers: []api.Container{
  559. {Name: "bar"},
  560. },
  561. },
  562. }
  563. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  564. verifyCalls(t, fakeDocker, []string{
  565. // Create pod infra container.
  566. "create", "start", "inspect_container", "inspect_container",
  567. // Create container.
  568. "create", "start", "inspect_container",
  569. })
  570. fakeDocker.Lock()
  571. found := false
  572. for _, c := range fakeDocker.RunningContainerList {
  573. if c.Image == "pod_infra_image" && strings.HasPrefix(c.Names[0], "/k8s_POD") {
  574. found = true
  575. break
  576. }
  577. }
  578. if !found {
  579. t.Errorf("Custom pod infra container not found: %v", fakeDocker.RunningContainerList)
  580. }
  581. if len(fakeDocker.Created) != 2 ||
  582. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
  583. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
  584. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  585. }
  586. fakeDocker.Unlock()
  587. }
  588. func TestSyncPodCreatesNetAndContainerPullsImage(t *testing.T) {
  589. dm, fakeDocker := newTestDockerManager()
  590. dm.podInfraContainerImage = "pod_infra_image"
  591. puller := dm.dockerPuller.(*FakeDockerPuller)
  592. puller.HasImages = []string{}
  593. dm.podInfraContainerImage = "pod_infra_image"
  594. pod := &api.Pod{
  595. ObjectMeta: api.ObjectMeta{
  596. UID: "12345678",
  597. Name: "foo",
  598. Namespace: "new",
  599. },
  600. Spec: api.PodSpec{
  601. Containers: []api.Container{
  602. {Name: "bar", Image: "something", ImagePullPolicy: "IfNotPresent"},
  603. },
  604. },
  605. }
  606. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  607. verifyCalls(t, fakeDocker, []string{
  608. // Create pod infra container.
  609. "create", "start", "inspect_container", "inspect_container",
  610. // Create container.
  611. "create", "start", "inspect_container",
  612. })
  613. fakeDocker.Lock()
  614. if !reflect.DeepEqual(puller.ImagesPulled, []string{"pod_infra_image", "something"}) {
  615. t.Errorf("unexpected pulled containers: %v", puller.ImagesPulled)
  616. }
  617. if len(fakeDocker.Created) != 2 ||
  618. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
  619. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
  620. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  621. }
  622. fakeDocker.Unlock()
  623. }
  624. func TestSyncPodWithPodInfraCreatesContainer(t *testing.T) {
  625. dm, fakeDocker := newTestDockerManager()
  626. pod := &api.Pod{
  627. ObjectMeta: api.ObjectMeta{
  628. UID: "12345678",
  629. Name: "foo",
  630. Namespace: "new",
  631. },
  632. Spec: api.PodSpec{
  633. Containers: []api.Container{
  634. {Name: "bar"},
  635. },
  636. },
  637. }
  638. fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
  639. ID: "9876",
  640. // Pod infra container.
  641. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
  642. }})
  643. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  644. verifyCalls(t, fakeDocker, []string{
  645. // Create container.
  646. "create", "start", "inspect_container",
  647. })
  648. fakeDocker.Lock()
  649. if len(fakeDocker.Created) != 1 ||
  650. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) {
  651. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  652. }
  653. fakeDocker.Unlock()
  654. }
  655. func TestSyncPodDeletesWithNoPodInfraContainer(t *testing.T) {
  656. dm, fakeDocker := newTestDockerManager()
  657. pod := &api.Pod{
  658. ObjectMeta: api.ObjectMeta{
  659. UID: "12345678",
  660. Name: "foo1",
  661. Namespace: "new",
  662. },
  663. Spec: api.PodSpec{
  664. Containers: []api.Container{
  665. {Name: "bar1"},
  666. },
  667. },
  668. }
  669. fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
  670. ID: "1234",
  671. Name: "/k8s_bar1_foo1_new_12345678_0",
  672. }})
  673. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  674. verifyCalls(t, fakeDocker, []string{
  675. // Kill the container since pod infra container is not running.
  676. "stop",
  677. // Create pod infra container.
  678. "create", "start", "inspect_container", "inspect_container",
  679. // Create container.
  680. "create", "start", "inspect_container",
  681. })
  682. // A map iteration is used to delete containers, so must not depend on
  683. // order here.
  684. expectedToStop := map[string]bool{
  685. "1234": true,
  686. }
  687. fakeDocker.Lock()
  688. if len(fakeDocker.Stopped) != 1 || !expectedToStop[fakeDocker.Stopped[0]] {
  689. t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
  690. }
  691. fakeDocker.Unlock()
  692. }
  693. func TestSyncPodDeletesDuplicate(t *testing.T) {
  694. dm, fakeDocker := newTestDockerManager()
  695. pod := &api.Pod{
  696. ObjectMeta: api.ObjectMeta{
  697. UID: "12345678",
  698. Name: "bar",
  699. Namespace: "new",
  700. },
  701. Spec: api.PodSpec{
  702. Containers: []api.Container{
  703. {Name: "foo"},
  704. },
  705. },
  706. }
  707. fakeDocker.SetFakeRunningContainers([]*FakeContainer{
  708. {
  709. ID: "1234",
  710. Name: "/k8s_foo_bar_new_12345678_1111",
  711. },
  712. {
  713. ID: "9876",
  714. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_bar_new_12345678_2222",
  715. },
  716. {
  717. ID: "4567",
  718. Name: "/k8s_foo_bar_new_12345678_3333",
  719. }})
  720. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  721. verifyCalls(t, fakeDocker, []string{
  722. // Kill the duplicated container.
  723. "stop",
  724. })
  725. // Expect one of the duplicates to be killed.
  726. if len(fakeDocker.Stopped) != 1 || (fakeDocker.Stopped[0] != "1234" && fakeDocker.Stopped[0] != "4567") {
  727. t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
  728. }
  729. }
  730. func TestSyncPodBadHash(t *testing.T) {
  731. dm, fakeDocker := newTestDockerManager()
  732. pod := &api.Pod{
  733. ObjectMeta: api.ObjectMeta{
  734. UID: "12345678",
  735. Name: "foo",
  736. Namespace: "new",
  737. },
  738. Spec: api.PodSpec{
  739. Containers: []api.Container{
  740. {Name: "bar"},
  741. },
  742. },
  743. }
  744. fakeDocker.SetFakeRunningContainers([]*FakeContainer{
  745. {
  746. ID: "1234",
  747. Name: "/k8s_bar.1234_foo_new_12345678_42",
  748. },
  749. {
  750. ID: "9876",
  751. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_42",
  752. }})
  753. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  754. verifyCalls(t, fakeDocker, []string{
  755. // Kill and restart the bad hash container.
  756. "stop", "create", "start", "inspect_container",
  757. })
  758. if err := fakeDocker.AssertStopped([]string{"1234"}); err != nil {
  759. t.Errorf("%v", err)
  760. }
  761. }
  762. func TestSyncPodsUnhealthy(t *testing.T) {
  763. const (
  764. unhealthyContainerID = "1234"
  765. infraContainerID = "9876"
  766. )
  767. dm, fakeDocker := newTestDockerManager()
  768. pod := &api.Pod{
  769. ObjectMeta: api.ObjectMeta{
  770. UID: "12345678",
  771. Name: "foo",
  772. Namespace: "new",
  773. },
  774. Spec: api.PodSpec{
  775. Containers: []api.Container{{Name: "unhealthy"}},
  776. },
  777. }
  778. fakeDocker.SetFakeRunningContainers([]*FakeContainer{
  779. {
  780. ID: unhealthyContainerID,
  781. Name: "/k8s_unhealthy_foo_new_12345678_42",
  782. },
  783. {
  784. ID: infraContainerID,
  785. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_42",
  786. }})
  787. dm.livenessManager.Set(kubecontainer.DockerID(unhealthyContainerID).ContainerID(), proberesults.Failure, pod)
  788. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  789. verifyCalls(t, fakeDocker, []string{
  790. // Kill the unhealthy container.
  791. "stop",
  792. // Restart the unhealthy container.
  793. "create", "start", "inspect_container",
  794. })
  795. if err := fakeDocker.AssertStopped([]string{unhealthyContainerID}); err != nil {
  796. t.Errorf("%v", err)
  797. }
  798. }
  799. func TestSyncPodsDoesNothing(t *testing.T) {
  800. dm, fakeDocker := newTestDockerManager()
  801. container := api.Container{Name: "bar"}
  802. pod := &api.Pod{
  803. ObjectMeta: api.ObjectMeta{
  804. UID: "12345678",
  805. Name: "foo",
  806. Namespace: "new",
  807. },
  808. Spec: api.PodSpec{
  809. Containers: []api.Container{
  810. container,
  811. },
  812. },
  813. }
  814. fakeDocker.SetFakeRunningContainers([]*FakeContainer{
  815. {
  816. ID: "1234",
  817. Name: "/k8s_bar." + strconv.FormatUint(kubecontainer.HashContainer(&container), 16) + "_foo_new_12345678_0",
  818. },
  819. {
  820. ID: "9876",
  821. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
  822. }})
  823. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  824. verifyCalls(t, fakeDocker, []string{})
  825. }
  826. func TestSyncPodWithRestartPolicy(t *testing.T) {
  827. dm, fakeDocker := newTestDockerManager()
  828. containers := []api.Container{
  829. {Name: "succeeded"},
  830. {Name: "failed"},
  831. }
  832. pod := &api.Pod{
  833. ObjectMeta: api.ObjectMeta{
  834. UID: "12345678",
  835. Name: "foo",
  836. Namespace: "new",
  837. },
  838. Spec: api.PodSpec{
  839. Containers: containers,
  840. },
  841. }
  842. dockerContainers := []*FakeContainer{
  843. {
  844. ID: "9876",
  845. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
  846. StartedAt: time.Now(),
  847. Running: true,
  848. },
  849. {
  850. ID: "1234",
  851. Name: "/k8s_succeeded." + strconv.FormatUint(kubecontainer.HashContainer(&containers[0]), 16) + "_foo_new_12345678_0",
  852. ExitCode: 0,
  853. StartedAt: time.Now(),
  854. FinishedAt: time.Now(),
  855. },
  856. {
  857. ID: "5678",
  858. Name: "/k8s_failed." + strconv.FormatUint(kubecontainer.HashContainer(&containers[1]), 16) + "_foo_new_12345678_0",
  859. ExitCode: 42,
  860. StartedAt: time.Now(),
  861. FinishedAt: time.Now(),
  862. }}
  863. tests := []struct {
  864. policy api.RestartPolicy
  865. calls []string
  866. created []string
  867. stopped []string
  868. }{
  869. {
  870. api.RestartPolicyAlways,
  871. []string{
  872. // Restart both containers.
  873. "create", "start", "inspect_container", "create", "start", "inspect_container",
  874. },
  875. []string{"succeeded", "failed"},
  876. []string{},
  877. },
  878. {
  879. api.RestartPolicyOnFailure,
  880. []string{
  881. // Restart the failed container.
  882. "create", "start", "inspect_container",
  883. },
  884. []string{"failed"},
  885. []string{},
  886. },
  887. {
  888. api.RestartPolicyNever,
  889. []string{
  890. // Check the pod infra container.
  891. "inspect_container", "inspect_container",
  892. // Stop the last pod infra container.
  893. "stop",
  894. },
  895. []string{},
  896. []string{"9876"},
  897. },
  898. }
  899. for i, tt := range tests {
  900. fakeDocker.SetFakeContainers(dockerContainers)
  901. pod.Spec.RestartPolicy = tt.policy
  902. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  903. // 'stop' is because the pod infra container is killed when no container is running.
  904. verifyCalls(t, fakeDocker, tt.calls)
  905. if err := fakeDocker.AssertCreated(tt.created); err != nil {
  906. t.Errorf("case [%d]: %v", i, err)
  907. }
  908. if err := fakeDocker.AssertStopped(tt.stopped); err != nil {
  909. t.Errorf("case [%d]: %v", i, err)
  910. }
  911. }
  912. }
  913. func TestSyncPodBackoff(t *testing.T) {
  914. var fakeClock = clock.NewFakeClock(time.Now())
  915. startTime := fakeClock.Now()
  916. dm, fakeDocker := newTestDockerManager()
  917. containers := []api.Container{
  918. {Name: "good"},
  919. {Name: "bad"},
  920. }
  921. pod := &api.Pod{
  922. ObjectMeta: api.ObjectMeta{
  923. UID: "12345678",
  924. Name: "podfoo",
  925. Namespace: "nsnew",
  926. },
  927. Spec: api.PodSpec{
  928. Containers: containers,
  929. },
  930. }
  931. stableId := "k8s_bad." + strconv.FormatUint(kubecontainer.HashContainer(&containers[1]), 16) + "_podfoo_nsnew_12345678"
  932. dockerContainers := []*FakeContainer{
  933. {
  934. ID: "9876",
  935. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_podfoo_nsnew_12345678_0",
  936. StartedAt: startTime,
  937. Running: true,
  938. },
  939. {
  940. ID: "1234",
  941. Name: "/k8s_good." + strconv.FormatUint(kubecontainer.HashContainer(&containers[0]), 16) + "_podfoo_nsnew_12345678_0",
  942. StartedAt: startTime,
  943. Running: true,
  944. },
  945. {
  946. ID: "5678",
  947. Name: "/k8s_bad." + strconv.FormatUint(kubecontainer.HashContainer(&containers[1]), 16) + "_podfoo_nsnew_12345678_0",
  948. ExitCode: 42,
  949. StartedAt: startTime,
  950. FinishedAt: fakeClock.Now(),
  951. },
  952. }
  953. startCalls := []string{"create", "start", "inspect_container"}
  954. backOffCalls := []string{}
  955. startResult := &kubecontainer.SyncResult{Action: kubecontainer.StartContainer, Target: "bad", Error: nil, Message: ""}
  956. backoffResult := &kubecontainer.SyncResult{Action: kubecontainer.StartContainer, Target: "bad", Error: kubecontainer.ErrCrashLoopBackOff, Message: ""}
  957. tests := []struct {
  958. tick int
  959. backoff int
  960. killDelay int
  961. result []string
  962. expectErr bool
  963. }{
  964. {1, 1, 1, startCalls, false},
  965. {2, 2, 2, startCalls, false},
  966. {3, 2, 3, backOffCalls, true},
  967. {4, 4, 4, startCalls, false},
  968. {5, 4, 5, backOffCalls, true},
  969. {6, 4, 6, backOffCalls, true},
  970. {7, 4, 7, backOffCalls, true},
  971. {8, 8, 129, startCalls, false},
  972. {130, 1, 0, startCalls, false},
  973. }
  974. backOff := flowcontrol.NewBackOff(time.Second, time.Minute)
  975. backOff.Clock = fakeClock
  976. for _, c := range tests {
  977. fakeDocker.SetFakeContainers(dockerContainers)
  978. fakeClock.SetTime(startTime.Add(time.Duration(c.tick) * time.Second))
  979. result := runSyncPod(t, dm, fakeDocker, pod, backOff, c.expectErr)
  980. verifyCalls(t, fakeDocker, c.result)
  981. // Verify whether the correct sync pod result is generated
  982. if c.expectErr {
  983. verifySyncResults(t, []*kubecontainer.SyncResult{backoffResult}, result)
  984. } else {
  985. verifySyncResults(t, []*kubecontainer.SyncResult{startResult}, result)
  986. }
  987. if backOff.Get(stableId) != time.Duration(c.backoff)*time.Second {
  988. t.Errorf("At tick %s expected backoff=%s got=%s", time.Duration(c.tick)*time.Second, time.Duration(c.backoff)*time.Second, backOff.Get(stableId))
  989. }
  990. if len(fakeDocker.Created) > 0 {
  991. // pretend kill the container
  992. fakeDocker.Created = nil
  993. dockerContainers[2].FinishedAt = startTime.Add(time.Duration(c.killDelay) * time.Second)
  994. }
  995. }
  996. }
  997. func TestGetRestartCount(t *testing.T) {
  998. dm, fakeDocker := newTestDockerManager()
  999. containerName := "bar"
  1000. pod := api.Pod{
  1001. ObjectMeta: api.ObjectMeta{
  1002. UID: "12345678",
  1003. Name: "foo",
  1004. Namespace: "new",
  1005. },
  1006. Spec: api.PodSpec{
  1007. Containers: []api.Container{
  1008. {Name: containerName},
  1009. },
  1010. RestartPolicy: "Always",
  1011. },
  1012. Status: api.PodStatus{
  1013. ContainerStatuses: []api.ContainerStatus{
  1014. {
  1015. Name: containerName,
  1016. RestartCount: 3,
  1017. },
  1018. },
  1019. },
  1020. }
  1021. // Helper function for verifying the restart count.
  1022. verifyRestartCount := func(pod *api.Pod, expectedCount int) {
  1023. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1024. status, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
  1025. if err != nil {
  1026. t.Fatalf("unexpected error %v", err)
  1027. }
  1028. cs := status.FindContainerStatusByName(containerName)
  1029. if cs == nil {
  1030. t.Fatalf("Can't find status for container %q", containerName)
  1031. }
  1032. restartCount := cs.RestartCount
  1033. if restartCount != expectedCount {
  1034. t.Errorf("expected %d restart count, got %d", expectedCount, restartCount)
  1035. }
  1036. }
  1037. killOneContainer := func(pod *api.Pod) {
  1038. status, err := dm.GetPodStatus(pod.UID, pod.Name, pod.Namespace)
  1039. if err != nil {
  1040. t.Fatalf("unexpected error %v", err)
  1041. }
  1042. cs := status.FindContainerStatusByName(containerName)
  1043. if cs == nil {
  1044. t.Fatalf("Can't find status for container %q", containerName)
  1045. }
  1046. dm.KillContainerInPod(cs.ID, &pod.Spec.Containers[0], pod, "test container restart count.", nil)
  1047. }
  1048. // Container "bar" starts the first time.
  1049. // TODO: container lists are expected to be sorted reversely by time.
  1050. // We should fix FakeDockerClient to sort the list before returning.
  1051. // (randome-liu) Just partially sorted now.
  1052. verifyRestartCount(&pod, 0)
  1053. killOneContainer(&pod)
  1054. // Poor container "bar" has been killed, and should be restarted with restart count 1
  1055. verifyRestartCount(&pod, 1)
  1056. killOneContainer(&pod)
  1057. // Poor container "bar" has been killed again, and should be restarted with restart count 2
  1058. verifyRestartCount(&pod, 2)
  1059. killOneContainer(&pod)
  1060. // Poor container "bar" has been killed again ang again, and should be restarted with restart count 3
  1061. verifyRestartCount(&pod, 3)
  1062. // The oldest container has been garbage collected
  1063. exitedContainers := fakeDocker.ExitedContainerList
  1064. fakeDocker.ExitedContainerList = exitedContainers[:len(exitedContainers)-1]
  1065. verifyRestartCount(&pod, 3)
  1066. // The last two oldest containers have been garbage collected
  1067. fakeDocker.ExitedContainerList = exitedContainers[:len(exitedContainers)-2]
  1068. verifyRestartCount(&pod, 3)
  1069. // All exited containers have been garbage collected, restart count should be got from old api pod status
  1070. fakeDocker.ExitedContainerList = []dockertypes.Container{}
  1071. verifyRestartCount(&pod, 3)
  1072. killOneContainer(&pod)
  1073. // Poor container "bar" has been killed again ang again and again, and should be restarted with restart count 4
  1074. verifyRestartCount(&pod, 4)
  1075. }
  1076. func TestGetTerminationMessagePath(t *testing.T) {
  1077. dm, fakeDocker := newTestDockerManager()
  1078. containers := []api.Container{
  1079. {
  1080. Name: "bar",
  1081. TerminationMessagePath: "/dev/somepath",
  1082. },
  1083. }
  1084. pod := &api.Pod{
  1085. ObjectMeta: api.ObjectMeta{
  1086. UID: "12345678",
  1087. Name: "foo",
  1088. Namespace: "new",
  1089. },
  1090. Spec: api.PodSpec{
  1091. Containers: containers,
  1092. },
  1093. }
  1094. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1095. containerList := fakeDocker.RunningContainerList
  1096. if len(containerList) != 2 {
  1097. // One for infra container, one for container "bar"
  1098. t.Fatalf("unexpected container list length %d", len(containerList))
  1099. }
  1100. inspectResult, err := fakeDocker.InspectContainer(containerList[0].ID)
  1101. if err != nil {
  1102. t.Fatalf("unexpected inspect error: %v", err)
  1103. }
  1104. containerInfo := getContainerInfoFromLabel(inspectResult.Config.Labels)
  1105. terminationMessagePath := containerInfo.TerminationMessagePath
  1106. if terminationMessagePath != containers[0].TerminationMessagePath {
  1107. t.Errorf("expected termination message path %s, got %s", containers[0].TerminationMessagePath, terminationMessagePath)
  1108. }
  1109. }
  1110. func TestSyncPodWithPodInfraCreatesContainerCallsHandler(t *testing.T) {
  1111. fakeHTTPClient := &fakeHTTP{}
  1112. dm, fakeDocker := newTestDockerManagerWithHTTPClient(fakeHTTPClient)
  1113. pod := &api.Pod{
  1114. ObjectMeta: api.ObjectMeta{
  1115. UID: "12345678",
  1116. Name: "foo",
  1117. Namespace: "new",
  1118. },
  1119. Spec: api.PodSpec{
  1120. Containers: []api.Container{
  1121. {
  1122. Name: "bar",
  1123. Lifecycle: &api.Lifecycle{
  1124. PostStart: &api.Handler{
  1125. HTTPGet: &api.HTTPGetAction{
  1126. Host: "foo",
  1127. Port: intstr.FromInt(8080),
  1128. Path: "bar",
  1129. },
  1130. },
  1131. },
  1132. },
  1133. },
  1134. },
  1135. }
  1136. fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
  1137. ID: "9876",
  1138. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
  1139. }})
  1140. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1141. verifyCalls(t, fakeDocker, []string{
  1142. // Create container.
  1143. "create", "start", "inspect_container",
  1144. })
  1145. fakeDocker.Lock()
  1146. if len(fakeDocker.Created) != 1 ||
  1147. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) {
  1148. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1149. }
  1150. fakeDocker.Unlock()
  1151. if fakeHTTPClient.url != "http://foo:8080/bar" {
  1152. t.Errorf("unexpected handler: %q", fakeHTTPClient.url)
  1153. }
  1154. }
  1155. func TestSyncPodEventHandlerFails(t *testing.T) {
  1156. // Simulate HTTP failure.
  1157. fakeHTTPClient := &fakeHTTP{err: fmt.Errorf("test error")}
  1158. dm, fakeDocker := newTestDockerManagerWithHTTPClient(fakeHTTPClient)
  1159. pod := &api.Pod{
  1160. ObjectMeta: api.ObjectMeta{
  1161. UID: "12345678",
  1162. Name: "foo",
  1163. Namespace: "new",
  1164. },
  1165. Spec: api.PodSpec{
  1166. Containers: []api.Container{
  1167. {Name: "bar",
  1168. Lifecycle: &api.Lifecycle{
  1169. PostStart: &api.Handler{
  1170. HTTPGet: &api.HTTPGetAction{
  1171. Host: "does.no.exist",
  1172. Port: intstr.FromInt(8080),
  1173. Path: "bar",
  1174. },
  1175. },
  1176. },
  1177. },
  1178. },
  1179. },
  1180. }
  1181. fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
  1182. ID: "9876",
  1183. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
  1184. }})
  1185. runSyncPod(t, dm, fakeDocker, pod, nil, true)
  1186. verifyCalls(t, fakeDocker, []string{
  1187. // Create the container.
  1188. "create", "start",
  1189. // Kill the container since event handler fails.
  1190. "stop",
  1191. })
  1192. // TODO(yifan): Check the stopped container's name.
  1193. if len(fakeDocker.Stopped) != 1 {
  1194. t.Fatalf("Wrong containers were stopped: %v", fakeDocker.Stopped)
  1195. }
  1196. dockerName, _, err := ParseDockerName(fakeDocker.Stopped[0])
  1197. if err != nil {
  1198. t.Errorf("unexpected error: %v", err)
  1199. }
  1200. if dockerName.ContainerName != "bar" {
  1201. t.Errorf("Wrong stopped container, expected: bar, get: %q", dockerName.ContainerName)
  1202. }
  1203. }
  1204. type fakeReadWriteCloser struct{}
  1205. func (*fakeReadWriteCloser) Read([]byte) (int, error) { return 0, nil }
  1206. func (*fakeReadWriteCloser) Write([]byte) (int, error) { return 0, nil }
  1207. func (*fakeReadWriteCloser) Close() error { return nil }
  1208. func TestPortForwardNoSuchContainer(t *testing.T) {
  1209. dm, _ := newTestDockerManager()
  1210. podName, podNamespace := "podName", "podNamespace"
  1211. err := dm.PortForward(
  1212. &kubecontainer.Pod{
  1213. ID: "podID",
  1214. Name: podName,
  1215. Namespace: podNamespace,
  1216. Containers: nil,
  1217. },
  1218. 5000,
  1219. // need a valid io.ReadWriteCloser here
  1220. &fakeReadWriteCloser{},
  1221. )
  1222. if err == nil {
  1223. t.Fatal("unexpected non-error")
  1224. }
  1225. expectedErr := noPodInfraContainerError(podName, podNamespace)
  1226. if !reflect.DeepEqual(err, expectedErr) {
  1227. t.Fatalf("expected %v, but saw %v", expectedErr, err)
  1228. }
  1229. }
  1230. func TestSyncPodWithTerminationLog(t *testing.T) {
  1231. dm, fakeDocker := newTestDockerManager()
  1232. container := api.Container{
  1233. Name: "bar",
  1234. TerminationMessagePath: "/dev/somepath",
  1235. }
  1236. pod := &api.Pod{
  1237. ObjectMeta: api.ObjectMeta{
  1238. UID: "12345678",
  1239. Name: "foo",
  1240. Namespace: "new",
  1241. },
  1242. Spec: api.PodSpec{
  1243. Containers: []api.Container{
  1244. container,
  1245. },
  1246. },
  1247. }
  1248. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1249. verifyCalls(t, fakeDocker, []string{
  1250. // Create pod infra container.
  1251. "create", "start", "inspect_container", "inspect_container",
  1252. // Create container.
  1253. "create", "start", "inspect_container",
  1254. })
  1255. defer os.Remove(testPodContainerDir)
  1256. fakeDocker.Lock()
  1257. if len(fakeDocker.Created) != 2 ||
  1258. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
  1259. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
  1260. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1261. }
  1262. fakeDocker.Unlock()
  1263. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1264. if err != nil {
  1265. t.Fatalf("unexpected error %v", err)
  1266. }
  1267. parts := strings.Split(newContainer.HostConfig.Binds[0], ":")
  1268. if !matchString(t, testPodContainerDir+"/[a-f0-9]", parts[0]) {
  1269. t.Errorf("unexpected host path: %s", parts[0])
  1270. }
  1271. if parts[1] != "/dev/somepath" {
  1272. t.Errorf("unexpected container path: %s", parts[1])
  1273. }
  1274. }
  1275. func TestSyncPodWithHostNetwork(t *testing.T) {
  1276. dm, fakeDocker := newTestDockerManager()
  1277. pod := &api.Pod{
  1278. ObjectMeta: api.ObjectMeta{
  1279. UID: "12345678",
  1280. Name: "foo",
  1281. Namespace: "new",
  1282. },
  1283. Spec: api.PodSpec{
  1284. Containers: []api.Container{
  1285. {Name: "bar"},
  1286. },
  1287. SecurityContext: &api.PodSecurityContext{
  1288. HostNetwork: true,
  1289. },
  1290. },
  1291. }
  1292. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1293. verifyCalls(t, fakeDocker, []string{
  1294. // Create pod infra container.
  1295. "create", "start", "inspect_container",
  1296. // Create container.
  1297. "create", "start", "inspect_container",
  1298. })
  1299. fakeDocker.Lock()
  1300. if len(fakeDocker.Created) != 2 ||
  1301. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
  1302. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
  1303. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1304. }
  1305. fakeDocker.Unlock()
  1306. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1307. if err != nil {
  1308. t.Fatalf("unexpected error %v", err)
  1309. }
  1310. utsMode := newContainer.HostConfig.UTSMode
  1311. if utsMode != "host" {
  1312. t.Errorf("Pod with host network must have \"host\" utsMode, actual: \"%v\"", utsMode)
  1313. }
  1314. }
  1315. func TestVerifyNonRoot(t *testing.T) {
  1316. dm, fakeDocker := newTestDockerManager()
  1317. // setup test cases.
  1318. var rootUid int64 = 0
  1319. var nonRootUid int64 = 1
  1320. tests := map[string]struct {
  1321. container *api.Container
  1322. inspectImage *dockertypes.ImageInspect
  1323. expectedError string
  1324. }{
  1325. // success cases
  1326. "non-root runAsUser": {
  1327. container: &api.Container{
  1328. SecurityContext: &api.SecurityContext{
  1329. RunAsUser: &nonRootUid,
  1330. },
  1331. },
  1332. },
  1333. "numeric non-root image user": {
  1334. container: &api.Container{},
  1335. inspectImage: &dockertypes.ImageInspect{
  1336. Config: &dockercontainer.Config{
  1337. User: "1",
  1338. },
  1339. },
  1340. },
  1341. "numeric non-root image user with gid": {
  1342. container: &api.Container{},
  1343. inspectImage: &dockertypes.ImageInspect{
  1344. Config: &dockercontainer.Config{
  1345. User: "1:2",
  1346. },
  1347. },
  1348. },
  1349. // failure cases
  1350. "root runAsUser": {
  1351. container: &api.Container{
  1352. SecurityContext: &api.SecurityContext{
  1353. RunAsUser: &rootUid,
  1354. },
  1355. },
  1356. expectedError: "container's runAsUser breaks non-root policy",
  1357. },
  1358. "non-numeric image user": {
  1359. container: &api.Container{},
  1360. inspectImage: &dockertypes.ImageInspect{
  1361. Config: &dockercontainer.Config{
  1362. User: "foo",
  1363. },
  1364. },
  1365. expectedError: "non-numeric user",
  1366. },
  1367. "numeric root image user": {
  1368. container: &api.Container{},
  1369. inspectImage: &dockertypes.ImageInspect{
  1370. Config: &dockercontainer.Config{
  1371. User: "0",
  1372. },
  1373. },
  1374. expectedError: "container has no runAsUser and image will run as root",
  1375. },
  1376. "numeric root image user with gid": {
  1377. container: &api.Container{},
  1378. inspectImage: &dockertypes.ImageInspect{
  1379. Config: &dockercontainer.Config{
  1380. User: "0:1",
  1381. },
  1382. },
  1383. expectedError: "container has no runAsUser and image will run as root",
  1384. },
  1385. "nil image in inspect": {
  1386. container: &api.Container{},
  1387. expectedError: "unable to inspect image",
  1388. },
  1389. "nil config in image inspect": {
  1390. container: &api.Container{},
  1391. inspectImage: &dockertypes.ImageInspect{},
  1392. expectedError: "unable to inspect image",
  1393. },
  1394. }
  1395. for k, v := range tests {
  1396. fakeDocker.Image = v.inspectImage
  1397. err := dm.verifyNonRoot(v.container)
  1398. if v.expectedError == "" && err != nil {
  1399. t.Errorf("case[%q]: unexpected error: %v", k, err)
  1400. }
  1401. if v.expectedError != "" && !strings.Contains(err.Error(), v.expectedError) {
  1402. t.Errorf("case[%q]: expected: %q, got: %q", k, v.expectedError, err.Error())
  1403. }
  1404. }
  1405. }
  1406. func TestGetUidFromUser(t *testing.T) {
  1407. tests := map[string]struct {
  1408. input string
  1409. expect string
  1410. }{
  1411. "no gid": {
  1412. input: "0",
  1413. expect: "0",
  1414. },
  1415. "uid/gid": {
  1416. input: "0:1",
  1417. expect: "0",
  1418. },
  1419. "empty input": {
  1420. input: "",
  1421. expect: "",
  1422. },
  1423. "multiple spearators": {
  1424. input: "1:2:3",
  1425. expect: "1",
  1426. },
  1427. }
  1428. for k, v := range tests {
  1429. actual := getUidFromUser(v.input)
  1430. if actual != v.expect {
  1431. t.Errorf("%s failed. Expected %s but got %s", k, v.expect, actual)
  1432. }
  1433. }
  1434. }
  1435. func TestGetPidMode(t *testing.T) {
  1436. // test false
  1437. pod := &api.Pod{}
  1438. pidMode := getPidMode(pod)
  1439. if pidMode != "" {
  1440. t.Errorf("expected empty pid mode for pod but got %v", pidMode)
  1441. }
  1442. // test true
  1443. pod.Spec.SecurityContext = &api.PodSecurityContext{}
  1444. pod.Spec.SecurityContext.HostPID = true
  1445. pidMode = getPidMode(pod)
  1446. if pidMode != "host" {
  1447. t.Errorf("expected host pid mode for pod but got %v", pidMode)
  1448. }
  1449. }
  1450. func TestGetIPCMode(t *testing.T) {
  1451. // test false
  1452. pod := &api.Pod{}
  1453. ipcMode := getIPCMode(pod)
  1454. if ipcMode != "" {
  1455. t.Errorf("expected empty ipc mode for pod but got %v", ipcMode)
  1456. }
  1457. // test true
  1458. pod.Spec.SecurityContext = &api.PodSecurityContext{}
  1459. pod.Spec.SecurityContext.HostIPC = true
  1460. ipcMode = getIPCMode(pod)
  1461. if ipcMode != "host" {
  1462. t.Errorf("expected host ipc mode for pod but got %v", ipcMode)
  1463. }
  1464. }
  1465. func TestSyncPodWithPullPolicy(t *testing.T) {
  1466. dm, fakeDocker := newTestDockerManager()
  1467. puller := dm.dockerPuller.(*FakeDockerPuller)
  1468. puller.HasImages = []string{"existing_one", "want:latest"}
  1469. dm.podInfraContainerImage = "pod_infra_image"
  1470. pod := &api.Pod{
  1471. ObjectMeta: api.ObjectMeta{
  1472. UID: "12345678",
  1473. Name: "foo",
  1474. Namespace: "new",
  1475. },
  1476. Spec: api.PodSpec{
  1477. Containers: []api.Container{
  1478. {Name: "bar", Image: "pull_always_image", ImagePullPolicy: api.PullAlways},
  1479. {Name: "bar2", Image: "pull_if_not_present_image", ImagePullPolicy: api.PullIfNotPresent},
  1480. {Name: "bar3", Image: "existing_one", ImagePullPolicy: api.PullIfNotPresent},
  1481. {Name: "bar4", Image: "want:latest", ImagePullPolicy: api.PullIfNotPresent},
  1482. {Name: "bar5", Image: "pull_never_image", ImagePullPolicy: api.PullNever},
  1483. },
  1484. },
  1485. }
  1486. expectedResults := []*kubecontainer.SyncResult{
  1487. //Sync result for infra container
  1488. {kubecontainer.StartContainer, PodInfraContainerName, nil, ""},
  1489. {kubecontainer.SetupNetwork, kubecontainer.GetPodFullName(pod), nil, ""},
  1490. //Sync result for user containers
  1491. {kubecontainer.StartContainer, "bar", nil, ""},
  1492. {kubecontainer.StartContainer, "bar2", nil, ""},
  1493. {kubecontainer.StartContainer, "bar3", nil, ""},
  1494. {kubecontainer.StartContainer, "bar4", nil, ""},
  1495. {kubecontainer.StartContainer, "bar5", images.ErrImageNeverPull,
  1496. "Container image \"pull_never_image\" is not present with pull policy of Never"},
  1497. }
  1498. result := runSyncPod(t, dm, fakeDocker, pod, nil, true)
  1499. verifySyncResults(t, expectedResults, result)
  1500. fakeDocker.Lock()
  1501. defer fakeDocker.Unlock()
  1502. pulledImageSorted := puller.ImagesPulled[:]
  1503. sort.Strings(pulledImageSorted)
  1504. assert.Equal(t, []string{"pod_infra_image", "pull_always_image", "pull_if_not_present_image"}, pulledImageSorted)
  1505. if len(fakeDocker.Created) != 5 {
  1506. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1507. }
  1508. }
  1509. // This test only covers SyncPod with PullImageFailure, CreateContainerFailure and StartContainerFailure.
  1510. // There are still quite a few failure cases not covered.
  1511. // TODO(random-liu): Better way to test the SyncPod failures.
  1512. func TestSyncPodWithFailure(t *testing.T) {
  1513. pod := &api.Pod{
  1514. ObjectMeta: api.ObjectMeta{
  1515. UID: "12345678",
  1516. Name: "foo",
  1517. Namespace: "new",
  1518. },
  1519. }
  1520. tests := map[string]struct {
  1521. container api.Container
  1522. dockerError map[string]error
  1523. pullerError []error
  1524. expected []*kubecontainer.SyncResult
  1525. }{
  1526. "PullImageFailure": {
  1527. api.Container{Name: "bar", Image: "realImage", ImagePullPolicy: api.PullAlways},
  1528. map[string]error{},
  1529. []error{fmt.Errorf("can't pull image")},
  1530. []*kubecontainer.SyncResult{{kubecontainer.StartContainer, "bar", images.ErrImagePull, "can't pull image"}},
  1531. },
  1532. "CreateContainerFailure": {
  1533. api.Container{Name: "bar", Image: "alreadyPresent"},
  1534. map[string]error{"create": fmt.Errorf("can't create container")},
  1535. []error{},
  1536. []*kubecontainer.SyncResult{{kubecontainer.StartContainer, "bar", kubecontainer.ErrRunContainer, "can't create container"}},
  1537. },
  1538. "StartContainerFailure": {
  1539. api.Container{Name: "bar", Image: "alreadyPresent"},
  1540. map[string]error{"start": fmt.Errorf("can't start container")},
  1541. []error{},
  1542. []*kubecontainer.SyncResult{{kubecontainer.StartContainer, "bar", kubecontainer.ErrRunContainer, "can't start container"}},
  1543. },
  1544. }
  1545. for _, test := range tests {
  1546. dm, fakeDocker := newTestDockerManager()
  1547. puller := dm.dockerPuller.(*FakeDockerPuller)
  1548. puller.HasImages = []string{test.container.Image}
  1549. // Pretend that the pod infra container has already been created, so that
  1550. // we can run the user containers.
  1551. fakeDocker.SetFakeRunningContainers([]*FakeContainer{{
  1552. ID: "9876",
  1553. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_0",
  1554. }})
  1555. fakeDocker.InjectErrors(test.dockerError)
  1556. puller.ErrorsToInject = test.pullerError
  1557. pod.Spec.Containers = []api.Container{test.container}
  1558. result := runSyncPod(t, dm, fakeDocker, pod, nil, true)
  1559. verifySyncResults(t, test.expected, result)
  1560. }
  1561. }
  1562. // Verify whether all the expected results appear exactly only once in real result.
  1563. func verifySyncResults(t *testing.T, expectedResults []*kubecontainer.SyncResult, realResult kubecontainer.PodSyncResult) {
  1564. if len(expectedResults) != len(realResult.SyncResults) {
  1565. t.Errorf("expected sync result number %d, got %d", len(expectedResults), len(realResult.SyncResults))
  1566. for _, r := range expectedResults {
  1567. t.Errorf("expected result: %#v", r)
  1568. }
  1569. for _, r := range realResult.SyncResults {
  1570. t.Errorf("real result: %+v", r)
  1571. }
  1572. return
  1573. }
  1574. // The container start order is not fixed, because SyncPod() uses a map to store the containers to start.
  1575. // Here we should make sure each expected result appears only once in the real result.
  1576. for _, expectR := range expectedResults {
  1577. found := 0
  1578. for _, realR := range realResult.SyncResults {
  1579. // For the same action of the same container, the result should be the same
  1580. if realR.Target == expectR.Target && realR.Action == expectR.Action {
  1581. // We use Contains() here because the message format may be changed, but at least we should
  1582. // make sure that the expected message is contained.
  1583. if realR.Error != expectR.Error || !strings.Contains(realR.Message, expectR.Message) {
  1584. t.Errorf("expected sync result %#v, got %+v", expectR, realR)
  1585. }
  1586. found++
  1587. }
  1588. }
  1589. if found == 0 {
  1590. t.Errorf("not found expected result %#v", expectR)
  1591. }
  1592. if found > 1 {
  1593. t.Errorf("got %d duplicate expected result %#v", found, expectR)
  1594. }
  1595. }
  1596. }
  1597. func TestSecurityOptsOperator(t *testing.T) {
  1598. dm110, _ := newTestDockerManagerWithVersion("1.10.1", "1.22")
  1599. dm111, _ := newTestDockerManagerWithVersion("1.11.0", "1.23")
  1600. secOpts := []dockerOpt{{"seccomp", "unconfined", ""}}
  1601. opts, err := dm110.fmtDockerOpts(secOpts)
  1602. if err != nil {
  1603. t.Fatalf("error getting security opts for Docker 1.10: %v", err)
  1604. }
  1605. if expected := []string{"seccomp:unconfined"}; len(opts) != 1 || opts[0] != expected[0] {
  1606. t.Fatalf("security opts for Docker 1.10: expected %v, got: %v", expected, opts)
  1607. }
  1608. opts, err = dm111.fmtDockerOpts(secOpts)
  1609. if err != nil {
  1610. t.Fatalf("error getting security opts for Docker 1.11: %v", err)
  1611. }
  1612. if expected := []string{"seccomp=unconfined"}; len(opts) != 1 || opts[0] != expected[0] {
  1613. t.Fatalf("security opts for Docker 1.11: expected %v, got: %v", expected, opts)
  1614. }
  1615. }
  1616. func TestGetSecurityOpts(t *testing.T) {
  1617. const containerName = "bar"
  1618. makePod := func(annotations map[string]string) *api.Pod {
  1619. return &api.Pod{
  1620. ObjectMeta: api.ObjectMeta{
  1621. UID: "12345678",
  1622. Name: "foo",
  1623. Namespace: "new",
  1624. Annotations: annotations,
  1625. },
  1626. Spec: api.PodSpec{
  1627. Containers: []api.Container{
  1628. {Name: containerName},
  1629. },
  1630. },
  1631. }
  1632. }
  1633. tests := []struct {
  1634. msg string
  1635. pod *api.Pod
  1636. expectedOpts []string
  1637. }{{
  1638. msg: "No security annotations",
  1639. pod: makePod(nil),
  1640. expectedOpts: []string{"seccomp=unconfined"},
  1641. }, {
  1642. msg: "Seccomp default",
  1643. pod: makePod(map[string]string{
  1644. api.SeccompContainerAnnotationKeyPrefix + containerName: "docker/default",
  1645. }),
  1646. expectedOpts: nil,
  1647. }, {
  1648. msg: "AppArmor runtime/default",
  1649. pod: makePod(map[string]string{
  1650. apparmor.ContainerAnnotationKeyPrefix + containerName: apparmor.ProfileRuntimeDefault,
  1651. }),
  1652. expectedOpts: []string{"seccomp=unconfined"},
  1653. }, {
  1654. msg: "AppArmor local profile",
  1655. pod: makePod(map[string]string{
  1656. apparmor.ContainerAnnotationKeyPrefix + containerName: apparmor.ProfileNamePrefix + "foo",
  1657. }),
  1658. expectedOpts: []string{"seccomp=unconfined", "apparmor=foo"},
  1659. }, {
  1660. msg: "AppArmor and seccomp profile",
  1661. pod: makePod(map[string]string{
  1662. api.SeccompContainerAnnotationKeyPrefix + containerName: "docker/default",
  1663. apparmor.ContainerAnnotationKeyPrefix + containerName: apparmor.ProfileNamePrefix + "foo",
  1664. }),
  1665. expectedOpts: []string{"apparmor=foo"},
  1666. }}
  1667. dm, _ := newTestDockerManagerWithVersion("1.11.1", "1.23")
  1668. for i, test := range tests {
  1669. securityOpts, err := dm.getSecurityOpts(test.pod, containerName)
  1670. assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
  1671. opts, err := dm.fmtDockerOpts(securityOpts)
  1672. assert.NoError(t, err, "TestCase[%d]: %s", i, test.msg)
  1673. assert.Len(t, opts, len(test.expectedOpts), "TestCase[%d]: %s", i, test.msg)
  1674. for _, opt := range test.expectedOpts {
  1675. assert.Contains(t, opts, opt, "TestCase[%d]: %s", i, test.msg)
  1676. }
  1677. }
  1678. }
  1679. func TestSeccompIsUnconfinedByDefaultWithDockerV110(t *testing.T) {
  1680. dm, fakeDocker := newTestDockerManagerWithVersion("1.10.1", "1.22")
  1681. // We want to capture events.
  1682. recorder := record.NewFakeRecorder(20)
  1683. dm.recorder = recorder
  1684. pod := &api.Pod{
  1685. ObjectMeta: api.ObjectMeta{
  1686. UID: "12345678",
  1687. Name: "foo",
  1688. Namespace: "new",
  1689. },
  1690. Spec: api.PodSpec{
  1691. Containers: []api.Container{
  1692. {Name: "bar"},
  1693. },
  1694. },
  1695. }
  1696. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1697. verifyCalls(t, fakeDocker, []string{
  1698. // Create pod infra container.
  1699. "create", "start", "inspect_container", "inspect_container",
  1700. // Create container.
  1701. "create", "start", "inspect_container",
  1702. })
  1703. fakeDocker.Lock()
  1704. if len(fakeDocker.Created) != 2 ||
  1705. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
  1706. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
  1707. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1708. }
  1709. fakeDocker.Unlock()
  1710. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1711. if err != nil {
  1712. t.Fatalf("unexpected error %v", err)
  1713. }
  1714. assert.Contains(t, newContainer.HostConfig.SecurityOpt, "seccomp:unconfined", "Pods with Docker versions >= 1.10 must not have seccomp disabled by default")
  1715. cid := utilstrings.ShortenString(fakeDocker.Created[1], 12)
  1716. assert.NoError(t, expectEvent(recorder, api.EventTypeNormal, events.CreatedContainer,
  1717. fmt.Sprintf("Created container with docker id %s; Security:[seccomp=unconfined]", cid)))
  1718. }
  1719. func TestUnconfinedSeccompProfileWithDockerV110(t *testing.T) {
  1720. dm, fakeDocker := newTestDockerManagerWithVersion("1.10.1", "1.22")
  1721. pod := &api.Pod{
  1722. ObjectMeta: api.ObjectMeta{
  1723. UID: "12345678",
  1724. Name: "foo4",
  1725. Namespace: "new",
  1726. Annotations: map[string]string{
  1727. api.SeccompPodAnnotationKey: "unconfined",
  1728. },
  1729. },
  1730. Spec: api.PodSpec{
  1731. Containers: []api.Container{
  1732. {Name: "bar4"},
  1733. },
  1734. },
  1735. }
  1736. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1737. verifyCalls(t, fakeDocker, []string{
  1738. // Create pod infra container.
  1739. "create", "start", "inspect_container", "inspect_container",
  1740. // Create container.
  1741. "create", "start", "inspect_container",
  1742. })
  1743. fakeDocker.Lock()
  1744. if len(fakeDocker.Created) != 2 ||
  1745. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo4_new_", fakeDocker.Created[0]) ||
  1746. !matchString(t, "/k8s_bar4\\.[a-f0-9]+_foo4_new_", fakeDocker.Created[1]) {
  1747. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1748. }
  1749. fakeDocker.Unlock()
  1750. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1751. if err != nil {
  1752. t.Fatalf("unexpected error %v", err)
  1753. }
  1754. assert.Contains(t, newContainer.HostConfig.SecurityOpt, "seccomp:unconfined", "Pods created with a secccomp annotation of unconfined should have seccomp:unconfined.")
  1755. }
  1756. func TestDefaultSeccompProfileWithDockerV110(t *testing.T) {
  1757. dm, fakeDocker := newTestDockerManagerWithVersion("1.10.1", "1.22")
  1758. pod := &api.Pod{
  1759. ObjectMeta: api.ObjectMeta{
  1760. UID: "12345678",
  1761. Name: "foo1",
  1762. Namespace: "new",
  1763. Annotations: map[string]string{
  1764. api.SeccompPodAnnotationKey: "docker/default",
  1765. },
  1766. },
  1767. Spec: api.PodSpec{
  1768. Containers: []api.Container{
  1769. {Name: "bar1"},
  1770. },
  1771. },
  1772. }
  1773. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1774. verifyCalls(t, fakeDocker, []string{
  1775. // Create pod infra container.
  1776. "create", "start", "inspect_container", "inspect_container",
  1777. // Create container.
  1778. "create", "start", "inspect_container",
  1779. })
  1780. fakeDocker.Lock()
  1781. if len(fakeDocker.Created) != 2 ||
  1782. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo1_new_", fakeDocker.Created[0]) ||
  1783. !matchString(t, "/k8s_bar1\\.[a-f0-9]+_foo1_new_", fakeDocker.Created[1]) {
  1784. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1785. }
  1786. fakeDocker.Unlock()
  1787. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1788. if err != nil {
  1789. t.Fatalf("unexpected error %v", err)
  1790. }
  1791. assert.NotContains(t, newContainer.HostConfig.SecurityOpt, "seccomp:unconfined", "Pods created with a secccomp annotation of docker/default should have empty security opt.")
  1792. }
  1793. func TestSeccompContainerAnnotationTrumpsPod(t *testing.T) {
  1794. dm, fakeDocker := newTestDockerManagerWithVersion("1.10.1", "1.22")
  1795. pod := &api.Pod{
  1796. ObjectMeta: api.ObjectMeta{
  1797. UID: "12345678",
  1798. Name: "foo2",
  1799. Namespace: "new",
  1800. Annotations: map[string]string{
  1801. api.SeccompPodAnnotationKey: "unconfined",
  1802. api.SeccompContainerAnnotationKeyPrefix + "bar2": "docker/default",
  1803. },
  1804. },
  1805. Spec: api.PodSpec{
  1806. Containers: []api.Container{
  1807. {Name: "bar2"},
  1808. },
  1809. },
  1810. }
  1811. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1812. verifyCalls(t, fakeDocker, []string{
  1813. // Create pod infra container.
  1814. "create", "start", "inspect_container", "inspect_container",
  1815. // Create container.
  1816. "create", "start", "inspect_container",
  1817. })
  1818. fakeDocker.Lock()
  1819. if len(fakeDocker.Created) != 2 ||
  1820. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo2_new_", fakeDocker.Created[0]) ||
  1821. !matchString(t, "/k8s_bar2\\.[a-f0-9]+_foo2_new_", fakeDocker.Created[1]) {
  1822. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1823. }
  1824. fakeDocker.Unlock()
  1825. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1826. if err != nil {
  1827. t.Fatalf("unexpected error %v", err)
  1828. }
  1829. assert.NotContains(t, newContainer.HostConfig.SecurityOpt, "seccomp:unconfined", "Container annotation should trump the pod annotation for seccomp.")
  1830. }
  1831. func TestSeccompLocalhostProfileIsLoaded(t *testing.T) {
  1832. tests := []struct {
  1833. annotations map[string]string
  1834. expectedSecOpt string
  1835. expectedSecMsg string
  1836. expectedError string
  1837. }{
  1838. {
  1839. annotations: map[string]string{
  1840. api.SeccompPodAnnotationKey: "localhost/test",
  1841. },
  1842. expectedSecOpt: `seccomp={"foo":"bar"}`,
  1843. expectedSecMsg: "seccomp=test(md5:21aeae45053385adebd25311f9dd9cb1)",
  1844. },
  1845. {
  1846. annotations: map[string]string{
  1847. api.SeccompPodAnnotationKey: "localhost/sub/subtest",
  1848. },
  1849. expectedSecOpt: `seccomp={"abc":"def"}`,
  1850. expectedSecMsg: "seccomp=sub/subtest(md5:07c9bcb4db631f7ca191d6e0bca49f76)",
  1851. },
  1852. {
  1853. annotations: map[string]string{
  1854. api.SeccompPodAnnotationKey: "localhost/not-existing",
  1855. },
  1856. expectedError: "cannot load seccomp profile",
  1857. },
  1858. }
  1859. for i, test := range tests {
  1860. dm, fakeDocker := newTestDockerManagerWithVersion("1.11.0", "1.23")
  1861. // We want to capture events.
  1862. recorder := record.NewFakeRecorder(20)
  1863. dm.recorder = recorder
  1864. _, filename, _, _ := goruntime.Caller(0)
  1865. dm.seccompProfileRoot = path.Join(path.Dir(filename), "fixtures", "seccomp")
  1866. pod := &api.Pod{
  1867. ObjectMeta: api.ObjectMeta{
  1868. UID: "12345678",
  1869. Name: "foo2",
  1870. Namespace: "new",
  1871. Annotations: test.annotations,
  1872. },
  1873. Spec: api.PodSpec{
  1874. Containers: []api.Container{
  1875. {Name: "bar2"},
  1876. },
  1877. },
  1878. }
  1879. result := runSyncPod(t, dm, fakeDocker, pod, nil, test.expectedError != "")
  1880. if test.expectedError != "" {
  1881. assert.Contains(t, result.Error().Error(), test.expectedError)
  1882. continue
  1883. }
  1884. verifyCalls(t, fakeDocker, []string{
  1885. // Create pod infra container.
  1886. "create", "start", "inspect_container", "inspect_container",
  1887. // Create container.
  1888. "create", "start", "inspect_container",
  1889. })
  1890. fakeDocker.Lock()
  1891. if len(fakeDocker.Created) != 2 ||
  1892. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo2_new_", fakeDocker.Created[0]) ||
  1893. !matchString(t, "/k8s_bar2\\.[a-f0-9]+_foo2_new_", fakeDocker.Created[1]) {
  1894. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1895. }
  1896. fakeDocker.Unlock()
  1897. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1898. if err != nil {
  1899. t.Fatalf("unexpected error %v", err)
  1900. }
  1901. assert.Contains(t, newContainer.HostConfig.SecurityOpt, test.expectedSecOpt, "The compacted seccomp json profile should be loaded.")
  1902. cid := utilstrings.ShortenString(fakeDocker.Created[1], 12)
  1903. assert.NoError(t, expectEvent(recorder, api.EventTypeNormal, events.CreatedContainer,
  1904. fmt.Sprintf("Created container with docker id %s; Security:[%s]", cid, test.expectedSecMsg)),
  1905. "testcase %d", i)
  1906. }
  1907. }
  1908. func TestSecurityOptsAreNilWithDockerV19(t *testing.T) {
  1909. dm, fakeDocker := newTestDockerManagerWithVersion("1.9.1", "1.21")
  1910. pod := &api.Pod{
  1911. ObjectMeta: api.ObjectMeta{
  1912. UID: "12345678",
  1913. Name: "foo",
  1914. Namespace: "new",
  1915. },
  1916. Spec: api.PodSpec{
  1917. Containers: []api.Container{
  1918. {Name: "bar"},
  1919. },
  1920. },
  1921. }
  1922. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1923. verifyCalls(t, fakeDocker, []string{
  1924. // Create pod infra container.
  1925. "create", "start", "inspect_container", "inspect_container",
  1926. // Create container.
  1927. "create", "start", "inspect_container",
  1928. })
  1929. fakeDocker.Lock()
  1930. if len(fakeDocker.Created) != 2 ||
  1931. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
  1932. !matchString(t, "/k8s_bar\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
  1933. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  1934. }
  1935. fakeDocker.Unlock()
  1936. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  1937. if err != nil {
  1938. t.Fatalf("unexpected error %v", err)
  1939. }
  1940. assert.NotContains(t, newContainer.HostConfig.SecurityOpt, "seccomp:unconfined", "Pods with Docker versions < 1.10 must not have seccomp disabled by default")
  1941. }
  1942. func TestCheckVersionCompatibility(t *testing.T) {
  1943. type test struct {
  1944. version string
  1945. compatible bool
  1946. }
  1947. tests := []test{
  1948. // Minimum apiversion
  1949. {minimumDockerAPIVersion, true},
  1950. // Invalid apiversion
  1951. {"invalid_api_version", false},
  1952. // Older apiversion
  1953. {"1.0.0", false},
  1954. // Newer apiversion
  1955. // NOTE(random-liu): We need to bump up the newer apiversion,
  1956. // if docker apiversion really reaches "9.9.9" someday. But I
  1957. // really doubt whether the test could live that long.
  1958. {"9.9.9", true},
  1959. }
  1960. for i, tt := range tests {
  1961. testCase := fmt.Sprintf("test case #%d test version %q", i, tt.version)
  1962. dm, fakeDocker := newTestDockerManagerWithVersion("", tt.version)
  1963. err := dm.checkVersionCompatibility()
  1964. assert.Equal(t, tt.compatible, err == nil, testCase)
  1965. if tt.compatible == true {
  1966. // Get docker version error
  1967. fakeDocker.InjectError("version", fmt.Errorf("injected version error"))
  1968. err := dm.checkVersionCompatibility()
  1969. assert.NotNil(t, err, testCase+" version error check")
  1970. }
  1971. }
  1972. }
  1973. func TestCreateAppArmorContanier(t *testing.T) {
  1974. dm, fakeDocker := newTestDockerManagerWithVersion("1.11.1", "1.23")
  1975. // We want to capture events.
  1976. recorder := record.NewFakeRecorder(20)
  1977. dm.recorder = recorder
  1978. pod := &api.Pod{
  1979. ObjectMeta: api.ObjectMeta{
  1980. UID: "12345678",
  1981. Name: "foo",
  1982. Namespace: "new",
  1983. Annotations: map[string]string{
  1984. apparmor.ContainerAnnotationKeyPrefix + "test": apparmor.ProfileNamePrefix + "test-profile",
  1985. },
  1986. },
  1987. Spec: api.PodSpec{
  1988. Containers: []api.Container{
  1989. {Name: "test"},
  1990. },
  1991. },
  1992. }
  1993. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  1994. verifyCalls(t, fakeDocker, []string{
  1995. // Create pod infra container.
  1996. "create", "start", "inspect_container", "inspect_container",
  1997. // Create container.
  1998. "create", "start", "inspect_container",
  1999. })
  2000. fakeDocker.Lock()
  2001. if len(fakeDocker.Created) != 2 ||
  2002. !matchString(t, "/k8s_POD\\.[a-f0-9]+_foo_new_", fakeDocker.Created[0]) ||
  2003. !matchString(t, "/k8s_test\\.[a-f0-9]+_foo_new_", fakeDocker.Created[1]) {
  2004. t.Errorf("unexpected containers created %v", fakeDocker.Created)
  2005. }
  2006. fakeDocker.Unlock()
  2007. // Verify security opts.
  2008. newContainer, err := fakeDocker.InspectContainer(fakeDocker.Created[1])
  2009. if err != nil {
  2010. t.Fatalf("unexpected error %v", err)
  2011. }
  2012. securityOpts := newContainer.HostConfig.SecurityOpt
  2013. assert.Contains(t, securityOpts, "apparmor=test-profile", "Container should have apparmor security opt")
  2014. cid := utilstrings.ShortenString(fakeDocker.Created[1], 12)
  2015. assert.NoError(t, expectEvent(recorder, api.EventTypeNormal, events.CreatedContainer,
  2016. fmt.Sprintf("Created container with docker id %s; Security:[seccomp=unconfined apparmor=test-profile]", cid)))
  2017. }
  2018. func expectEvent(recorder *record.FakeRecorder, eventType, reason, msg string) error {
  2019. expected := fmt.Sprintf("%s %s %s", eventType, reason, msg)
  2020. var events []string
  2021. // Drain the event channel.
  2022. for {
  2023. select {
  2024. case event := <-recorder.Events:
  2025. if event == expected {
  2026. return nil
  2027. }
  2028. events = append(events, event)
  2029. default:
  2030. // No more events!
  2031. return fmt.Errorf("Event %q not found in [%s]", expected, strings.Join(events, ", "))
  2032. }
  2033. }
  2034. }
  2035. func TestNewDockerVersion(t *testing.T) {
  2036. cases := []struct {
  2037. value string
  2038. out string
  2039. err bool
  2040. }{
  2041. {value: "1", err: true},
  2042. {value: "1.8", err: true},
  2043. {value: "1.8.1", out: "1.8.1"},
  2044. {value: "1.8.1-fc21.other", out: "1.8.1-fc21.other"},
  2045. {value: "1.8.1-beta.12", out: "1.8.1-beta.12"},
  2046. }
  2047. for _, test := range cases {
  2048. v, err := newDockerVersion(test.value)
  2049. switch {
  2050. case err != nil && test.err:
  2051. continue
  2052. case (err != nil) != test.err:
  2053. t.Errorf("error for %q: expected %t, got %v", test.value, test.err, err)
  2054. continue
  2055. }
  2056. if v.String() != test.out {
  2057. t.Errorf("unexpected parsed version %q for %q", v, test.value)
  2058. }
  2059. }
  2060. }
  2061. func TestDockerVersionComparison(t *testing.T) {
  2062. v, err := newDockerVersion("1.10.3")
  2063. assert.NoError(t, err)
  2064. for i, test := range []struct {
  2065. version string
  2066. compare int
  2067. err bool
  2068. }{
  2069. {version: "1.9.2", compare: 1},
  2070. {version: "1.9.2-rc2", compare: 1},
  2071. {version: "1.10.3", compare: 0},
  2072. {version: "1.10.3-rc3", compare: 1},
  2073. {version: "1.10.4", compare: -1},
  2074. {version: "1.10.4-rc1", compare: -1},
  2075. {version: "1.11.1", compare: -1},
  2076. {version: "1.11.1-rc4", compare: -1},
  2077. {version: "invalid", compare: -1, err: true},
  2078. } {
  2079. testCase := fmt.Sprintf("test case #%d test version %q", i, test.version)
  2080. res, err := v.Compare(test.version)
  2081. assert.Equal(t, test.compare, res, testCase)
  2082. assert.Equal(t, test.err, err != nil, testCase)
  2083. }
  2084. }
  2085. func TestVersion(t *testing.T) {
  2086. expectedVersion := "1.8.1"
  2087. expectedAPIVersion := "1.20"
  2088. dm, _ := newTestDockerManagerWithVersion(expectedVersion, expectedAPIVersion)
  2089. version, err := dm.Version()
  2090. if err != nil {
  2091. t.Errorf("got error while getting docker server version - %v", err)
  2092. }
  2093. if e, a := expectedVersion, version.String(); e != a {
  2094. t.Errorf("expect docker server version %q, got %q", e, a)
  2095. }
  2096. apiVersion, err := dm.APIVersion()
  2097. if err != nil {
  2098. t.Errorf("got error while getting docker api version - %v", err)
  2099. }
  2100. if e, a := expectedAPIVersion, apiVersion.String(); e != a {
  2101. t.Errorf("expect docker api version %q, got %q", e, a)
  2102. }
  2103. }
  2104. func TestGetPodStatusNoSuchContainer(t *testing.T) {
  2105. const (
  2106. noSuchContainerID = "nosuchcontainer"
  2107. infraContainerID = "9876"
  2108. )
  2109. dm, fakeDocker := newTestDockerManager()
  2110. pod := &api.Pod{
  2111. ObjectMeta: api.ObjectMeta{
  2112. UID: "12345678",
  2113. Name: "foo",
  2114. Namespace: "new",
  2115. },
  2116. Spec: api.PodSpec{
  2117. Containers: []api.Container{{Name: "nosuchcontainer"}},
  2118. },
  2119. }
  2120. fakeDocker.SetFakeContainers([]*FakeContainer{
  2121. {
  2122. ID: noSuchContainerID,
  2123. Name: "/k8s_nosuchcontainer_foo_new_12345678_42",
  2124. ExitCode: 0,
  2125. StartedAt: time.Now(),
  2126. FinishedAt: time.Now(),
  2127. Running: false,
  2128. },
  2129. {
  2130. ID: infraContainerID,
  2131. Name: "/k8s_POD." + strconv.FormatUint(generatePodInfraContainerHash(pod), 16) + "_foo_new_12345678_42",
  2132. ExitCode: 0,
  2133. StartedAt: time.Now(),
  2134. FinishedAt: time.Now(),
  2135. Running: false,
  2136. },
  2137. })
  2138. fakeDocker.InjectErrors(map[string]error{"inspect_container": containerNotFoundError{}})
  2139. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  2140. // Verify that we will try to start new contrainers even if the inspections
  2141. // failed.
  2142. verifyCalls(t, fakeDocker, []string{
  2143. // Start a new infra container.
  2144. "create", "start", "inspect_container", "inspect_container",
  2145. // Start a new container.
  2146. "create", "start", "inspect_container",
  2147. })
  2148. }
  2149. func TestPruneInitContainers(t *testing.T) {
  2150. dm, fake := newTestDockerManager()
  2151. pod := &api.Pod{
  2152. Spec: api.PodSpec{
  2153. InitContainers: []api.Container{
  2154. {Name: "init1"},
  2155. {Name: "init2"},
  2156. },
  2157. },
  2158. }
  2159. status := &kubecontainer.PodStatus{
  2160. ContainerStatuses: []*kubecontainer.ContainerStatus{
  2161. {Name: "init2", ID: kubecontainer.ContainerID{ID: "init2-new-1"}, State: kubecontainer.ContainerStateExited},
  2162. {Name: "init1", ID: kubecontainer.ContainerID{ID: "init1-new-1"}, State: kubecontainer.ContainerStateExited},
  2163. {Name: "init1", ID: kubecontainer.ContainerID{ID: "init1-new-2"}, State: kubecontainer.ContainerStateExited},
  2164. {Name: "init1", ID: kubecontainer.ContainerID{ID: "init1-old-1"}, State: kubecontainer.ContainerStateExited},
  2165. {Name: "init2", ID: kubecontainer.ContainerID{ID: "init2-old-1"}, State: kubecontainer.ContainerStateExited},
  2166. },
  2167. }
  2168. fake.ExitedContainerList = []dockertypes.Container{
  2169. {ID: "init1-new-1"},
  2170. {ID: "init1-new-2"},
  2171. {ID: "init1-old-1"},
  2172. {ID: "init2-new-1"},
  2173. {ID: "init2-old-1"},
  2174. }
  2175. keep := map[kubecontainer.DockerID]int{}
  2176. dm.pruneInitContainersBeforeStart(pod, status, keep)
  2177. sort.Sort(sort.StringSlice(fake.Removed))
  2178. if !reflect.DeepEqual([]string{"init1-new-2", "init1-old-1", "init2-old-1"}, fake.Removed) {
  2179. t.Fatal(fake.Removed)
  2180. }
  2181. }
  2182. func TestGetPodStatusFromNetworkPlugin(t *testing.T) {
  2183. cases := []struct {
  2184. pod *api.Pod
  2185. fakePodIP string
  2186. containerID string
  2187. infraContainerID string
  2188. networkStatusError error
  2189. expectRunning bool
  2190. expectUnknown bool
  2191. }{
  2192. {
  2193. pod: &api.Pod{
  2194. ObjectMeta: api.ObjectMeta{
  2195. UID: "12345678",
  2196. Name: "foo",
  2197. Namespace: "new",
  2198. },
  2199. Spec: api.PodSpec{
  2200. Containers: []api.Container{{Name: "container"}},
  2201. },
  2202. },
  2203. fakePodIP: "10.10.10.10",
  2204. containerID: "123",
  2205. infraContainerID: "9876",
  2206. networkStatusError: nil,
  2207. expectRunning: true,
  2208. expectUnknown: false,
  2209. },
  2210. {
  2211. pod: &api.Pod{
  2212. ObjectMeta: api.ObjectMeta{
  2213. UID: "12345678",
  2214. Name: "foo",
  2215. Namespace: "new",
  2216. },
  2217. Spec: api.PodSpec{
  2218. Containers: []api.Container{{Name: "container"}},
  2219. },
  2220. },
  2221. fakePodIP: "",
  2222. containerID: "123",
  2223. infraContainerID: "9876",
  2224. networkStatusError: fmt.Errorf("CNI plugin error"),
  2225. expectRunning: false,
  2226. expectUnknown: true,
  2227. },
  2228. }
  2229. for _, test := range cases {
  2230. dm, fakeDocker := newTestDockerManager()
  2231. ctrl := gomock.NewController(t)
  2232. fnp := mock_network.NewMockNetworkPlugin(ctrl)
  2233. dm.networkPlugin = fnp
  2234. fakeDocker.SetFakeRunningContainers([]*FakeContainer{
  2235. {
  2236. ID: test.containerID,
  2237. Name: fmt.Sprintf("/k8s_container_%s_%s_%s_42", test.pod.Name, test.pod.Namespace, test.pod.UID),
  2238. Running: true,
  2239. },
  2240. {
  2241. ID: test.infraContainerID,
  2242. Name: fmt.Sprintf("/k8s_POD.%s_%s_%s_%s_42", strconv.FormatUint(generatePodInfraContainerHash(test.pod), 16), test.pod.Name, test.pod.Namespace, test.pod.UID),
  2243. Running: true,
  2244. },
  2245. })
  2246. fnp.EXPECT().Name().Return("someNetworkPlugin").AnyTimes()
  2247. var podNetworkStatus *network.PodNetworkStatus
  2248. if test.fakePodIP != "" {
  2249. podNetworkStatus = &network.PodNetworkStatus{IP: net.ParseIP(test.fakePodIP)}
  2250. }
  2251. fnp.EXPECT().GetPodNetworkStatus(test.pod.Namespace, test.pod.Name, kubecontainer.DockerID(test.infraContainerID).ContainerID()).Return(podNetworkStatus, test.networkStatusError)
  2252. podStatus, err := dm.GetPodStatus(test.pod.UID, test.pod.Name, test.pod.Namespace)
  2253. if err != nil {
  2254. t.Fatal(err)
  2255. }
  2256. if podStatus.IP != test.fakePodIP {
  2257. t.Errorf("Got wrong ip, expected %v, got %v", test.fakePodIP, podStatus.IP)
  2258. }
  2259. expectedStatesCount := 0
  2260. var expectedState kubecontainer.ContainerState
  2261. if test.expectRunning {
  2262. expectedState = kubecontainer.ContainerStateRunning
  2263. } else if test.expectUnknown {
  2264. expectedState = kubecontainer.ContainerStateUnknown
  2265. } else {
  2266. t.Errorf("Some state has to be expected")
  2267. }
  2268. for _, containerStatus := range podStatus.ContainerStatuses {
  2269. if containerStatus.State == expectedState {
  2270. expectedStatesCount++
  2271. }
  2272. }
  2273. if expectedStatesCount < 1 {
  2274. t.Errorf("Invalid count of containers with expected state")
  2275. }
  2276. }
  2277. }
  2278. func TestSyncPodGetsPodIPFromNetworkPlugin(t *testing.T) {
  2279. const (
  2280. containerID = "123"
  2281. infraContainerID = "9876"
  2282. fakePodIP = "10.10.10.10"
  2283. )
  2284. dm, fakeDocker := newTestDockerManager()
  2285. dm.podInfraContainerImage = "pod_infra_image"
  2286. ctrl := gomock.NewController(t)
  2287. defer ctrl.Finish()
  2288. fnp := mock_network.NewMockNetworkPlugin(ctrl)
  2289. dm.networkPlugin = fnp
  2290. pod := &api.Pod{
  2291. ObjectMeta: api.ObjectMeta{
  2292. UID: "12345678",
  2293. Name: "foo",
  2294. Namespace: "new",
  2295. },
  2296. Spec: api.PodSpec{
  2297. Containers: []api.Container{
  2298. {Name: "bar"},
  2299. },
  2300. },
  2301. }
  2302. // Can be called multiple times due to GetPodStatus
  2303. fnp.EXPECT().Name().Return("someNetworkPlugin").AnyTimes()
  2304. fnp.EXPECT().GetPodNetworkStatus("new", "foo", gomock.Any()).Return(&network.PodNetworkStatus{IP: net.ParseIP(fakePodIP)}, nil).AnyTimes()
  2305. fnp.EXPECT().SetUpPod("new", "foo", gomock.Any()).Return(nil)
  2306. runSyncPod(t, dm, fakeDocker, pod, nil, false)
  2307. verifyCalls(t, fakeDocker, []string{
  2308. // Create pod infra container.
  2309. "create", "start", "inspect_container", "inspect_container",
  2310. // Create container.
  2311. "create", "start", "inspect_container",
  2312. })
  2313. }
  2314. // only test conditions "if inspect == nil || inspect.Config == nil || inspect.Config.Labels == nil" now
  2315. func TestContainerAndPodFromLabels(t *testing.T) {
  2316. tests := []struct {
  2317. inspect *dockertypes.ContainerJSON
  2318. expectedError error
  2319. }{
  2320. {
  2321. inspect: nil,
  2322. expectedError: errNoPodOnContainer,
  2323. },
  2324. {
  2325. inspect: &dockertypes.ContainerJSON{},
  2326. expectedError: errNoPodOnContainer,
  2327. },
  2328. {
  2329. inspect: &dockertypes.ContainerJSON{
  2330. Config: &dockercontainer.Config{
  2331. Hostname: "foo",
  2332. },
  2333. },
  2334. expectedError: errNoPodOnContainer,
  2335. },
  2336. }
  2337. for k, v := range tests {
  2338. pod, container, err := containerAndPodFromLabels(v.inspect)
  2339. if pod != nil || container != nil || err != v.expectedError {
  2340. t.Errorf("case[%q]: expected: nil, nil, %v, got: %v, %v, %v", k, v.expectedError, pod, container, err)
  2341. }
  2342. }
  2343. }