rkt_test.go 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938
  1. /*
  2. Copyright 2015 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 rkt
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "net"
  18. "os"
  19. "path/filepath"
  20. "sort"
  21. "testing"
  22. "time"
  23. appcschema "github.com/appc/spec/schema"
  24. appctypes "github.com/appc/spec/schema/types"
  25. rktapi "github.com/coreos/rkt/api/v1alpha"
  26. "github.com/golang/mock/gomock"
  27. "github.com/stretchr/testify/assert"
  28. "k8s.io/kubernetes/pkg/api"
  29. "k8s.io/kubernetes/pkg/api/resource"
  30. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  31. containertesting "k8s.io/kubernetes/pkg/kubelet/container/testing"
  32. kubetesting "k8s.io/kubernetes/pkg/kubelet/container/testing"
  33. "k8s.io/kubernetes/pkg/kubelet/lifecycle"
  34. "k8s.io/kubernetes/pkg/kubelet/network"
  35. "k8s.io/kubernetes/pkg/kubelet/network/kubenet"
  36. "k8s.io/kubernetes/pkg/kubelet/network/mock_network"
  37. "k8s.io/kubernetes/pkg/kubelet/rkt/mock_os"
  38. "k8s.io/kubernetes/pkg/kubelet/types"
  39. kubetypes "k8s.io/kubernetes/pkg/types"
  40. "k8s.io/kubernetes/pkg/util/errors"
  41. utilexec "k8s.io/kubernetes/pkg/util/exec"
  42. utiltesting "k8s.io/kubernetes/pkg/util/testing"
  43. )
  44. func mustMarshalPodManifest(man *appcschema.PodManifest) []byte {
  45. manblob, err := json.Marshal(man)
  46. if err != nil {
  47. panic(err)
  48. }
  49. return manblob
  50. }
  51. func mustMarshalImageManifest(man *appcschema.ImageManifest) []byte {
  52. manblob, err := json.Marshal(man)
  53. if err != nil {
  54. panic(err)
  55. }
  56. return manblob
  57. }
  58. func mustRktHash(hash string) *appctypes.Hash {
  59. h, err := appctypes.NewHash(hash)
  60. if err != nil {
  61. panic(err)
  62. }
  63. return h
  64. }
  65. func makeRktPod(rktPodState rktapi.PodState,
  66. rktPodID, podUID, podName, podNamespace string, podCreatedAt, podStartedAt int64,
  67. podRestartCount string, appNames, imgIDs, imgNames,
  68. containerHashes []string, appStates []rktapi.AppState,
  69. exitcodes []int32, ips map[string]string) *rktapi.Pod {
  70. podManifest := &appcschema.PodManifest{
  71. ACKind: appcschema.PodManifestKind,
  72. ACVersion: appcschema.AppContainerVersion,
  73. Annotations: appctypes.Annotations{
  74. appctypes.Annotation{
  75. Name: *appctypes.MustACIdentifier(k8sRktKubeletAnno),
  76. Value: k8sRktKubeletAnnoValue,
  77. },
  78. appctypes.Annotation{
  79. Name: *appctypes.MustACIdentifier(types.KubernetesPodUIDLabel),
  80. Value: podUID,
  81. },
  82. appctypes.Annotation{
  83. Name: *appctypes.MustACIdentifier(types.KubernetesPodNameLabel),
  84. Value: podName,
  85. },
  86. appctypes.Annotation{
  87. Name: *appctypes.MustACIdentifier(types.KubernetesPodNamespaceLabel),
  88. Value: podNamespace,
  89. },
  90. appctypes.Annotation{
  91. Name: *appctypes.MustACIdentifier(k8sRktRestartCountAnno),
  92. Value: podRestartCount,
  93. },
  94. },
  95. }
  96. appNum := len(appNames)
  97. if appNum != len(imgNames) ||
  98. appNum != len(imgIDs) ||
  99. appNum != len(containerHashes) ||
  100. appNum != len(appStates) {
  101. panic("inconsistent app number")
  102. }
  103. apps := make([]*rktapi.App, appNum)
  104. for i := range appNames {
  105. apps[i] = &rktapi.App{
  106. Name: appNames[i],
  107. State: appStates[i],
  108. Image: &rktapi.Image{
  109. Id: imgIDs[i],
  110. Name: imgNames[i],
  111. Version: "latest",
  112. Manifest: mustMarshalImageManifest(
  113. &appcschema.ImageManifest{
  114. ACKind: appcschema.ImageManifestKind,
  115. ACVersion: appcschema.AppContainerVersion,
  116. Name: *appctypes.MustACIdentifier(imgNames[i]),
  117. Annotations: appctypes.Annotations{
  118. appctypes.Annotation{
  119. Name: *appctypes.MustACIdentifier(k8sRktContainerHashAnno),
  120. Value: containerHashes[i],
  121. },
  122. },
  123. },
  124. ),
  125. },
  126. ExitCode: exitcodes[i],
  127. }
  128. podManifest.Apps = append(podManifest.Apps, appcschema.RuntimeApp{
  129. Name: *appctypes.MustACName(appNames[i]),
  130. Image: appcschema.RuntimeImage{ID: *mustRktHash("sha512-foo")},
  131. Annotations: appctypes.Annotations{
  132. appctypes.Annotation{
  133. Name: *appctypes.MustACIdentifier(k8sRktContainerHashAnno),
  134. Value: containerHashes[i],
  135. },
  136. },
  137. })
  138. }
  139. var networks []*rktapi.Network
  140. for name, ip := range ips {
  141. networks = append(networks, &rktapi.Network{Name: name, Ipv4: ip})
  142. }
  143. return &rktapi.Pod{
  144. Id: rktPodID,
  145. State: rktPodState,
  146. Apps: apps,
  147. Manifest: mustMarshalPodManifest(podManifest),
  148. StartedAt: podStartedAt,
  149. CreatedAt: podCreatedAt,
  150. Networks: networks,
  151. }
  152. }
  153. func TestCheckVersion(t *testing.T) {
  154. fr := newFakeRktInterface()
  155. fs := newFakeSystemd()
  156. r := &Runtime{apisvc: fr, systemd: fs}
  157. fr.info = rktapi.Info{
  158. RktVersion: "1.2.3+git",
  159. AppcVersion: "1.2.4+git",
  160. ApiVersion: "1.2.6-alpha",
  161. }
  162. fs.version = "100"
  163. tests := []struct {
  164. minimumRktBinVersion string
  165. recommendedRktBinVersion string
  166. minimumRktApiVersion string
  167. minimumSystemdVersion string
  168. err error
  169. calledGetInfo bool
  170. calledSystemVersion bool
  171. }{
  172. // Good versions.
  173. {
  174. "1.2.3",
  175. "1.2.3",
  176. "1.2.5",
  177. "99",
  178. nil,
  179. true,
  180. true,
  181. },
  182. // Good versions.
  183. {
  184. "1.2.3+git",
  185. "1.2.3+git",
  186. "1.2.6-alpha",
  187. "100",
  188. nil,
  189. true,
  190. true,
  191. },
  192. // Requires greater binary version.
  193. {
  194. "1.2.4",
  195. "1.2.4",
  196. "1.2.6-alpha",
  197. "100",
  198. fmt.Errorf("rkt: binary version is too old(%v), requires at least %v", fr.info.RktVersion, "1.2.4"),
  199. true,
  200. true,
  201. },
  202. // Requires greater API version.
  203. {
  204. "1.2.3",
  205. "1.2.3",
  206. "1.2.6",
  207. "100",
  208. fmt.Errorf("rkt: API version is too old(%v), requires at least %v", fr.info.ApiVersion, "1.2.6"),
  209. true,
  210. true,
  211. },
  212. // Requires greater API version.
  213. {
  214. "1.2.3",
  215. "1.2.3",
  216. "1.2.7",
  217. "100",
  218. fmt.Errorf("rkt: API version is too old(%v), requires at least %v", fr.info.ApiVersion, "1.2.7"),
  219. true,
  220. true,
  221. },
  222. // Requires greater systemd version.
  223. {
  224. "1.2.3",
  225. "1.2.3",
  226. "1.2.7",
  227. "101",
  228. fmt.Errorf("rkt: systemd version(%v) is too old, requires at least %v", fs.version, "101"),
  229. false,
  230. true,
  231. },
  232. }
  233. for i, tt := range tests {
  234. testCaseHint := fmt.Sprintf("test case #%d", i)
  235. err := r.checkVersion(tt.minimumRktBinVersion, tt.recommendedRktBinVersion, tt.minimumRktApiVersion, tt.minimumSystemdVersion)
  236. assert.Equal(t, tt.err, err, testCaseHint)
  237. if tt.calledGetInfo {
  238. assert.Equal(t, fr.called, []string{"GetInfo"}, testCaseHint)
  239. }
  240. if tt.calledSystemVersion {
  241. assert.Equal(t, fs.called, []string{"Version"}, testCaseHint)
  242. }
  243. if err == nil {
  244. assert.Equal(t, fr.info.RktVersion, r.versions.binVersion.String(), testCaseHint)
  245. assert.Equal(t, fr.info.ApiVersion, r.versions.apiVersion.String(), testCaseHint)
  246. }
  247. fr.CleanCalls()
  248. fs.CleanCalls()
  249. }
  250. }
  251. func TestListImages(t *testing.T) {
  252. fr := newFakeRktInterface()
  253. fs := newFakeSystemd()
  254. r := &Runtime{apisvc: fr, systemd: fs}
  255. tests := []struct {
  256. images []*rktapi.Image
  257. expected []kubecontainer.Image
  258. }{
  259. {nil, []kubecontainer.Image{}},
  260. {
  261. []*rktapi.Image{
  262. {
  263. Id: "sha512-a2fb8f390702",
  264. Name: "quay.io/coreos/alpine-sh",
  265. Version: "latest",
  266. },
  267. },
  268. []kubecontainer.Image{
  269. {
  270. ID: "sha512-a2fb8f390702",
  271. RepoTags: []string{"quay.io/coreos/alpine-sh:latest"},
  272. },
  273. },
  274. },
  275. {
  276. []*rktapi.Image{
  277. {
  278. Id: "sha512-a2fb8f390702",
  279. Name: "quay.io/coreos/alpine-sh",
  280. Version: "latest",
  281. Size: 400,
  282. },
  283. {
  284. Id: "sha512-c6b597f42816",
  285. Name: "coreos.com/rkt/stage1-coreos",
  286. Version: "0.10.0",
  287. Size: 400,
  288. },
  289. },
  290. []kubecontainer.Image{
  291. {
  292. ID: "sha512-a2fb8f390702",
  293. RepoTags: []string{"quay.io/coreos/alpine-sh:latest"},
  294. Size: 400,
  295. },
  296. {
  297. ID: "sha512-c6b597f42816",
  298. RepoTags: []string{"coreos.com/rkt/stage1-coreos:0.10.0"},
  299. Size: 400,
  300. },
  301. },
  302. },
  303. }
  304. for i, tt := range tests {
  305. fr.images = tt.images
  306. images, err := r.ListImages()
  307. if err != nil {
  308. t.Errorf("%v", err)
  309. }
  310. assert.Equal(t, tt.expected, images)
  311. assert.Equal(t, fr.called, []string{"ListImages"}, fmt.Sprintf("test case %d: unexpected called list", i))
  312. fr.CleanCalls()
  313. }
  314. }
  315. func TestGetPods(t *testing.T) {
  316. fr := newFakeRktInterface()
  317. fs := newFakeSystemd()
  318. r := &Runtime{apisvc: fr, systemd: fs}
  319. ns := func(seconds int64) int64 {
  320. return seconds * 1e9
  321. }
  322. tests := []struct {
  323. pods []*rktapi.Pod
  324. result []*kubecontainer.Pod
  325. }{
  326. // No pods.
  327. {},
  328. // One pod.
  329. {
  330. []*rktapi.Pod{
  331. makeRktPod(rktapi.PodState_POD_STATE_RUNNING,
  332. "uuid-4002", "42", "guestbook", "default",
  333. ns(10), ns(10), "7",
  334. []string{"app-1", "app-2"},
  335. []string{"img-id-1", "img-id-2"},
  336. []string{"img-name-1", "img-name-2"},
  337. []string{"1001", "1002"},
  338. []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
  339. []int32{0, 0},
  340. nil,
  341. ),
  342. },
  343. []*kubecontainer.Pod{
  344. {
  345. ID: "42",
  346. Name: "guestbook",
  347. Namespace: "default",
  348. Containers: []*kubecontainer.Container{
  349. {
  350. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"),
  351. Name: "app-1",
  352. Image: "img-name-1:latest",
  353. ImageID: "img-id-1",
  354. Hash: 1001,
  355. State: "running",
  356. },
  357. {
  358. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"),
  359. Name: "app-2",
  360. Image: "img-name-2:latest",
  361. ImageID: "img-id-2",
  362. Hash: 1002,
  363. State: "exited",
  364. },
  365. },
  366. },
  367. },
  368. },
  369. // Multiple pods.
  370. {
  371. []*rktapi.Pod{
  372. makeRktPod(rktapi.PodState_POD_STATE_RUNNING,
  373. "uuid-4002", "42", "guestbook", "default",
  374. ns(10), ns(20), "7",
  375. []string{"app-1", "app-2"},
  376. []string{"img-id-1", "img-id-2"},
  377. []string{"img-name-1", "img-name-2"},
  378. []string{"1001", "1002"},
  379. []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
  380. []int32{0, 0},
  381. nil,
  382. ),
  383. makeRktPod(rktapi.PodState_POD_STATE_EXITED,
  384. "uuid-4003", "43", "guestbook", "default",
  385. ns(30), ns(40), "7",
  386. []string{"app-11", "app-22"},
  387. []string{"img-id-11", "img-id-22"},
  388. []string{"img-name-11", "img-name-22"},
  389. []string{"10011", "10022"},
  390. []rktapi.AppState{rktapi.AppState_APP_STATE_EXITED, rktapi.AppState_APP_STATE_EXITED},
  391. []int32{0, 0},
  392. nil,
  393. ),
  394. makeRktPod(rktapi.PodState_POD_STATE_EXITED,
  395. "uuid-4004", "43", "guestbook", "default",
  396. ns(50), ns(60), "8",
  397. []string{"app-11", "app-22"},
  398. []string{"img-id-11", "img-id-22"},
  399. []string{"img-name-11", "img-name-22"},
  400. []string{"10011", "10022"},
  401. []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_RUNNING},
  402. []int32{0, 0},
  403. nil,
  404. ),
  405. },
  406. []*kubecontainer.Pod{
  407. {
  408. ID: "42",
  409. Name: "guestbook",
  410. Namespace: "default",
  411. Containers: []*kubecontainer.Container{
  412. {
  413. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"),
  414. Name: "app-1",
  415. Image: "img-name-1:latest",
  416. ImageID: "img-id-1",
  417. Hash: 1001,
  418. State: "running",
  419. },
  420. {
  421. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"),
  422. Name: "app-2",
  423. Image: "img-name-2:latest",
  424. ImageID: "img-id-2",
  425. Hash: 1002,
  426. State: "exited",
  427. },
  428. },
  429. },
  430. {
  431. ID: "43",
  432. Name: "guestbook",
  433. Namespace: "default",
  434. Containers: []*kubecontainer.Container{
  435. {
  436. ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-11"),
  437. Name: "app-11",
  438. Image: "img-name-11:latest",
  439. ImageID: "img-id-11",
  440. Hash: 10011,
  441. State: "exited",
  442. },
  443. {
  444. ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-22"),
  445. Name: "app-22",
  446. Image: "img-name-22:latest",
  447. ImageID: "img-id-22",
  448. Hash: 10022,
  449. State: "exited",
  450. },
  451. {
  452. ID: kubecontainer.BuildContainerID("rkt", "uuid-4004:app-11"),
  453. Name: "app-11",
  454. Image: "img-name-11:latest",
  455. ImageID: "img-id-11",
  456. Hash: 10011,
  457. State: "running",
  458. },
  459. {
  460. ID: kubecontainer.BuildContainerID("rkt", "uuid-4004:app-22"),
  461. Name: "app-22",
  462. Image: "img-name-22:latest",
  463. ImageID: "img-id-22",
  464. Hash: 10022,
  465. State: "running",
  466. },
  467. },
  468. },
  469. },
  470. },
  471. }
  472. for i, tt := range tests {
  473. testCaseHint := fmt.Sprintf("test case #%d", i)
  474. fr.pods = tt.pods
  475. pods, err := r.GetPods(true)
  476. if err != nil {
  477. t.Errorf("test case #%d: unexpected error: %v", i, err)
  478. }
  479. assert.Equal(t, tt.result, pods, testCaseHint)
  480. assert.Equal(t, []string{"ListPods"}, fr.called, fmt.Sprintf("test case %d: unexpected called list", i))
  481. fr.CleanCalls()
  482. }
  483. }
  484. func TestGetPodsFilters(t *testing.T) {
  485. fr := newFakeRktInterface()
  486. fs := newFakeSystemd()
  487. r := &Runtime{apisvc: fr, systemd: fs}
  488. for _, test := range []struct {
  489. All bool
  490. ExpectedFilters []*rktapi.PodFilter
  491. }{
  492. {
  493. true,
  494. []*rktapi.PodFilter{
  495. {
  496. Annotations: []*rktapi.KeyValue{
  497. {
  498. Key: k8sRktKubeletAnno,
  499. Value: k8sRktKubeletAnnoValue,
  500. },
  501. },
  502. },
  503. },
  504. },
  505. {
  506. false,
  507. []*rktapi.PodFilter{
  508. {
  509. States: []rktapi.PodState{rktapi.PodState_POD_STATE_RUNNING},
  510. Annotations: []*rktapi.KeyValue{
  511. {
  512. Key: k8sRktKubeletAnno,
  513. Value: k8sRktKubeletAnnoValue,
  514. },
  515. },
  516. },
  517. },
  518. },
  519. } {
  520. _, err := r.GetPods(test.All)
  521. if err != nil {
  522. t.Errorf("%v", err)
  523. }
  524. assert.Equal(t, test.ExpectedFilters, fr.podFilters, "filters didn't match when all=%b", test.All)
  525. }
  526. }
  527. func TestGetPodStatus(t *testing.T) {
  528. ctrl := gomock.NewController(t)
  529. defer ctrl.Finish()
  530. fr := newFakeRktInterface()
  531. fs := newFakeSystemd()
  532. fnp := mock_network.NewMockNetworkPlugin(ctrl)
  533. fos := &containertesting.FakeOS{}
  534. frh := &fakeRuntimeHelper{}
  535. r := &Runtime{
  536. apisvc: fr,
  537. systemd: fs,
  538. runtimeHelper: frh,
  539. os: fos,
  540. networkPlugin: fnp,
  541. }
  542. ns := func(seconds int64) int64 {
  543. return seconds * 1e9
  544. }
  545. tests := []struct {
  546. networkPluginName string
  547. pods []*rktapi.Pod
  548. result *kubecontainer.PodStatus
  549. }{
  550. // # case 0, No pods.
  551. {
  552. kubenet.KubenetPluginName,
  553. nil,
  554. &kubecontainer.PodStatus{ID: "42", Name: "guestbook", Namespace: "default"},
  555. },
  556. // # case 1, One pod.
  557. {
  558. kubenet.KubenetPluginName,
  559. []*rktapi.Pod{
  560. makeRktPod(rktapi.PodState_POD_STATE_RUNNING,
  561. "uuid-4002", "42", "guestbook", "default",
  562. ns(10), ns(20), "7",
  563. []string{"app-1", "app-2"},
  564. []string{"img-id-1", "img-id-2"},
  565. []string{"img-name-1", "img-name-2"},
  566. []string{"1001", "1002"},
  567. []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
  568. []int32{0, 0},
  569. nil,
  570. ),
  571. },
  572. &kubecontainer.PodStatus{
  573. ID: "42",
  574. Name: "guestbook",
  575. Namespace: "default",
  576. IP: "10.10.10.42",
  577. ContainerStatuses: []*kubecontainer.ContainerStatus{
  578. {
  579. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"),
  580. Name: "app-1",
  581. State: kubecontainer.ContainerStateRunning,
  582. CreatedAt: time.Unix(10, 0),
  583. StartedAt: time.Unix(20, 0),
  584. FinishedAt: time.Unix(0, 30),
  585. Image: "img-name-1:latest",
  586. ImageID: "rkt://img-id-1",
  587. Hash: 1001,
  588. RestartCount: 7,
  589. },
  590. {
  591. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"),
  592. Name: "app-2",
  593. State: kubecontainer.ContainerStateExited,
  594. CreatedAt: time.Unix(10, 0),
  595. StartedAt: time.Unix(20, 0),
  596. FinishedAt: time.Unix(0, 30),
  597. Image: "img-name-2:latest",
  598. ImageID: "rkt://img-id-2",
  599. Hash: 1002,
  600. RestartCount: 7,
  601. Reason: "Completed",
  602. },
  603. },
  604. },
  605. },
  606. // # case 2, One pod with no-op network plugin name.
  607. {
  608. network.DefaultPluginName,
  609. []*rktapi.Pod{
  610. makeRktPod(rktapi.PodState_POD_STATE_RUNNING,
  611. "uuid-4002", "42", "guestbook", "default",
  612. ns(10), ns(20), "7",
  613. []string{"app-1", "app-2"},
  614. []string{"img-id-1", "img-id-2"},
  615. []string{"img-name-1", "img-name-2"},
  616. []string{"1001", "1002"},
  617. []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
  618. []int32{0, 0},
  619. map[string]string{defaultNetworkName: "10.10.10.22"},
  620. ),
  621. },
  622. &kubecontainer.PodStatus{
  623. ID: "42",
  624. Name: "guestbook",
  625. Namespace: "default",
  626. IP: "10.10.10.22",
  627. ContainerStatuses: []*kubecontainer.ContainerStatus{
  628. {
  629. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"),
  630. Name: "app-1",
  631. State: kubecontainer.ContainerStateRunning,
  632. CreatedAt: time.Unix(10, 0),
  633. StartedAt: time.Unix(20, 0),
  634. FinishedAt: time.Unix(0, 30),
  635. Image: "img-name-1:latest",
  636. ImageID: "rkt://img-id-1",
  637. Hash: 1001,
  638. RestartCount: 7,
  639. },
  640. {
  641. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"),
  642. Name: "app-2",
  643. State: kubecontainer.ContainerStateExited,
  644. CreatedAt: time.Unix(10, 0),
  645. StartedAt: time.Unix(20, 0),
  646. FinishedAt: time.Unix(0, 30),
  647. Image: "img-name-2:latest",
  648. ImageID: "rkt://img-id-2",
  649. Hash: 1002,
  650. RestartCount: 7,
  651. Reason: "Completed",
  652. },
  653. },
  654. },
  655. },
  656. // # case 3, Multiple pods.
  657. {
  658. kubenet.KubenetPluginName,
  659. []*rktapi.Pod{
  660. makeRktPod(rktapi.PodState_POD_STATE_EXITED,
  661. "uuid-4002", "42", "guestbook", "default",
  662. ns(10), ns(20), "7",
  663. []string{"app-1", "app-2"},
  664. []string{"img-id-1", "img-id-2"},
  665. []string{"img-name-1", "img-name-2"},
  666. []string{"1001", "1002"},
  667. []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
  668. []int32{0, 0},
  669. nil,
  670. ),
  671. makeRktPod(rktapi.PodState_POD_STATE_RUNNING, // The latest pod is running.
  672. "uuid-4003", "42", "guestbook", "default",
  673. ns(10), ns(20), "10",
  674. []string{"app-1", "app-2"},
  675. []string{"img-id-1", "img-id-2"},
  676. []string{"img-name-1", "img-name-2"},
  677. []string{"1001", "1002"},
  678. []rktapi.AppState{rktapi.AppState_APP_STATE_RUNNING, rktapi.AppState_APP_STATE_EXITED},
  679. []int32{0, 1},
  680. nil,
  681. ),
  682. },
  683. &kubecontainer.PodStatus{
  684. ID: "42",
  685. Name: "guestbook",
  686. Namespace: "default",
  687. IP: "10.10.10.42",
  688. // Result should contain all containers.
  689. ContainerStatuses: []*kubecontainer.ContainerStatus{
  690. {
  691. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-1"),
  692. Name: "app-1",
  693. State: kubecontainer.ContainerStateRunning,
  694. CreatedAt: time.Unix(10, 0),
  695. StartedAt: time.Unix(20, 0),
  696. FinishedAt: time.Unix(0, 30),
  697. Image: "img-name-1:latest",
  698. ImageID: "rkt://img-id-1",
  699. Hash: 1001,
  700. RestartCount: 7,
  701. },
  702. {
  703. ID: kubecontainer.BuildContainerID("rkt", "uuid-4002:app-2"),
  704. Name: "app-2",
  705. State: kubecontainer.ContainerStateExited,
  706. CreatedAt: time.Unix(10, 0),
  707. StartedAt: time.Unix(20, 0),
  708. FinishedAt: time.Unix(0, 30),
  709. Image: "img-name-2:latest",
  710. ImageID: "rkt://img-id-2",
  711. Hash: 1002,
  712. RestartCount: 7,
  713. Reason: "Completed",
  714. },
  715. {
  716. ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-1"),
  717. Name: "app-1",
  718. State: kubecontainer.ContainerStateRunning,
  719. CreatedAt: time.Unix(10, 0),
  720. StartedAt: time.Unix(20, 0),
  721. FinishedAt: time.Unix(0, 30),
  722. Image: "img-name-1:latest",
  723. ImageID: "rkt://img-id-1",
  724. Hash: 1001,
  725. RestartCount: 10,
  726. },
  727. {
  728. ID: kubecontainer.BuildContainerID("rkt", "uuid-4003:app-2"),
  729. Name: "app-2",
  730. State: kubecontainer.ContainerStateExited,
  731. CreatedAt: time.Unix(10, 0),
  732. StartedAt: time.Unix(20, 0),
  733. FinishedAt: time.Unix(0, 30),
  734. Image: "img-name-2:latest",
  735. ImageID: "rkt://img-id-2",
  736. Hash: 1002,
  737. RestartCount: 10,
  738. ExitCode: 1,
  739. Reason: "Error",
  740. },
  741. },
  742. },
  743. },
  744. }
  745. for i, tt := range tests {
  746. testCaseHint := fmt.Sprintf("test case #%d", i)
  747. fr.pods = tt.pods
  748. podTimes := map[string]time.Time{}
  749. for _, pod := range tt.pods {
  750. podTimes[podFinishedMarkerPath(r.runtimeHelper.GetPodDir(tt.result.ID), pod.Id)] = tt.result.ContainerStatuses[0].FinishedAt
  751. }
  752. r.os.(*containertesting.FakeOS).StatFn = func(name string) (os.FileInfo, error) {
  753. podTime, ok := podTimes[name]
  754. if !ok {
  755. t.Errorf("osStat called with %v, but only knew about %#v", name, podTimes)
  756. }
  757. mockFI := mock_os.NewMockFileInfo(ctrl)
  758. mockFI.EXPECT().ModTime().Return(podTime)
  759. return mockFI, nil
  760. }
  761. fnp.EXPECT().Name().Return(tt.networkPluginName)
  762. if tt.networkPluginName == kubenet.KubenetPluginName {
  763. if tt.result.IP != "" {
  764. fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}).
  765. Return(&network.PodNetworkStatus{IP: net.ParseIP(tt.result.IP)}, nil)
  766. } else {
  767. fnp.EXPECT().GetPodNetworkStatus("default", "guestbook", kubecontainer.ContainerID{ID: "42"}).
  768. Return(nil, fmt.Errorf("no such network"))
  769. }
  770. }
  771. status, err := r.GetPodStatus("42", "guestbook", "default")
  772. if err != nil {
  773. t.Errorf("test case #%d: unexpected error: %v", i, err)
  774. }
  775. assert.Equal(t, tt.result, status, testCaseHint)
  776. assert.Equal(t, []string{"ListPods"}, fr.called, testCaseHint)
  777. fr.CleanCalls()
  778. }
  779. }
  780. func generateCapRetainIsolator(t *testing.T, caps ...string) appctypes.Isolator {
  781. retain, err := appctypes.NewLinuxCapabilitiesRetainSet(caps...)
  782. if err != nil {
  783. t.Fatalf("Error generating cap retain isolator: %v", err)
  784. }
  785. return retain.AsIsolator()
  786. }
  787. func generateCapRevokeIsolator(t *testing.T, caps ...string) appctypes.Isolator {
  788. revoke, err := appctypes.NewLinuxCapabilitiesRevokeSet(caps...)
  789. if err != nil {
  790. t.Fatalf("Error generating cap revoke isolator: %v", err)
  791. }
  792. return revoke.AsIsolator()
  793. }
  794. func generateCPUIsolator(t *testing.T, request, limit string) appctypes.Isolator {
  795. cpu, err := appctypes.NewResourceCPUIsolator(request, limit)
  796. if err != nil {
  797. t.Fatalf("Error generating cpu resource isolator: %v", err)
  798. }
  799. return cpu.AsIsolator()
  800. }
  801. func generateMemoryIsolator(t *testing.T, request, limit string) appctypes.Isolator {
  802. memory, err := appctypes.NewResourceMemoryIsolator(request, limit)
  803. if err != nil {
  804. t.Fatalf("Error generating memory resource isolator: %v", err)
  805. }
  806. return memory.AsIsolator()
  807. }
  808. func baseApp(t *testing.T) *appctypes.App {
  809. return &appctypes.App{
  810. User: "0",
  811. Group: "0",
  812. Exec: appctypes.Exec{"/bin/foo", "bar"},
  813. SupplementaryGIDs: []int{4, 5, 6},
  814. WorkingDirectory: "/foo",
  815. Environment: []appctypes.EnvironmentVariable{
  816. {Name: "env-foo", Value: "bar"},
  817. },
  818. MountPoints: []appctypes.MountPoint{
  819. {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: false},
  820. },
  821. Ports: []appctypes.Port{
  822. {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 4242},
  823. },
  824. Isolators: []appctypes.Isolator{
  825. generateCapRetainIsolator(t, "CAP_SYS_ADMIN"),
  826. generateCapRevokeIsolator(t, "CAP_NET_ADMIN"),
  827. generateCPUIsolator(t, "100m", "200m"),
  828. generateMemoryIsolator(t, "10M", "20M"),
  829. },
  830. }
  831. }
  832. func baseImageManifest(t *testing.T) *appcschema.ImageManifest {
  833. img := &appcschema.ImageManifest{App: baseApp(t)}
  834. entrypoint, err := json.Marshal([]string{"/bin/foo"})
  835. if err != nil {
  836. t.Fatal(err)
  837. }
  838. cmd, err := json.Marshal([]string{"bar"})
  839. if err != nil {
  840. t.Fatal(err)
  841. }
  842. img.Annotations.Set(*appctypes.MustACIdentifier(appcDockerEntrypoint), string(entrypoint))
  843. img.Annotations.Set(*appctypes.MustACIdentifier(appcDockerCmd), string(cmd))
  844. return img
  845. }
  846. func baseAppWithRootUserGroup(t *testing.T) *appctypes.App {
  847. app := baseApp(t)
  848. app.User, app.Group = "0", "0"
  849. return app
  850. }
  851. type envByName []appctypes.EnvironmentVariable
  852. func (s envByName) Len() int { return len(s) }
  853. func (s envByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
  854. func (s envByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  855. type mountsByName []appctypes.MountPoint
  856. func (s mountsByName) Len() int { return len(s) }
  857. func (s mountsByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
  858. func (s mountsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  859. type portsByName []appctypes.Port
  860. func (s portsByName) Len() int { return len(s) }
  861. func (s portsByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
  862. func (s portsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  863. type isolatorsByName []appctypes.Isolator
  864. func (s isolatorsByName) Len() int { return len(s) }
  865. func (s isolatorsByName) Less(i, j int) bool { return s[i].Name < s[j].Name }
  866. func (s isolatorsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  867. func sortAppFields(app *appctypes.App) {
  868. sort.Sort(envByName(app.Environment))
  869. sort.Sort(mountsByName(app.MountPoints))
  870. sort.Sort(portsByName(app.Ports))
  871. sort.Sort(isolatorsByName(app.Isolators))
  872. }
  873. type sortedStringList []string
  874. func (s sortedStringList) Len() int { return len(s) }
  875. func (s sortedStringList) Less(i, j int) bool { return s[i] < s[j] }
  876. func (s sortedStringList) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  877. func TestSetApp(t *testing.T) {
  878. tmpDir, err := utiltesting.MkTmpdir("rkt_test")
  879. if err != nil {
  880. t.Fatalf("error creating temp dir: %v", err)
  881. }
  882. defer os.RemoveAll(tmpDir)
  883. rootUser := int64(0)
  884. nonRootUser := int64(42)
  885. runAsNonRootTrue := true
  886. fsgid := int64(3)
  887. tests := []struct {
  888. container *api.Container
  889. mountPoints []appctypes.MountPoint
  890. containerPorts []appctypes.Port
  891. envs []kubecontainer.EnvVar
  892. ctx *api.SecurityContext
  893. podCtx *api.PodSecurityContext
  894. supplementalGids []int64
  895. expect *appctypes.App
  896. err error
  897. }{
  898. // Nothing should change, but the "User" and "Group" should be filled.
  899. {
  900. container: &api.Container{},
  901. mountPoints: []appctypes.MountPoint{},
  902. containerPorts: []appctypes.Port{},
  903. envs: []kubecontainer.EnvVar{},
  904. ctx: nil,
  905. podCtx: nil,
  906. supplementalGids: nil,
  907. expect: baseAppWithRootUserGroup(t),
  908. err: nil,
  909. },
  910. // error verifying non-root.
  911. {
  912. container: &api.Container{},
  913. mountPoints: []appctypes.MountPoint{},
  914. containerPorts: []appctypes.Port{},
  915. envs: []kubecontainer.EnvVar{},
  916. ctx: &api.SecurityContext{
  917. RunAsNonRoot: &runAsNonRootTrue,
  918. RunAsUser: &rootUser,
  919. },
  920. podCtx: nil,
  921. supplementalGids: nil,
  922. expect: nil,
  923. err: fmt.Errorf("container has no runAsUser and image will run as root"),
  924. },
  925. // app's args should be changed.
  926. {
  927. container: &api.Container{
  928. Args: []string{"foo"},
  929. },
  930. mountPoints: []appctypes.MountPoint{},
  931. containerPorts: []appctypes.Port{},
  932. envs: []kubecontainer.EnvVar{},
  933. ctx: nil,
  934. podCtx: nil,
  935. supplementalGids: nil,
  936. expect: &appctypes.App{
  937. Exec: appctypes.Exec{"/bin/foo", "foo"},
  938. User: "0",
  939. Group: "0",
  940. SupplementaryGIDs: []int{4, 5, 6},
  941. WorkingDirectory: "/foo",
  942. Environment: []appctypes.EnvironmentVariable{
  943. {Name: "env-foo", Value: "bar"},
  944. },
  945. MountPoints: []appctypes.MountPoint{
  946. {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: false},
  947. },
  948. Ports: []appctypes.Port{
  949. {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 4242},
  950. },
  951. Isolators: []appctypes.Isolator{
  952. generateCapRetainIsolator(t, "CAP_SYS_ADMIN"),
  953. generateCapRevokeIsolator(t, "CAP_NET_ADMIN"),
  954. generateCPUIsolator(t, "100m", "200m"),
  955. generateMemoryIsolator(t, "10M", "20M"),
  956. },
  957. },
  958. err: nil,
  959. },
  960. // app should be changed.
  961. {
  962. container: &api.Container{
  963. Command: []string{"/bin/bar", "$(env-bar)"},
  964. WorkingDir: tmpDir,
  965. Resources: api.ResourceRequirements{
  966. Limits: api.ResourceList{"cpu": resource.MustParse("50m"), "memory": resource.MustParse("50M")},
  967. Requests: api.ResourceList{"cpu": resource.MustParse("5m"), "memory": resource.MustParse("5M")},
  968. },
  969. },
  970. mountPoints: []appctypes.MountPoint{
  971. {Name: *appctypes.MustACName("mnt-bar"), Path: "/mnt-bar", ReadOnly: true},
  972. },
  973. containerPorts: []appctypes.Port{
  974. {Name: *appctypes.MustACName("port-bar"), Protocol: "TCP", Port: 1234},
  975. },
  976. envs: []kubecontainer.EnvVar{
  977. {Name: "env-bar", Value: "foo"},
  978. },
  979. ctx: &api.SecurityContext{
  980. Capabilities: &api.Capabilities{
  981. Add: []api.Capability{"CAP_SYS_CHROOT", "CAP_SYS_BOOT"},
  982. Drop: []api.Capability{"CAP_SETUID", "CAP_SETGID"},
  983. },
  984. RunAsUser: &nonRootUser,
  985. RunAsNonRoot: &runAsNonRootTrue,
  986. },
  987. podCtx: &api.PodSecurityContext{
  988. SupplementalGroups: []int64{1, 2},
  989. FSGroup: &fsgid,
  990. },
  991. supplementalGids: []int64{4},
  992. expect: &appctypes.App{
  993. Exec: appctypes.Exec{"/bin/bar", "foo"},
  994. User: "42",
  995. Group: "0",
  996. SupplementaryGIDs: []int{1, 2, 3, 4},
  997. WorkingDirectory: tmpDir,
  998. Environment: []appctypes.EnvironmentVariable{
  999. {Name: "env-foo", Value: "bar"},
  1000. {Name: "env-bar", Value: "foo"},
  1001. },
  1002. MountPoints: []appctypes.MountPoint{
  1003. {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: false},
  1004. {Name: *appctypes.MustACName("mnt-bar"), Path: "/mnt-bar", ReadOnly: true},
  1005. },
  1006. Ports: []appctypes.Port{
  1007. {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 4242},
  1008. {Name: *appctypes.MustACName("port-bar"), Protocol: "TCP", Port: 1234},
  1009. },
  1010. Isolators: []appctypes.Isolator{
  1011. generateCapRetainIsolator(t, "CAP_SYS_CHROOT", "CAP_SYS_BOOT"),
  1012. generateCapRevokeIsolator(t, "CAP_SETUID", "CAP_SETGID"),
  1013. generateCPUIsolator(t, "5m", "50m"),
  1014. generateMemoryIsolator(t, "5M", "50M"),
  1015. },
  1016. },
  1017. },
  1018. // app should be changed. (env, mounts, ports, are overrided).
  1019. {
  1020. container: &api.Container{
  1021. Name: "hello-world",
  1022. Command: []string{"/bin/hello", "$(env-foo)"},
  1023. Args: []string{"hello", "world", "$(env-bar)"},
  1024. WorkingDir: tmpDir,
  1025. Resources: api.ResourceRequirements{
  1026. Limits: api.ResourceList{"cpu": resource.MustParse("50m")},
  1027. Requests: api.ResourceList{"memory": resource.MustParse("5M")},
  1028. },
  1029. },
  1030. mountPoints: []appctypes.MountPoint{
  1031. {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: true},
  1032. },
  1033. containerPorts: []appctypes.Port{
  1034. {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 1234},
  1035. },
  1036. envs: []kubecontainer.EnvVar{
  1037. {Name: "env-foo", Value: "foo"},
  1038. {Name: "env-bar", Value: "bar"},
  1039. },
  1040. ctx: &api.SecurityContext{
  1041. Capabilities: &api.Capabilities{
  1042. Add: []api.Capability{"CAP_SYS_CHROOT", "CAP_SYS_BOOT"},
  1043. Drop: []api.Capability{"CAP_SETUID", "CAP_SETGID"},
  1044. },
  1045. RunAsUser: &nonRootUser,
  1046. RunAsNonRoot: &runAsNonRootTrue,
  1047. },
  1048. podCtx: &api.PodSecurityContext{
  1049. SupplementalGroups: []int64{1, 2},
  1050. FSGroup: &fsgid,
  1051. },
  1052. supplementalGids: []int64{4},
  1053. expect: &appctypes.App{
  1054. Exec: appctypes.Exec{"/bin/hello", "foo", "hello", "world", "bar"},
  1055. User: "42",
  1056. Group: "0",
  1057. SupplementaryGIDs: []int{1, 2, 3, 4},
  1058. WorkingDirectory: tmpDir,
  1059. Environment: []appctypes.EnvironmentVariable{
  1060. {Name: "env-foo", Value: "foo"},
  1061. {Name: "env-bar", Value: "bar"},
  1062. },
  1063. MountPoints: []appctypes.MountPoint{
  1064. {Name: *appctypes.MustACName("mnt-foo"), Path: "/mnt-foo", ReadOnly: true},
  1065. },
  1066. Ports: []appctypes.Port{
  1067. {Name: *appctypes.MustACName("port-foo"), Protocol: "TCP", Port: 1234},
  1068. },
  1069. Isolators: []appctypes.Isolator{
  1070. generateCapRetainIsolator(t, "CAP_SYS_CHROOT", "CAP_SYS_BOOT"),
  1071. generateCapRevokeIsolator(t, "CAP_SETUID", "CAP_SETGID"),
  1072. generateCPUIsolator(t, "50m", "50m"),
  1073. generateMemoryIsolator(t, "5M", "5M"),
  1074. },
  1075. },
  1076. },
  1077. }
  1078. for i, tt := range tests {
  1079. testCaseHint := fmt.Sprintf("test case #%d", i)
  1080. img := baseImageManifest(t)
  1081. err := setApp(img, tt.container,
  1082. tt.mountPoints, tt.containerPorts, tt.envs,
  1083. tt.ctx, tt.podCtx, tt.supplementalGids)
  1084. if err == nil && tt.err != nil || err != nil && tt.err == nil {
  1085. t.Errorf("%s: expect %v, saw %v", testCaseHint, tt.err, err)
  1086. }
  1087. if err == nil {
  1088. sortAppFields(tt.expect)
  1089. sortAppFields(img.App)
  1090. assert.Equal(t, tt.expect, img.App, testCaseHint)
  1091. }
  1092. }
  1093. }
  1094. func TestGenerateRunCommand(t *testing.T) {
  1095. hostName := "test-hostname"
  1096. boolTrue := true
  1097. boolFalse := false
  1098. tests := []struct {
  1099. networkPlugin network.NetworkPlugin
  1100. pod *api.Pod
  1101. uuid string
  1102. netnsName string
  1103. dnsServers []string
  1104. dnsSearches []string
  1105. hostName string
  1106. err error
  1107. expect string
  1108. }{
  1109. // Case #0, returns error.
  1110. {
  1111. kubenet.NewPlugin("/tmp"),
  1112. &api.Pod{
  1113. ObjectMeta: api.ObjectMeta{
  1114. Name: "pod-name-foo",
  1115. },
  1116. Spec: api.PodSpec{
  1117. Containers: []api.Container{{Name: "container-foo"}},
  1118. },
  1119. },
  1120. "rkt-uuid-foo",
  1121. "default",
  1122. []string{},
  1123. []string{},
  1124. "",
  1125. fmt.Errorf("failed to get cluster dns"),
  1126. "",
  1127. },
  1128. // Case #1, returns no dns, with private-net.
  1129. {
  1130. kubenet.NewPlugin("/tmp"),
  1131. &api.Pod{
  1132. ObjectMeta: api.ObjectMeta{
  1133. Name: "pod-name-foo",
  1134. },
  1135. Spec: api.PodSpec{
  1136. Containers: []api.Container{{Name: "container-foo"}},
  1137. },
  1138. },
  1139. "rkt-uuid-foo",
  1140. "default",
  1141. []string{},
  1142. []string{},
  1143. "pod-hostname-foo",
  1144. nil,
  1145. "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo",
  1146. },
  1147. // Case #2, returns no dns, with host-net.
  1148. {
  1149. kubenet.NewPlugin("/tmp"),
  1150. &api.Pod{
  1151. ObjectMeta: api.ObjectMeta{
  1152. Name: "pod-name-foo",
  1153. },
  1154. Spec: api.PodSpec{
  1155. SecurityContext: &api.PodSecurityContext{
  1156. HostNetwork: true,
  1157. },
  1158. Containers: []api.Container{{Name: "container-foo"}},
  1159. },
  1160. },
  1161. "rkt-uuid-foo",
  1162. "",
  1163. []string{},
  1164. []string{},
  1165. "",
  1166. nil,
  1167. fmt.Sprintf("/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=%s rkt-uuid-foo", hostName),
  1168. },
  1169. // Case #3, returns dns, dns searches, with private-net.
  1170. {
  1171. kubenet.NewPlugin("/tmp"),
  1172. &api.Pod{
  1173. ObjectMeta: api.ObjectMeta{
  1174. Name: "pod-name-foo",
  1175. },
  1176. Spec: api.PodSpec{
  1177. SecurityContext: &api.PodSecurityContext{
  1178. HostNetwork: false,
  1179. },
  1180. Containers: []api.Container{{Name: "container-foo"}},
  1181. },
  1182. },
  1183. "rkt-uuid-foo",
  1184. "default",
  1185. []string{"127.0.0.1"},
  1186. []string{"."},
  1187. "pod-hostname-foo",
  1188. nil,
  1189. "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --dns=127.0.0.1 --dns-search=. --dns-opt=ndots:5 --hostname=pod-hostname-foo rkt-uuid-foo",
  1190. },
  1191. // Case #4, returns no dns, dns searches, with host-network.
  1192. {
  1193. kubenet.NewPlugin("/tmp"),
  1194. &api.Pod{
  1195. ObjectMeta: api.ObjectMeta{
  1196. Name: "pod-name-foo",
  1197. },
  1198. Spec: api.PodSpec{
  1199. SecurityContext: &api.PodSecurityContext{
  1200. HostNetwork: true,
  1201. },
  1202. Containers: []api.Container{{Name: "container-foo"}},
  1203. },
  1204. },
  1205. "rkt-uuid-foo",
  1206. "",
  1207. []string{"127.0.0.1"},
  1208. []string{"."},
  1209. "pod-hostname-foo",
  1210. nil,
  1211. fmt.Sprintf("/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=%s rkt-uuid-foo", hostName),
  1212. },
  1213. // Case #5, with no-op plugin, returns --net=rkt.kubernetes.io, with dns and dns search.
  1214. {
  1215. &network.NoopNetworkPlugin{},
  1216. &api.Pod{
  1217. ObjectMeta: api.ObjectMeta{
  1218. Name: "pod-name-foo",
  1219. },
  1220. Spec: api.PodSpec{
  1221. Containers: []api.Container{{Name: "container-foo"}},
  1222. },
  1223. },
  1224. "rkt-uuid-foo",
  1225. "default",
  1226. []string{"127.0.0.1"},
  1227. []string{"."},
  1228. "pod-hostname-foo",
  1229. nil,
  1230. "/bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=rkt.kubernetes.io --dns=127.0.0.1 --dns-search=. --dns-opt=ndots:5 --hostname=pod-hostname-foo rkt-uuid-foo",
  1231. },
  1232. // Case #6, if all containers are privileged, the result should have 'insecure-options=all-run'
  1233. {
  1234. kubenet.NewPlugin("/tmp"),
  1235. &api.Pod{
  1236. ObjectMeta: api.ObjectMeta{
  1237. Name: "pod-name-foo",
  1238. },
  1239. Spec: api.PodSpec{
  1240. Containers: []api.Container{
  1241. {Name: "container-foo", SecurityContext: &api.SecurityContext{Privileged: &boolTrue}},
  1242. {Name: "container-bar", SecurityContext: &api.SecurityContext{Privileged: &boolTrue}},
  1243. },
  1244. },
  1245. },
  1246. "rkt-uuid-foo",
  1247. "default",
  1248. []string{},
  1249. []string{},
  1250. "pod-hostname-foo",
  1251. nil,
  1252. "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk,all-run --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo",
  1253. },
  1254. // Case #7, if not all containers are privileged, the result should not have 'insecure-options=all-run'
  1255. {
  1256. kubenet.NewPlugin("/tmp"),
  1257. &api.Pod{
  1258. ObjectMeta: api.ObjectMeta{
  1259. Name: "pod-name-foo",
  1260. },
  1261. Spec: api.PodSpec{
  1262. Containers: []api.Container{
  1263. {Name: "container-foo", SecurityContext: &api.SecurityContext{Privileged: &boolTrue}},
  1264. {Name: "container-bar", SecurityContext: &api.SecurityContext{Privileged: &boolFalse}},
  1265. },
  1266. },
  1267. },
  1268. "rkt-uuid-foo",
  1269. "default",
  1270. []string{},
  1271. []string{},
  1272. "pod-hostname-foo",
  1273. nil,
  1274. "/usr/bin/nsenter --net=/var/run/netns/default -- /bin/rkt/rkt --insecure-options=image,ondisk --local-config=/var/rkt/local/data --dir=/var/data run-prepared --net=host --hostname=pod-hostname-foo rkt-uuid-foo",
  1275. },
  1276. }
  1277. rkt := &Runtime{
  1278. nsenterPath: "/usr/bin/nsenter",
  1279. os: &kubetesting.FakeOS{HostName: hostName},
  1280. config: &Config{
  1281. Path: "/bin/rkt/rkt",
  1282. Stage1Image: "/bin/rkt/stage1-coreos.aci",
  1283. Dir: "/var/data",
  1284. InsecureOptions: "image,ondisk",
  1285. LocalConfigDir: "/var/rkt/local/data",
  1286. },
  1287. }
  1288. for i, tt := range tests {
  1289. testCaseHint := fmt.Sprintf("test case #%d", i)
  1290. rkt.networkPlugin = tt.networkPlugin
  1291. rkt.runtimeHelper = &fakeRuntimeHelper{tt.dnsServers, tt.dnsSearches, tt.hostName, "", tt.err}
  1292. rkt.execer = &utilexec.FakeExec{CommandScript: []utilexec.FakeCommandAction{func(cmd string, args ...string) utilexec.Cmd {
  1293. return utilexec.InitFakeCmd(&utilexec.FakeCmd{}, cmd, args...)
  1294. }}}
  1295. // a command should be created of this form, but the returned command shouldn't be called (asserted by having no expectations on it)
  1296. result, err := rkt.generateRunCommand(tt.pod, tt.uuid, tt.netnsName)
  1297. assert.Equal(t, tt.err, err, testCaseHint)
  1298. assert.Equal(t, tt.expect, result, testCaseHint)
  1299. }
  1300. }
  1301. func TestLifeCycleHooks(t *testing.T) {
  1302. runner := lifecycle.NewFakeHandlerRunner()
  1303. fr := newFakeRktInterface()
  1304. fs := newFakeSystemd()
  1305. rkt := &Runtime{
  1306. runner: runner,
  1307. apisvc: fr,
  1308. systemd: fs,
  1309. containerRefManager: kubecontainer.NewRefManager(),
  1310. }
  1311. tests := []struct {
  1312. pod *api.Pod
  1313. runtimePod *kubecontainer.Pod
  1314. postStartRuns []string
  1315. preStopRuns []string
  1316. err error
  1317. }{
  1318. {
  1319. // Case 0, container without any hooks.
  1320. &api.Pod{
  1321. ObjectMeta: api.ObjectMeta{
  1322. Name: "pod-1",
  1323. Namespace: "ns-1",
  1324. UID: "uid-1",
  1325. },
  1326. Spec: api.PodSpec{
  1327. Containers: []api.Container{
  1328. {Name: "container-name-1"},
  1329. },
  1330. },
  1331. },
  1332. &kubecontainer.Pod{
  1333. Containers: []*kubecontainer.Container{
  1334. {ID: kubecontainer.BuildContainerID("rkt", "id-1")},
  1335. },
  1336. },
  1337. []string{},
  1338. []string{},
  1339. nil,
  1340. },
  1341. {
  1342. // Case 1, containers with post-start and pre-stop hooks.
  1343. &api.Pod{
  1344. ObjectMeta: api.ObjectMeta{
  1345. Name: "pod-1",
  1346. Namespace: "ns-1",
  1347. UID: "uid-1",
  1348. },
  1349. Spec: api.PodSpec{
  1350. Containers: []api.Container{
  1351. {
  1352. Name: "container-name-1",
  1353. Lifecycle: &api.Lifecycle{
  1354. PostStart: &api.Handler{
  1355. Exec: &api.ExecAction{},
  1356. },
  1357. },
  1358. },
  1359. {
  1360. Name: "container-name-2",
  1361. Lifecycle: &api.Lifecycle{
  1362. PostStart: &api.Handler{
  1363. HTTPGet: &api.HTTPGetAction{},
  1364. },
  1365. },
  1366. },
  1367. {
  1368. Name: "container-name-3",
  1369. Lifecycle: &api.Lifecycle{
  1370. PreStop: &api.Handler{
  1371. Exec: &api.ExecAction{},
  1372. },
  1373. },
  1374. },
  1375. {
  1376. Name: "container-name-4",
  1377. Lifecycle: &api.Lifecycle{
  1378. PreStop: &api.Handler{
  1379. HTTPGet: &api.HTTPGetAction{},
  1380. },
  1381. },
  1382. },
  1383. },
  1384. },
  1385. },
  1386. &kubecontainer.Pod{
  1387. Containers: []*kubecontainer.Container{
  1388. {
  1389. ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-4"),
  1390. Name: "container-name-4",
  1391. },
  1392. {
  1393. ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-3"),
  1394. Name: "container-name-3",
  1395. },
  1396. {
  1397. ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-2"),
  1398. Name: "container-name-2",
  1399. },
  1400. {
  1401. ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-1"),
  1402. Name: "container-name-1",
  1403. },
  1404. },
  1405. },
  1406. []string{
  1407. "exec on pod: pod-1_ns-1(uid-1), container: container-name-1: rkt://uuid:container-name-1",
  1408. "http-get on pod: pod-1_ns-1(uid-1), container: container-name-2: rkt://uuid:container-name-2",
  1409. },
  1410. []string{
  1411. "exec on pod: pod-1_ns-1(uid-1), container: container-name-3: rkt://uuid:container-name-3",
  1412. "http-get on pod: pod-1_ns-1(uid-1), container: container-name-4: rkt://uuid:container-name-4",
  1413. },
  1414. nil,
  1415. },
  1416. {
  1417. // Case 2, one container with invalid hooks.
  1418. &api.Pod{
  1419. ObjectMeta: api.ObjectMeta{
  1420. Name: "pod-1",
  1421. Namespace: "ns-1",
  1422. UID: "uid-1",
  1423. },
  1424. Spec: api.PodSpec{
  1425. Containers: []api.Container{
  1426. {
  1427. Name: "container-name-1",
  1428. Lifecycle: &api.Lifecycle{
  1429. PostStart: &api.Handler{},
  1430. PreStop: &api.Handler{},
  1431. },
  1432. },
  1433. },
  1434. },
  1435. },
  1436. &kubecontainer.Pod{
  1437. Containers: []*kubecontainer.Container{
  1438. {
  1439. ID: kubecontainer.ParseContainerID("rkt://uuid:container-name-1"),
  1440. Name: "container-name-1",
  1441. },
  1442. },
  1443. },
  1444. []string{},
  1445. []string{},
  1446. errors.NewAggregate([]error{fmt.Errorf("Invalid handler: %v", &api.Handler{})}),
  1447. },
  1448. }
  1449. for i, tt := range tests {
  1450. testCaseHint := fmt.Sprintf("test case #%d", i)
  1451. pod := &rktapi.Pod{Id: "uuid"}
  1452. for _, c := range tt.runtimePod.Containers {
  1453. pod.Apps = append(pod.Apps, &rktapi.App{
  1454. Name: c.Name,
  1455. State: rktapi.AppState_APP_STATE_RUNNING,
  1456. })
  1457. }
  1458. fr.pods = []*rktapi.Pod{pod}
  1459. // Run post-start hooks
  1460. err := rkt.runLifecycleHooks(tt.pod, tt.runtimePod, lifecyclePostStartHook)
  1461. assert.Equal(t, tt.err, err, testCaseHint)
  1462. sort.Sort(sortedStringList(tt.postStartRuns))
  1463. sort.Sort(sortedStringList(runner.HandlerRuns))
  1464. assert.Equal(t, tt.postStartRuns, runner.HandlerRuns, testCaseHint)
  1465. runner.Reset()
  1466. // Run pre-stop hooks.
  1467. err = rkt.runLifecycleHooks(tt.pod, tt.runtimePod, lifecyclePreStopHook)
  1468. assert.Equal(t, tt.err, err, testCaseHint)
  1469. sort.Sort(sortedStringList(tt.preStopRuns))
  1470. sort.Sort(sortedStringList(runner.HandlerRuns))
  1471. assert.Equal(t, tt.preStopRuns, runner.HandlerRuns, testCaseHint)
  1472. runner.Reset()
  1473. }
  1474. }
  1475. func TestImageStats(t *testing.T) {
  1476. fr := newFakeRktInterface()
  1477. rkt := &Runtime{apisvc: fr}
  1478. fr.images = []*rktapi.Image{
  1479. {Size: 100},
  1480. {Size: 200},
  1481. {Size: 300},
  1482. }
  1483. result, err := rkt.ImageStats()
  1484. assert.NoError(t, err)
  1485. assert.Equal(t, result, &kubecontainer.ImageStats{TotalStorageBytes: 600})
  1486. }
  1487. func TestGarbageCollect(t *testing.T) {
  1488. fr := newFakeRktInterface()
  1489. fs := newFakeSystemd()
  1490. cli := newFakeRktCli()
  1491. fakeOS := kubetesting.NewFakeOS()
  1492. getter := newFakePodGetter()
  1493. rkt := &Runtime{
  1494. os: fakeOS,
  1495. cli: cli,
  1496. apisvc: fr,
  1497. podGetter: getter,
  1498. systemd: fs,
  1499. containerRefManager: kubecontainer.NewRefManager(),
  1500. }
  1501. fakeApp := &rktapi.App{Name: "app-foo"}
  1502. tests := []struct {
  1503. gcPolicy kubecontainer.ContainerGCPolicy
  1504. apiPods []*api.Pod
  1505. pods []*rktapi.Pod
  1506. serviceFilesOnDisk []string
  1507. expectedCommands []string
  1508. expectedServiceFiles []string
  1509. }{
  1510. // All running pods, should not be gc'd.
  1511. // Dead, new pods should not be gc'd.
  1512. // Dead, old pods should be gc'd.
  1513. // Deleted pods should be gc'd.
  1514. // Service files without corresponded pods should be removed.
  1515. {
  1516. kubecontainer.ContainerGCPolicy{
  1517. MinAge: 0,
  1518. MaxContainers: 0,
  1519. },
  1520. []*api.Pod{
  1521. {ObjectMeta: api.ObjectMeta{UID: "pod-uid-1"}},
  1522. {ObjectMeta: api.ObjectMeta{UID: "pod-uid-2"}},
  1523. {ObjectMeta: api.ObjectMeta{UID: "pod-uid-3"}},
  1524. {ObjectMeta: api.ObjectMeta{UID: "pod-uid-4"}},
  1525. },
  1526. []*rktapi.Pod{
  1527. {
  1528. Id: "deleted-foo",
  1529. State: rktapi.PodState_POD_STATE_EXITED,
  1530. CreatedAt: time.Now().Add(time.Hour).UnixNano(),
  1531. StartedAt: time.Now().Add(time.Hour).UnixNano(),
  1532. Apps: []*rktapi.App{fakeApp},
  1533. Annotations: []*rktapi.KeyValue{
  1534. {
  1535. Key: types.KubernetesPodUIDLabel,
  1536. Value: "pod-uid-0",
  1537. },
  1538. },
  1539. },
  1540. {
  1541. Id: "running-foo",
  1542. State: rktapi.PodState_POD_STATE_RUNNING,
  1543. CreatedAt: 0,
  1544. StartedAt: 0,
  1545. Apps: []*rktapi.App{fakeApp},
  1546. Annotations: []*rktapi.KeyValue{
  1547. {
  1548. Key: types.KubernetesPodUIDLabel,
  1549. Value: "pod-uid-1",
  1550. },
  1551. },
  1552. },
  1553. {
  1554. Id: "running-bar",
  1555. State: rktapi.PodState_POD_STATE_RUNNING,
  1556. CreatedAt: 0,
  1557. StartedAt: 0,
  1558. Apps: []*rktapi.App{fakeApp},
  1559. Annotations: []*rktapi.KeyValue{
  1560. {
  1561. Key: types.KubernetesPodUIDLabel,
  1562. Value: "pod-uid-2",
  1563. },
  1564. },
  1565. },
  1566. {
  1567. Id: "dead-old",
  1568. State: rktapi.PodState_POD_STATE_EXITED,
  1569. CreatedAt: 0,
  1570. StartedAt: 0,
  1571. Apps: []*rktapi.App{fakeApp},
  1572. Annotations: []*rktapi.KeyValue{
  1573. {
  1574. Key: types.KubernetesPodUIDLabel,
  1575. Value: "pod-uid-3",
  1576. },
  1577. },
  1578. },
  1579. {
  1580. Id: "dead-new",
  1581. State: rktapi.PodState_POD_STATE_EXITED,
  1582. CreatedAt: time.Now().Add(time.Hour).UnixNano(),
  1583. StartedAt: time.Now().Add(time.Hour).UnixNano(),
  1584. Apps: []*rktapi.App{fakeApp},
  1585. Annotations: []*rktapi.KeyValue{
  1586. {
  1587. Key: types.KubernetesPodUIDLabel,
  1588. Value: "pod-uid-4",
  1589. },
  1590. },
  1591. },
  1592. },
  1593. []string{"k8s_dead-old.service", "k8s_deleted-foo.service", "k8s_non-existing-bar.service"},
  1594. []string{"rkt rm dead-old", "rkt rm deleted-foo"},
  1595. []string{"/run/systemd/system/k8s_dead-old.service", "/run/systemd/system/k8s_deleted-foo.service", "/run/systemd/system/k8s_non-existing-bar.service"},
  1596. },
  1597. // gcPolicy.MaxContainers should be enforced.
  1598. // Oldest ones are removed first.
  1599. {
  1600. kubecontainer.ContainerGCPolicy{
  1601. MinAge: 0,
  1602. MaxContainers: 1,
  1603. },
  1604. []*api.Pod{
  1605. {ObjectMeta: api.ObjectMeta{UID: "pod-uid-0"}},
  1606. {ObjectMeta: api.ObjectMeta{UID: "pod-uid-1"}},
  1607. {ObjectMeta: api.ObjectMeta{UID: "pod-uid-2"}},
  1608. },
  1609. []*rktapi.Pod{
  1610. {
  1611. Id: "dead-2",
  1612. State: rktapi.PodState_POD_STATE_EXITED,
  1613. CreatedAt: 2,
  1614. StartedAt: 2,
  1615. Apps: []*rktapi.App{fakeApp},
  1616. Annotations: []*rktapi.KeyValue{
  1617. {
  1618. Key: types.KubernetesPodUIDLabel,
  1619. Value: "pod-uid-2",
  1620. },
  1621. },
  1622. },
  1623. {
  1624. Id: "dead-1",
  1625. State: rktapi.PodState_POD_STATE_EXITED,
  1626. CreatedAt: 1,
  1627. StartedAt: 1,
  1628. Apps: []*rktapi.App{fakeApp},
  1629. Annotations: []*rktapi.KeyValue{
  1630. {
  1631. Key: types.KubernetesPodUIDLabel,
  1632. Value: "pod-uid-1",
  1633. },
  1634. },
  1635. },
  1636. {
  1637. Id: "dead-0",
  1638. State: rktapi.PodState_POD_STATE_EXITED,
  1639. CreatedAt: 0,
  1640. StartedAt: 0,
  1641. Apps: []*rktapi.App{fakeApp},
  1642. Annotations: []*rktapi.KeyValue{
  1643. {
  1644. Key: types.KubernetesPodUIDLabel,
  1645. Value: "pod-uid-0",
  1646. },
  1647. },
  1648. },
  1649. },
  1650. []string{"k8s_dead-0.service", "k8s_dead-1.service", "k8s_dead-2.service"},
  1651. []string{"rkt rm dead-0", "rkt rm dead-1"},
  1652. []string{"/run/systemd/system/k8s_dead-0.service", "/run/systemd/system/k8s_dead-1.service"},
  1653. },
  1654. }
  1655. for i, tt := range tests {
  1656. testCaseHint := fmt.Sprintf("test case #%d", i)
  1657. ctrl := gomock.NewController(t)
  1658. fakeOS.ReadDirFn = func(dirname string) ([]os.FileInfo, error) {
  1659. serviceFileNames := tt.serviceFilesOnDisk
  1660. var fileInfos []os.FileInfo
  1661. for _, name := range serviceFileNames {
  1662. mockFI := mock_os.NewMockFileInfo(ctrl)
  1663. mockFI.EXPECT().Name().Return(name)
  1664. fileInfos = append(fileInfos, mockFI)
  1665. }
  1666. return fileInfos, nil
  1667. }
  1668. fr.pods = tt.pods
  1669. for _, p := range tt.apiPods {
  1670. getter.pods[p.UID] = p
  1671. }
  1672. allSourcesReady := true
  1673. err := rkt.GarbageCollect(tt.gcPolicy, allSourcesReady)
  1674. assert.NoError(t, err, testCaseHint)
  1675. sort.Sort(sortedStringList(tt.expectedCommands))
  1676. sort.Sort(sortedStringList(cli.cmds))
  1677. assert.Equal(t, tt.expectedCommands, cli.cmds, testCaseHint)
  1678. sort.Sort(sortedStringList(tt.expectedServiceFiles))
  1679. sort.Sort(sortedStringList(fakeOS.Removes))
  1680. sort.Sort(sortedStringList(fs.resetFailedUnits))
  1681. assert.Equal(t, tt.expectedServiceFiles, fakeOS.Removes, testCaseHint)
  1682. var expectedService []string
  1683. for _, f := range tt.expectedServiceFiles {
  1684. expectedService = append(expectedService, filepath.Base(f))
  1685. }
  1686. assert.Equal(t, expectedService, fs.resetFailedUnits, testCaseHint)
  1687. // Cleanup after each test.
  1688. cli.Reset()
  1689. ctrl.Finish()
  1690. fakeOS.Removes = []string{}
  1691. fs.resetFailedUnits = []string{}
  1692. getter.pods = make(map[kubetypes.UID]*api.Pod)
  1693. }
  1694. }
  1695. type annotationsByName []appctypes.Annotation
  1696. func (a annotationsByName) Len() int { return len(a) }
  1697. func (a annotationsByName) Less(x, y int) bool { return a[x].Name < a[y].Name }
  1698. func (a annotationsByName) Swap(x, y int) { a[x], a[y] = a[y], a[x] }
  1699. func TestMakePodManifestAnnotations(t *testing.T) {
  1700. ctrl := gomock.NewController(t)
  1701. defer ctrl.Finish()
  1702. fr := newFakeRktInterface()
  1703. fs := newFakeSystemd()
  1704. r := &Runtime{apisvc: fr, systemd: fs}
  1705. testCases := []struct {
  1706. in *api.Pod
  1707. out *appcschema.PodManifest
  1708. outerr error
  1709. }{
  1710. {
  1711. in: &api.Pod{
  1712. ObjectMeta: api.ObjectMeta{
  1713. UID: "uid-1",
  1714. Name: "name-1",
  1715. Namespace: "namespace-1",
  1716. Annotations: map[string]string{
  1717. k8sRktStage1NameAnno: "stage1-override-img",
  1718. },
  1719. },
  1720. },
  1721. out: &appcschema.PodManifest{
  1722. Annotations: []appctypes.Annotation{
  1723. {
  1724. Name: "io.kubernetes.container.name",
  1725. Value: "POD",
  1726. },
  1727. {
  1728. Name: appctypes.ACIdentifier(k8sRktStage1NameAnno),
  1729. Value: "stage1-override-img",
  1730. },
  1731. {
  1732. Name: appctypes.ACIdentifier(types.KubernetesPodUIDLabel),
  1733. Value: "uid-1",
  1734. },
  1735. {
  1736. Name: appctypes.ACIdentifier(types.KubernetesPodNameLabel),
  1737. Value: "name-1",
  1738. },
  1739. {
  1740. Name: appctypes.ACIdentifier(k8sRktKubeletAnno),
  1741. Value: "true",
  1742. },
  1743. {
  1744. Name: appctypes.ACIdentifier(types.KubernetesPodNamespaceLabel),
  1745. Value: "namespace-1",
  1746. },
  1747. {
  1748. Name: appctypes.ACIdentifier(k8sRktRestartCountAnno),
  1749. Value: "0",
  1750. },
  1751. },
  1752. },
  1753. },
  1754. }
  1755. for i, testCase := range testCases {
  1756. hint := fmt.Sprintf("case #%d", i)
  1757. result, err := r.makePodManifest(testCase.in, "", []api.Secret{})
  1758. assert.Equal(t, testCase.outerr, err, hint)
  1759. if err == nil {
  1760. sort.Sort(annotationsByName(result.Annotations))
  1761. sort.Sort(annotationsByName(testCase.out.Annotations))
  1762. assert.Equal(t, testCase.out.Annotations, result.Annotations, hint)
  1763. }
  1764. }
  1765. }
  1766. func TestPreparePodArgs(t *testing.T) {
  1767. r := &Runtime{
  1768. config: &Config{},
  1769. }
  1770. testCases := []struct {
  1771. manifest appcschema.PodManifest
  1772. stage1Config string
  1773. cmd []string
  1774. }{
  1775. {
  1776. appcschema.PodManifest{
  1777. Annotations: appctypes.Annotations{
  1778. {
  1779. Name: k8sRktStage1NameAnno,
  1780. Value: "stage1-image",
  1781. },
  1782. },
  1783. },
  1784. "",
  1785. []string{"prepare", "--quiet", "--pod-manifest", "file", "--stage1-name=stage1-image"},
  1786. },
  1787. {
  1788. appcschema.PodManifest{
  1789. Annotations: appctypes.Annotations{
  1790. {
  1791. Name: k8sRktStage1NameAnno,
  1792. Value: "stage1-image",
  1793. },
  1794. },
  1795. },
  1796. "stage1-image0",
  1797. []string{"prepare", "--quiet", "--pod-manifest", "file", "--stage1-name=stage1-image"},
  1798. },
  1799. {
  1800. appcschema.PodManifest{
  1801. Annotations: appctypes.Annotations{},
  1802. },
  1803. "stage1-image0",
  1804. []string{"prepare", "--quiet", "--pod-manifest", "file", "--stage1-name=stage1-image0"},
  1805. },
  1806. {
  1807. appcschema.PodManifest{
  1808. Annotations: appctypes.Annotations{},
  1809. },
  1810. "",
  1811. []string{"prepare", "--quiet", "--pod-manifest", "file"},
  1812. },
  1813. }
  1814. for i, testCase := range testCases {
  1815. r.config.Stage1Image = testCase.stage1Config
  1816. cmd := r.preparePodArgs(&testCase.manifest, "file")
  1817. assert.Equal(t, testCase.cmd, cmd, fmt.Sprintf("Test case #%d", i))
  1818. }
  1819. }