github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/test/e2e/play_kube_test.go (about) 1 // +build !remoteclient 2 3 package integration 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "text/template" 11 12 . "github.com/containers/libpod/test/utils" 13 . "github.com/onsi/ginkgo" 14 . "github.com/onsi/gomega" 15 ) 16 17 var yamlTemplate = ` 18 apiVersion: v1 19 kind: Pod 20 metadata: 21 creationTimestamp: "2019-07-17T14:44:08Z" 22 labels: 23 app: {{ .Name }} 24 name: {{ .Name }} 25 {{ with .Annotations }} 26 annotations: 27 {{ range $key, $value := . }} 28 {{ $key }}: {{ $value }} 29 {{ end }} 30 {{ end }} 31 32 spec: 33 hostname: {{ .Hostname }} 34 containers: 35 {{ with .Ctrs }} 36 {{ range . }} 37 - command: 38 {{ range .Cmd }} 39 - {{.}} 40 {{ end }} 41 env: 42 - name: PATH 43 value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 44 - name: TERM 45 value: xterm 46 - name: HOSTNAME 47 - name: container 48 value: podman 49 image: {{ .Image }} 50 name: {{ .Name }} 51 imagePullPolicy: {{ .PullPolicy }} 52 resources: {} 53 {{ if .SecurityContext }} 54 securityContext: 55 allowPrivilegeEscalation: true 56 {{ if .Caps }} 57 capabilities: 58 {{ with .CapAdd }} 59 add: 60 {{ range . }} 61 - {{.}} 62 {{ end }} 63 {{ end }} 64 {{ with .CapDrop }} 65 drop: 66 {{ range . }} 67 - {{.}} 68 {{ end }} 69 {{ end }} 70 {{ end }} 71 privileged: false 72 readOnlyRootFilesystem: false 73 workingDir: / 74 {{ end }} 75 {{ end }} 76 {{ end }} 77 status: {} 78 ` 79 80 var ( 81 defaultCtrName = "testCtr" 82 defaultCtrCmd = []string{"top"} 83 defaultCtrImage = ALPINE 84 defaultPodName = "testPod" 85 seccompPwdEPERM = []byte(`{"defaultAction":"SCMP_ACT_ALLOW","syscalls":[{"name":"getcwd","action":"SCMP_ACT_ERRNO"}]}`) 86 ) 87 88 func generateKubeYaml(pod *Pod, fileName string) error { 89 f, err := os.Create(fileName) 90 if err != nil { 91 return err 92 } 93 defer f.Close() 94 95 t, err := template.New("pod").Parse(yamlTemplate) 96 if err != nil { 97 return err 98 } 99 100 if err := t.Execute(f, pod); err != nil { 101 return err 102 } 103 104 return nil 105 } 106 107 // Pod describes the options a kube yaml can be configured at pod level 108 type Pod struct { 109 Name string 110 Hostname string 111 Ctrs []*Ctr 112 Annotations map[string]string 113 } 114 115 // getPod takes a list of podOptions and returns a pod with sane defaults 116 // and the configured options 117 // if no containers are added, it will add the default container 118 func getPod(options ...podOption) *Pod { 119 p := Pod{defaultPodName, "", make([]*Ctr, 0), make(map[string]string)} 120 for _, option := range options { 121 option(&p) 122 } 123 if len(p.Ctrs) == 0 { 124 p.Ctrs = []*Ctr{getCtr()} 125 } 126 return &p 127 } 128 129 type podOption func(*Pod) 130 131 func withHostname(h string) podOption { 132 return func(pod *Pod) { 133 pod.Hostname = h 134 } 135 } 136 137 func withCtr(c *Ctr) podOption { 138 return func(pod *Pod) { 139 pod.Ctrs = append(pod.Ctrs, c) 140 } 141 } 142 143 func withAnnotation(k, v string) podOption { 144 return func(pod *Pod) { 145 pod.Annotations[k] = v 146 } 147 } 148 149 // Ctr describes the options a kube yaml can be configured at container level 150 type Ctr struct { 151 Name string 152 Image string 153 Cmd []string 154 SecurityContext bool 155 Caps bool 156 CapAdd []string 157 CapDrop []string 158 PullPolicy string 159 } 160 161 // getCtr takes a list of ctrOptions and returns a Ctr with sane defaults 162 // and the configured options 163 func getCtr(options ...ctrOption) *Ctr { 164 c := Ctr{defaultCtrName, defaultCtrImage, defaultCtrCmd, true, false, nil, nil, ""} 165 for _, option := range options { 166 option(&c) 167 } 168 return &c 169 } 170 171 type ctrOption func(*Ctr) 172 173 func withCmd(cmd []string) ctrOption { 174 return func(c *Ctr) { 175 c.Cmd = cmd 176 } 177 } 178 179 func withImage(img string) ctrOption { 180 return func(c *Ctr) { 181 c.Image = img 182 } 183 } 184 185 func withSecurityContext(sc bool) ctrOption { 186 return func(c *Ctr) { 187 c.SecurityContext = sc 188 } 189 } 190 191 func withCapAdd(caps []string) ctrOption { 192 return func(c *Ctr) { 193 c.CapAdd = caps 194 c.Caps = true 195 } 196 } 197 198 func withCapDrop(caps []string) ctrOption { 199 return func(c *Ctr) { 200 c.CapDrop = caps 201 c.Caps = true 202 } 203 } 204 205 func withPullPolicy(policy string) ctrOption { 206 return func(c *Ctr) { 207 c.PullPolicy = policy 208 } 209 } 210 211 var _ = Describe("Podman generate kube", func() { 212 var ( 213 tempdir string 214 err error 215 podmanTest *PodmanTestIntegration 216 kubeYaml string 217 ) 218 219 BeforeEach(func() { 220 tempdir, err = CreateTempDirInTempDir() 221 if err != nil { 222 os.Exit(1) 223 } 224 podmanTest = PodmanTestCreate(tempdir) 225 podmanTest.Setup() 226 podmanTest.SeedImages() 227 228 kubeYaml = filepath.Join(podmanTest.TempDir, "kube.yaml") 229 }) 230 231 AfterEach(func() { 232 podmanTest.Cleanup() 233 f := CurrentGinkgoTestDescription() 234 processTestResult(f) 235 }) 236 237 It("podman play kube fail with nonexist authfile", func() { 238 err := generateKubeYaml(getPod(), kubeYaml) 239 Expect(err).To(BeNil()) 240 241 kube := podmanTest.Podman([]string{"play", "kube", "--authfile", "/tmp/nonexist", kubeYaml}) 242 kube.WaitWithDefaultTimeout() 243 Expect(kube.ExitCode()).To(Not(Equal(0))) 244 245 }) 246 247 It("podman play kube test correct command", func() { 248 err := generateKubeYaml(getPod(), kubeYaml) 249 Expect(err).To(BeNil()) 250 251 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 252 kube.WaitWithDefaultTimeout() 253 Expect(kube.ExitCode()).To(Equal(0)) 254 255 inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) 256 inspect.WaitWithDefaultTimeout() 257 Expect(inspect.ExitCode()).To(Equal(0)) 258 Expect(inspect.OutputToString()).To(ContainSubstring(defaultCtrCmd[0])) 259 }) 260 261 It("podman play kube test correct output", func() { 262 p := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"})))) 263 264 err := generateKubeYaml(p, kubeYaml) 265 Expect(err).To(BeNil()) 266 267 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 268 kube.WaitWithDefaultTimeout() 269 Expect(kube.ExitCode()).To(Equal(0)) 270 271 logs := podmanTest.Podman([]string{"logs", defaultCtrName}) 272 logs.WaitWithDefaultTimeout() 273 Expect(logs.ExitCode()).To(Equal(0)) 274 Expect(logs.OutputToString()).To(ContainSubstring("hello")) 275 276 inspect := podmanTest.Podman([]string{"inspect", defaultCtrName, "--format", "'{{ .Config.Cmd }}'"}) 277 inspect.WaitWithDefaultTimeout() 278 Expect(inspect.ExitCode()).To(Equal(0)) 279 Expect(inspect.OutputToString()).To(ContainSubstring("hello")) 280 }) 281 282 It("podman play kube test hostname", func() { 283 err := generateKubeYaml(getPod(), kubeYaml) 284 Expect(err).To(BeNil()) 285 286 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 287 kube.WaitWithDefaultTimeout() 288 Expect(kube.ExitCode()).To(Equal(0)) 289 290 inspect := podmanTest.Podman([]string{"inspect", defaultCtrName, "--format", "{{ .Config.Hostname }}"}) 291 inspect.WaitWithDefaultTimeout() 292 Expect(inspect.ExitCode()).To(Equal(0)) 293 Expect(inspect.OutputToString()).To(Equal(defaultPodName)) 294 }) 295 296 It("podman play kube test with customized hostname", func() { 297 hostname := "myhostname" 298 err := generateKubeYaml(getPod(withHostname(hostname)), kubeYaml) 299 Expect(err).To(BeNil()) 300 301 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 302 kube.WaitWithDefaultTimeout() 303 Expect(kube.ExitCode()).To(Equal(0)) 304 305 inspect := podmanTest.Podman([]string{"inspect", defaultCtrName, "--format", "{{ .Config.Hostname }}"}) 306 inspect.WaitWithDefaultTimeout() 307 Expect(inspect.ExitCode()).To(Equal(0)) 308 Expect(inspect.OutputToString()).To(Equal(hostname)) 309 }) 310 311 It("podman play kube cap add", func() { 312 capAdd := "CAP_SYS_ADMIN" 313 ctr := getCtr(withCapAdd([]string{capAdd}), withCmd([]string{"cat", "/proc/self/status"})) 314 315 err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) 316 Expect(err).To(BeNil()) 317 318 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 319 kube.WaitWithDefaultTimeout() 320 Expect(kube.ExitCode()).To(Equal(0)) 321 322 inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) 323 inspect.WaitWithDefaultTimeout() 324 Expect(inspect.ExitCode()).To(Equal(0)) 325 Expect(inspect.OutputToString()).To(ContainSubstring(capAdd)) 326 }) 327 328 It("podman play kube cap drop", func() { 329 capDrop := "CAP_CHOWN" 330 ctr := getCtr(withCapDrop([]string{capDrop})) 331 332 err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) 333 Expect(err).To(BeNil()) 334 335 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 336 kube.WaitWithDefaultTimeout() 337 Expect(kube.ExitCode()).To(Equal(0)) 338 339 inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) 340 inspect.WaitWithDefaultTimeout() 341 Expect(inspect.ExitCode()).To(Equal(0)) 342 Expect(inspect.OutputToString()).To(ContainSubstring(capDrop)) 343 }) 344 345 It("podman play kube no security context", func() { 346 // expect play kube to not fail if no security context is specified 347 err := generateKubeYaml(getPod(withCtr(getCtr(withSecurityContext(false)))), kubeYaml) 348 Expect(err).To(BeNil()) 349 350 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 351 kube.WaitWithDefaultTimeout() 352 Expect(kube.ExitCode()).To(Equal(0)) 353 354 inspect := podmanTest.Podman([]string{"inspect", defaultCtrName}) 355 inspect.WaitWithDefaultTimeout() 356 Expect(inspect.ExitCode()).To(Equal(0)) 357 }) 358 359 It("podman play kube seccomp container level", func() { 360 // expect play kube is expected to set a seccomp label if it's applied as an annotation 361 jsonFile, err := podmanTest.CreateSeccompJson(seccompPwdEPERM) 362 if err != nil { 363 fmt.Println(err) 364 Skip("Failed to prepare seccomp.json for test.") 365 } 366 367 ctrAnnotation := "container.seccomp.security.alpha.kubernetes.io/" + defaultCtrName 368 ctr := getCtr(withCmd([]string{"pwd"})) 369 370 err = generateKubeYaml(getPod(withCtr(ctr), withAnnotation(ctrAnnotation, "localhost/"+filepath.Base(jsonFile))), kubeYaml) 371 Expect(err).To(BeNil()) 372 373 // CreateSeccompJson will put the profile into podmanTest.TempDir. Use --seccomp-profile-root to tell play kube where to look 374 kube := podmanTest.Podman([]string{"play", "kube", "--seccomp-profile-root", podmanTest.TempDir, kubeYaml}) 375 kube.WaitWithDefaultTimeout() 376 Expect(kube.ExitCode()).To(Equal(0)) 377 378 logs := podmanTest.Podman([]string{"logs", defaultCtrName}) 379 logs.WaitWithDefaultTimeout() 380 Expect(logs.ExitCode()).To(Equal(0)) 381 Expect(logs.OutputToString()).To(ContainSubstring("Operation not permitted")) 382 }) 383 384 It("podman play kube seccomp pod level", func() { 385 // expect play kube is expected to set a seccomp label if it's applied as an annotation 386 jsonFile, err := podmanTest.CreateSeccompJson(seccompPwdEPERM) 387 if err != nil { 388 fmt.Println(err) 389 Skip("Failed to prepare seccomp.json for test.") 390 } 391 defer os.Remove(jsonFile) 392 393 ctr := getCtr(withCmd([]string{"pwd"})) 394 395 err = generateKubeYaml(getPod(withCtr(ctr), withAnnotation("seccomp.security.alpha.kubernetes.io/pod", "localhost/"+filepath.Base(jsonFile))), kubeYaml) 396 Expect(err).To(BeNil()) 397 398 // CreateSeccompJson will put the profile into podmanTest.TempDir. Use --seccomp-profile-root to tell play kube where to look 399 kube := podmanTest.Podman([]string{"play", "kube", "--seccomp-profile-root", podmanTest.TempDir, kubeYaml}) 400 kube.WaitWithDefaultTimeout() 401 Expect(kube.ExitCode()).To(Equal(0)) 402 403 logs := podmanTest.Podman([]string{"logs", defaultCtrName}) 404 logs.WaitWithDefaultTimeout() 405 Expect(logs.ExitCode()).To(Equal(0)) 406 Expect(logs.OutputToString()).To(ContainSubstring("Operation not permitted")) 407 }) 408 409 It("podman play kube with pull policy of never should be 125", func() { 410 ctr := getCtr(withPullPolicy("never"), withImage(BB_GLIBC)) 411 err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) 412 Expect(err).To(BeNil()) 413 414 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 415 kube.WaitWithDefaultTimeout() 416 Expect(kube.ExitCode()).To(Equal(125)) 417 }) 418 419 It("podman play kube with pull policy of missing", func() { 420 ctr := getCtr(withPullPolicy("missing"), withImage(BB)) 421 err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) 422 Expect(err).To(BeNil()) 423 424 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 425 kube.WaitWithDefaultTimeout() 426 Expect(kube.ExitCode()).To(Equal(0)) 427 }) 428 429 It("podman play kube with pull always", func() { 430 oldBB := "docker.io/library/busybox:1.30.1" 431 pull := podmanTest.Podman([]string{"pull", oldBB}) 432 pull.WaitWithDefaultTimeout() 433 434 tag := podmanTest.Podman([]string{"tag", oldBB, BB}) 435 tag.WaitWithDefaultTimeout() 436 Expect(tag.ExitCode()).To(BeZero()) 437 438 rmi := podmanTest.Podman([]string{"rmi", oldBB}) 439 rmi.WaitWithDefaultTimeout() 440 Expect(rmi.ExitCode()).To(BeZero()) 441 442 inspect := podmanTest.Podman([]string{"inspect", BB}) 443 inspect.WaitWithDefaultTimeout() 444 oldBBinspect := inspect.InspectImageJSON() 445 446 ctr := getCtr(withPullPolicy("always"), withImage(BB)) 447 err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) 448 Expect(err).To(BeNil()) 449 450 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 451 kube.WaitWithDefaultTimeout() 452 Expect(kube.ExitCode()).To(Equal(0)) 453 454 inspect = podmanTest.Podman([]string{"inspect", BB}) 455 inspect.WaitWithDefaultTimeout() 456 newBBinspect := inspect.InspectImageJSON() 457 Expect(oldBBinspect[0].Digest).To(Not(Equal(newBBinspect[0].Digest))) 458 }) 459 460 It("podman play kube with latest image should always pull", func() { 461 oldBB := "docker.io/library/busybox:1.30.1" 462 pull := podmanTest.Podman([]string{"pull", oldBB}) 463 pull.WaitWithDefaultTimeout() 464 465 tag := podmanTest.Podman([]string{"tag", oldBB, BB}) 466 tag.WaitWithDefaultTimeout() 467 Expect(tag.ExitCode()).To(BeZero()) 468 469 rmi := podmanTest.Podman([]string{"rmi", oldBB}) 470 rmi.WaitWithDefaultTimeout() 471 Expect(rmi.ExitCode()).To(BeZero()) 472 473 inspect := podmanTest.Podman([]string{"inspect", BB}) 474 inspect.WaitWithDefaultTimeout() 475 oldBBinspect := inspect.InspectImageJSON() 476 477 ctr := getCtr(withImage(BB)) 478 err := generateKubeYaml(getPod(withCtr(ctr)), kubeYaml) 479 Expect(err).To(BeNil()) 480 481 kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) 482 kube.WaitWithDefaultTimeout() 483 Expect(kube.ExitCode()).To(Equal(0)) 484 485 inspect = podmanTest.Podman([]string{"inspect", BB}) 486 inspect.WaitWithDefaultTimeout() 487 newBBinspect := inspect.InspectImageJSON() 488 Expect(oldBBinspect[0].Digest).To(Not(Equal(newBBinspect[0].Digest))) 489 }) 490 491 It("podman play kube with image data", func() { 492 testyaml := ` 493 apiVersion: v1 494 kind: Pod 495 metadata: 496 name: demo_pod 497 spec: 498 containers: 499 - image: demo 500 name: demo_kube 501 ` 502 pull := podmanTest.Podman([]string{"create", "--workdir", "/etc", "--name", "newBB", "--label", "key1=value1", "alpine"}) 503 504 pull.WaitWithDefaultTimeout() 505 Expect(pull.ExitCode()).To(BeZero()) 506 507 c := podmanTest.Podman([]string{"commit", "-c", "STOPSIGNAL=51", "newBB", "demo"}) 508 c.WaitWithDefaultTimeout() 509 Expect(c.ExitCode()).To(Equal(0)) 510 511 conffile := filepath.Join(podmanTest.TempDir, "kube.yaml") 512 tempdir, err = CreateTempDirInTempDir() 513 Expect(err).To(BeNil()) 514 515 err := ioutil.WriteFile(conffile, []byte(testyaml), 0755) 516 Expect(err).To(BeNil()) 517 518 kube := podmanTest.Podman([]string{"play", "kube", conffile}) 519 kube.WaitWithDefaultTimeout() 520 Expect(kube.ExitCode()).To(Equal(0)) 521 522 inspect := podmanTest.Podman([]string{"inspect", "demo_kube"}) 523 inspect.WaitWithDefaultTimeout() 524 Expect(inspect.ExitCode()).To(Equal(0)) 525 526 ctr := inspect.InspectContainerToJSON() 527 Expect(ctr[0].Config.WorkingDir).To(ContainSubstring("/etc")) 528 Expect(ctr[0].Config.Labels["key1"]).To(ContainSubstring("value1")) 529 Expect(ctr[0].Config.Labels["key1"]).To(ContainSubstring("value1")) 530 Expect(ctr[0].Config.StopSignal).To(Equal(uint(51))) 531 }) 532 })