github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/test/e2e/common_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "math/rand" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "sort" 11 "strconv" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/containers/podman/v2/libpod/define" 17 "github.com/containers/podman/v2/pkg/cgroups" 18 "github.com/containers/podman/v2/pkg/inspect" 19 "github.com/containers/podman/v2/pkg/rootless" 20 . "github.com/containers/podman/v2/test/utils" 21 "github.com/containers/storage" 22 "github.com/containers/storage/pkg/reexec" 23 "github.com/containers/storage/pkg/stringid" 24 jsoniter "github.com/json-iterator/go" 25 "github.com/onsi/ginkgo" 26 . "github.com/onsi/ginkgo" 27 . "github.com/onsi/gomega" 28 . "github.com/onsi/gomega/gexec" 29 "github.com/pkg/errors" 30 "github.com/sirupsen/logrus" 31 ) 32 33 var ( 34 PODMAN_BINARY string 35 CONMON_BINARY string 36 CNI_CONFIG_DIR string 37 RUNC_BINARY string 38 INTEGRATION_ROOT string 39 CGROUP_MANAGER = "systemd" 40 ARTIFACT_DIR = "/tmp/.artifacts" 41 RESTORE_IMAGES = []string{ALPINE, BB, nginx} 42 defaultWaitTimeout = 90 43 CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode() 44 ) 45 46 // PodmanTestIntegration struct for command line options 47 type PodmanTestIntegration struct { 48 PodmanTest 49 ConmonBinary string 50 CrioRoot string 51 CNIConfigDir string 52 OCIRuntime string 53 RunRoot string 54 StorageOptions string 55 SignaturePolicyPath string 56 CgroupManager string 57 Host HostOS 58 Timings []string 59 TmpDir string 60 RemoteStartErr error 61 } 62 63 var LockTmpDir string 64 65 // PodmanSessionIntegration sturct for command line session 66 type PodmanSessionIntegration struct { 67 *PodmanSession 68 } 69 70 type testResult struct { 71 name string 72 length float64 73 } 74 75 var noCache = "Cannot run nocache with remote" 76 77 type testResultsSorted []testResult 78 79 func (a testResultsSorted) Len() int { return len(a) } 80 func (a testResultsSorted) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 81 82 type testResultsSortedLength struct{ testResultsSorted } 83 84 func (a testResultsSorted) Less(i, j int) bool { return a[i].length < a[j].length } 85 86 var testResults []testResult 87 88 func TestMain(m *testing.M) { 89 if reexec.Init() { 90 return 91 } 92 os.Exit(m.Run()) 93 } 94 95 // TestLibpod ginkgo master function 96 func TestLibpod(t *testing.T) { 97 if os.Getenv("NOCACHE") == "1" { 98 CACHE_IMAGES = []string{} 99 RESTORE_IMAGES = []string{} 100 } 101 RegisterFailHandler(Fail) 102 RunSpecs(t, "Libpod Suite") 103 } 104 105 var _ = SynchronizedBeforeSuite(func() []byte { 106 // make cache dir 107 if err := os.MkdirAll(ImageCacheDir, 0777); err != nil { 108 fmt.Printf("%q\n", err) 109 os.Exit(1) 110 } 111 112 // Cache images 113 cwd, _ := os.Getwd() 114 INTEGRATION_ROOT = filepath.Join(cwd, "../../") 115 podman := PodmanTestSetup("/tmp") 116 podman.ArtifactPath = ARTIFACT_DIR 117 if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) { 118 if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil { 119 fmt.Printf("%q\n", err) 120 os.Exit(1) 121 } 122 } 123 124 // Pull cirros but dont put it into the cache 125 pullImages := []string{cirros, fedoraToolbox} 126 pullImages = append(pullImages, CACHE_IMAGES...) 127 for _, image := range pullImages { 128 podman.createArtifact(image) 129 } 130 131 if err := os.MkdirAll(filepath.Join(ImageCacheDir, podman.ImageCacheFS+"-images"), 0777); err != nil { 132 fmt.Printf("%q\n", err) 133 os.Exit(1) 134 } 135 podman.CrioRoot = ImageCacheDir 136 // If running localized tests, the cache dir is created and populated. if the 137 // tests are remote, this is a no-op 138 populateCache(podman) 139 140 host := GetHostDistributionInfo() 141 if host.Distribution == "rhel" && strings.HasPrefix(host.Version, "7") { 142 f, err := os.OpenFile("/proc/sys/user/max_user_namespaces", os.O_WRONLY, 0644) 143 if err != nil { 144 fmt.Println("Unable to enable userspace on RHEL 7") 145 os.Exit(1) 146 } 147 _, err = f.WriteString("15000") 148 if err != nil { 149 fmt.Println("Unable to enable userspace on RHEL 7") 150 os.Exit(1) 151 } 152 f.Close() 153 } 154 path, err := ioutil.TempDir("", "libpodlock") 155 if err != nil { 156 fmt.Println(err) 157 os.Exit(1) 158 } 159 160 // If running remote, we need to stop the associated podman system service 161 if podman.RemoteTest { 162 podman.StopRemoteService() 163 } 164 165 return []byte(path) 166 }, func(data []byte) { 167 cwd, _ := os.Getwd() 168 INTEGRATION_ROOT = filepath.Join(cwd, "../../") 169 LockTmpDir = string(data) 170 }) 171 172 func (p *PodmanTestIntegration) Setup() { 173 cwd, _ := os.Getwd() 174 INTEGRATION_ROOT = filepath.Join(cwd, "../../") 175 p.ArtifactPath = ARTIFACT_DIR 176 } 177 178 var _ = SynchronizedAfterSuite(func() {}, 179 func() { 180 sort.Sort(testResultsSortedLength{testResults}) 181 fmt.Println("integration timing results") 182 for _, result := range testResults { 183 fmt.Printf("%s\t\t%f\n", result.name, result.length) 184 } 185 186 // previous crio-run 187 tempdir, err := CreateTempDirInTempDir() 188 if err != nil { 189 os.Exit(1) 190 } 191 podmanTest := PodmanTestCreate(tempdir) 192 193 if err := os.RemoveAll(podmanTest.CrioRoot); err != nil { 194 fmt.Printf("%q\n", err) 195 } 196 197 // If running remote, we need to stop the associated podman system service 198 if podmanTest.RemoteTest { 199 podmanTest.StopRemoteService() 200 } 201 // for localized tests, this removes the image cache dir and for remote tests 202 // this is a no-op 203 removeCache() 204 }) 205 206 // PodmanTestCreate creates a PodmanTestIntegration instance for the tests 207 func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration { 208 var ( 209 podmanRemoteBinary string 210 ) 211 212 host := GetHostDistributionInfo() 213 cwd, _ := os.Getwd() 214 215 podmanBinary := filepath.Join(cwd, "../../bin/podman") 216 if os.Getenv("PODMAN_BINARY") != "" { 217 podmanBinary = os.Getenv("PODMAN_BINARY") 218 } 219 220 if remote { 221 podmanRemoteBinary = filepath.Join(cwd, "../../bin/podman-remote") 222 if os.Getenv("PODMAN_REMOTE_BINARY") != "" { 223 podmanRemoteBinary = os.Getenv("PODMAN_REMOTE_BINARY") 224 } 225 } 226 conmonBinary := filepath.Join("/usr/libexec/podman/conmon") 227 altConmonBinary := "/usr/bin/conmon" 228 if _, err := os.Stat(conmonBinary); os.IsNotExist(err) { 229 conmonBinary = altConmonBinary 230 } 231 if os.Getenv("CONMON_BINARY") != "" { 232 conmonBinary = os.Getenv("CONMON_BINARY") 233 } 234 storageOptions := STORAGE_OPTIONS 235 if os.Getenv("STORAGE_OPTIONS") != "" { 236 storageOptions = os.Getenv("STORAGE_OPTIONS") 237 } 238 239 cgroupManager := CGROUP_MANAGER 240 if rootless.IsRootless() { 241 cgroupManager = "cgroupfs" 242 } 243 if os.Getenv("CGROUP_MANAGER") != "" { 244 cgroupManager = os.Getenv("CGROUP_MANAGER") 245 } 246 247 ociRuntime := os.Getenv("OCI_RUNTIME") 248 if ociRuntime == "" { 249 ociRuntime = "crun" 250 } 251 os.Setenv("DISABLE_HC_SYSTEMD", "true") 252 CNIConfigDir := "/etc/cni/net.d" 253 if rootless.IsRootless() { 254 CNIConfigDir = filepath.Join(os.Getenv("HOME"), ".config/cni/net.d") 255 } 256 if err := os.MkdirAll(CNIConfigDir, 0755); err != nil { 257 panic(err) 258 } 259 260 storageFs := STORAGE_FS 261 if rootless.IsRootless() { 262 storageFs = ROOTLESS_STORAGE_FS 263 } 264 p := &PodmanTestIntegration{ 265 PodmanTest: PodmanTest{ 266 PodmanBinary: podmanBinary, 267 ArtifactPath: ARTIFACT_DIR, 268 TempDir: tempDir, 269 RemoteTest: remote, 270 ImageCacheFS: storageFs, 271 ImageCacheDir: ImageCacheDir, 272 }, 273 ConmonBinary: conmonBinary, 274 CrioRoot: filepath.Join(tempDir, "crio"), 275 TmpDir: tempDir, 276 CNIConfigDir: CNIConfigDir, 277 OCIRuntime: ociRuntime, 278 RunRoot: filepath.Join(tempDir, "crio-run"), 279 StorageOptions: storageOptions, 280 SignaturePolicyPath: filepath.Join(INTEGRATION_ROOT, "test/policy.json"), 281 CgroupManager: cgroupManager, 282 Host: host, 283 } 284 if remote { 285 p.PodmanTest.RemotePodmanBinary = podmanRemoteBinary 286 uuid := stringid.GenerateNonCryptoID() 287 if !rootless.IsRootless() { 288 p.RemoteSocket = fmt.Sprintf("unix:/run/podman/podman-%s.sock", uuid) 289 } else { 290 runtimeDir := os.Getenv("XDG_RUNTIME_DIR") 291 socket := fmt.Sprintf("podman-%s.sock", uuid) 292 fqpath := filepath.Join(runtimeDir, socket) 293 p.RemoteSocket = fmt.Sprintf("unix:%s", fqpath) 294 } 295 } 296 297 // Setup registries.conf ENV variable 298 p.setDefaultRegistriesConfigEnv() 299 // Rewrite the PodmanAsUser function 300 p.PodmanMakeOptions = p.makeOptions 301 return p 302 } 303 304 func (p PodmanTestIntegration) AddImageToRWStore(image string) { 305 if err := p.RestoreArtifact(image); err != nil { 306 logrus.Errorf("unable to restore %s to RW store", image) 307 } 308 } 309 310 // createArtifact creates a cached image in the artifact dir 311 func (p *PodmanTestIntegration) createArtifact(image string) { 312 if os.Getenv("NO_TEST_CACHE") != "" { 313 return 314 } 315 dest := strings.Split(image, "/") 316 destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) 317 fmt.Printf("Caching %s at %s...", image, destName) 318 if _, err := os.Stat(destName); os.IsNotExist(err) { 319 pull := p.PodmanNoCache([]string{"pull", image}) 320 pull.Wait(90) 321 Expect(pull.ExitCode()).To(Equal(0)) 322 323 save := p.PodmanNoCache([]string{"save", "-o", destName, image}) 324 save.Wait(90) 325 Expect(save.ExitCode()).To(Equal(0)) 326 fmt.Printf("\n") 327 } else { 328 fmt.Printf(" already exists.\n") 329 } 330 } 331 332 // InspectImageJSON takes the session output of an inspect 333 // image and returns json 334 func (s *PodmanSessionIntegration) InspectImageJSON() []inspect.ImageData { 335 var i []inspect.ImageData 336 err := jsoniter.Unmarshal(s.Out.Contents(), &i) 337 Expect(err).To(BeNil()) 338 return i 339 } 340 341 // InspectContainer returns a container's inspect data in JSON format 342 func (p *PodmanTestIntegration) InspectContainer(name string) []define.InspectContainerData { 343 cmd := []string{"inspect", name} 344 session := p.Podman(cmd) 345 session.WaitWithDefaultTimeout() 346 Expect(session).Should(Exit(0)) 347 return session.InspectContainerToJSON() 348 } 349 350 func processTestResult(f GinkgoTestDescription) { 351 tr := testResult{length: f.Duration.Seconds(), name: f.TestText} 352 testResults = append(testResults, tr) 353 } 354 355 func GetPortLock(port string) storage.Locker { 356 lockFile := filepath.Join(LockTmpDir, port) 357 lock, err := storage.GetLockfile(lockFile) 358 if err != nil { 359 fmt.Println(err) 360 os.Exit(1) 361 } 362 lock.Lock() 363 return lock 364 } 365 366 // GetRandomIPAddress returns a random IP address to avoid IP 367 // collisions during parallel tests 368 func GetRandomIPAddress() string { 369 // To avoid IP collisions of initialize random seed for random IP addresses 370 rand.Seed(time.Now().UnixNano()) 371 // Add GinkgoParallelNode() on top of the IP address 372 // in case of the same random seed 373 ip3 := strconv.Itoa(rand.Intn(230) + GinkgoParallelNode()) 374 ip4 := strconv.Itoa(rand.Intn(230) + GinkgoParallelNode()) 375 return "10.88." + ip3 + "." + ip4 376 } 377 378 // RunTopContainer runs a simple container in the background that 379 // runs top. If the name passed != "", it will have a name 380 func (p *PodmanTestIntegration) RunTopContainer(name string) *PodmanSessionIntegration { 381 var podmanArgs = []string{"run"} 382 if name != "" { 383 podmanArgs = append(podmanArgs, "--name", name) 384 } 385 podmanArgs = append(podmanArgs, "-d", ALPINE, "top") 386 return p.Podman(podmanArgs) 387 } 388 389 // RunLsContainer runs a simple container in the background that 390 // simply runs ls. If the name passed != "", it will have a name 391 func (p *PodmanTestIntegration) RunLsContainer(name string) (*PodmanSessionIntegration, int, string) { 392 var podmanArgs = []string{"run"} 393 if name != "" { 394 podmanArgs = append(podmanArgs, "--name", name) 395 } 396 podmanArgs = append(podmanArgs, "-d", ALPINE, "ls") 397 session := p.Podman(podmanArgs) 398 session.WaitWithDefaultTimeout() 399 return session, session.ExitCode(), session.OutputToString() 400 } 401 402 // RunNginxWithHealthCheck runs the alpine nginx container with an optional name and adds a healthcheck into it 403 func (p *PodmanTestIntegration) RunNginxWithHealthCheck(name string) (*PodmanSessionIntegration, string) { 404 var podmanArgs = []string{"run"} 405 if name != "" { 406 podmanArgs = append(podmanArgs, "--name", name) 407 } 408 podmanArgs = append(podmanArgs, "-dt", "-P", "--health-cmd", "curl http://localhost/", nginx) 409 session := p.Podman(podmanArgs) 410 session.WaitWithDefaultTimeout() 411 return session, session.OutputToString() 412 } 413 414 func (p *PodmanTestIntegration) RunLsContainerInPod(name, pod string) (*PodmanSessionIntegration, int, string) { 415 var podmanArgs = []string{"run", "--pod", pod} 416 if name != "" { 417 podmanArgs = append(podmanArgs, "--name", name) 418 } 419 podmanArgs = append(podmanArgs, "-d", ALPINE, "ls") 420 session := p.Podman(podmanArgs) 421 session.WaitWithDefaultTimeout() 422 return session, session.ExitCode(), session.OutputToString() 423 } 424 425 // BuildImage uses podman build and buildah to build an image 426 // called imageName based on a string dockerfile 427 func (p *PodmanTestIntegration) BuildImage(dockerfile, imageName string, layers string) { 428 dockerfilePath := filepath.Join(p.TempDir, "Dockerfile") 429 err := ioutil.WriteFile(dockerfilePath, []byte(dockerfile), 0755) 430 Expect(err).To(BeNil()) 431 session := p.Podman([]string{"build", "--layers=" + layers, "-t", imageName, "--file", dockerfilePath, p.TempDir}) 432 session.Wait(120) 433 Expect(session).Should(Exit(0), fmt.Sprintf("BuildImage session output: %q", session.OutputToString())) 434 } 435 436 // PodmanPID execs podman and returns its PID 437 func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegration, int) { 438 podmanOptions := p.MakeOptions(args, false, false) 439 fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " ")) 440 command := exec.Command(p.PodmanBinary, podmanOptions...) 441 session, err := Start(command, GinkgoWriter, GinkgoWriter) 442 if err != nil { 443 Fail(fmt.Sprintf("unable to run podman command: %s", strings.Join(podmanOptions, " "))) 444 } 445 podmanSession := &PodmanSession{session} 446 return &PodmanSessionIntegration{podmanSession}, command.Process.Pid 447 } 448 449 // Cleanup cleans up the temporary store 450 func (p *PodmanTestIntegration) Cleanup() { 451 // Remove all containers 452 stopall := p.Podman([]string{"stop", "-a", "--time", "0"}) 453 stopall.WaitWithDefaultTimeout() 454 455 podstop := p.Podman([]string{"pod", "stop", "-a", "-t", "0"}) 456 podstop.WaitWithDefaultTimeout() 457 podrm := p.Podman([]string{"pod", "rm", "-fa"}) 458 podrm.WaitWithDefaultTimeout() 459 460 session := p.Podman([]string{"rm", "-fa"}) 461 session.WaitWithDefaultTimeout() 462 463 p.StopRemoteService() 464 // Nuke tempdir 465 if err := os.RemoveAll(p.TempDir); err != nil { 466 fmt.Printf("%q\n", err) 467 } 468 469 // Clean up the registries configuration file ENV variable set in Create 470 resetRegistriesConfigEnv() 471 } 472 473 // CleanupVolume cleans up the temporary store 474 func (p *PodmanTestIntegration) CleanupVolume() { 475 // Remove all containers 476 session := p.Podman([]string{"volume", "rm", "-fa"}) 477 session.Wait(90) 478 479 // Stop remove service on volume cleanup 480 p.StopRemoteService() 481 482 // Nuke tempdir 483 if err := os.RemoveAll(p.TempDir); err != nil { 484 fmt.Printf("%q\n", err) 485 } 486 } 487 488 // InspectContainerToJSON takes the session output of an inspect 489 // container and returns json 490 func (s *PodmanSessionIntegration) InspectContainerToJSON() []define.InspectContainerData { 491 var i []define.InspectContainerData 492 err := jsoniter.Unmarshal(s.Out.Contents(), &i) 493 Expect(err).To(BeNil()) 494 return i 495 } 496 497 // InspectPodToJSON takes the sessions output from a pod inspect and returns json 498 func (s *PodmanSessionIntegration) InspectPodToJSON() define.InspectPodData { 499 var i define.InspectPodData 500 err := jsoniter.Unmarshal(s.Out.Contents(), &i) 501 Expect(err).To(BeNil()) 502 return i 503 } 504 505 // InspectPodToJSON takes the sessions output from an inspect and returns json 506 func (s *PodmanSessionIntegration) InspectPodArrToJSON() []define.InspectPodData { 507 var i []define.InspectPodData 508 err := jsoniter.Unmarshal(s.Out.Contents(), &i) 509 Expect(err).To(BeNil()) 510 return i 511 } 512 513 // CreatePod creates a pod with no infra container 514 // it optionally takes a pod name 515 func (p *PodmanTestIntegration) CreatePod(name string) (*PodmanSessionIntegration, int, string) { 516 var podmanArgs = []string{"pod", "create", "--infra=false", "--share", ""} 517 if name != "" { 518 podmanArgs = append(podmanArgs, "--name", name) 519 } 520 session := p.Podman(podmanArgs) 521 session.WaitWithDefaultTimeout() 522 return session, session.ExitCode(), session.OutputToString() 523 } 524 525 // CreatePod creates a pod with no infra container and some labels. 526 // it optionally takes a pod name 527 func (p *PodmanTestIntegration) CreatePodWithLabels(name string, labels map[string]string) (*PodmanSessionIntegration, int, string) { 528 var podmanArgs = []string{"pod", "create", "--infra=false", "--share", ""} 529 if name != "" { 530 podmanArgs = append(podmanArgs, "--name", name) 531 } 532 for labelKey, labelValue := range labels { 533 podmanArgs = append(podmanArgs, "--label", fmt.Sprintf("%s=%s", labelKey, labelValue)) 534 } 535 session := p.Podman(podmanArgs) 536 session.WaitWithDefaultTimeout() 537 return session, session.ExitCode(), session.OutputToString() 538 } 539 540 func (p *PodmanTestIntegration) RunTopContainerInPod(name, pod string) *PodmanSessionIntegration { 541 var podmanArgs = []string{"run", "--pod", pod} 542 if name != "" { 543 podmanArgs = append(podmanArgs, "--name", name) 544 } 545 podmanArgs = append(podmanArgs, "-d", ALPINE, "top") 546 return p.Podman(podmanArgs) 547 } 548 549 func (p *PodmanTestIntegration) RunHealthCheck(cid string) error { 550 for i := 0; i < 10; i++ { 551 hc := p.Podman([]string{"healthcheck", "run", cid}) 552 hc.WaitWithDefaultTimeout() 553 if hc.ExitCode() == 0 { 554 return nil 555 } 556 // Restart container if it's not running 557 ps := p.Podman([]string{"ps", "--no-trunc", "--quiet", "--filter", fmt.Sprintf("id=%s", cid)}) 558 ps.WaitWithDefaultTimeout() 559 if ps.ExitCode() == 0 { 560 if !strings.Contains(ps.OutputToString(), cid) { 561 fmt.Printf("Container %s is not running, restarting", cid) 562 restart := p.Podman([]string{"restart", cid}) 563 restart.WaitWithDefaultTimeout() 564 if restart.ExitCode() != 0 { 565 return errors.Errorf("unable to restart %s", cid) 566 } 567 } 568 } 569 fmt.Printf("Waiting for %s to pass healthcheck\n", cid) 570 time.Sleep(1 * time.Second) 571 } 572 return errors.Errorf("unable to detect %s as running", cid) 573 } 574 575 func (p *PodmanTestIntegration) CreateSeccompJson(in []byte) (string, error) { 576 jsonFile := filepath.Join(p.TempDir, "seccomp.json") 577 err := WriteJsonFile(in, jsonFile) 578 if err != nil { 579 return "", err 580 } 581 return jsonFile, nil 582 } 583 584 func checkReason(reason string) { 585 if len(reason) < 5 { 586 panic("Test must specify a reason to skip") 587 } 588 } 589 590 func SkipIfRootlessCgroupsV1(reason string) { 591 checkReason(reason) 592 if os.Geteuid() != 0 && !CGROUPSV2 { 593 Skip("[rootless]: " + reason) 594 } 595 } 596 597 func SkipIfUnprivilegedCPULimits() { 598 info := GetHostDistributionInfo() 599 if isRootless() && info.Distribution == "fedora" { 600 ginkgo.Skip("Rootless Fedora doesn't have permission to set CPU limits") 601 } 602 } 603 604 func SkipIfRootless(reason string) { 605 checkReason(reason) 606 if os.Geteuid() != 0 { 607 ginkgo.Skip("[rootless]: " + reason) 608 } 609 } 610 611 func SkipIfNotRootless(reason string) { 612 checkReason(reason) 613 if os.Geteuid() == 0 { 614 ginkgo.Skip("[notRootless]: " + reason) 615 } 616 } 617 618 func SkipIfNotFedora() { 619 info := GetHostDistributionInfo() 620 if info.Distribution != "fedora" { 621 ginkgo.Skip("Test can only run on Fedora") 622 } 623 } 624 625 func isRootless() bool { 626 return os.Geteuid() != 0 627 } 628 629 func SkipIfCgroupV1(reason string) { 630 checkReason(reason) 631 if !CGROUPSV2 { 632 Skip(reason) 633 } 634 } 635 636 func SkipIfCgroupV2(reason string) { 637 checkReason(reason) 638 if CGROUPSV2 { 639 Skip(reason) 640 } 641 } 642 643 func isContainerized() bool { 644 // This is set to "podman" by podman automatically 645 if os.Getenv("container") != "" { 646 return true 647 } 648 return false 649 } 650 651 func SkipIfContainerized(reason string) { 652 checkReason(reason) 653 if isContainerized() { 654 Skip(reason) 655 } 656 } 657 658 // PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment 659 func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { 660 podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil) 661 return &PodmanSessionIntegration{podmanSession} 662 } 663 664 // We don't support running Varlink when local 665 func (p *PodmanTestIntegration) RestartRemoteService() { 666 p.StopRemoteService() 667 p.StartRemoteService() 668 } 669 670 // RestoreArtifactToCache populates the imagecache from tarballs that were cached earlier 671 func (p *PodmanTestIntegration) RestoreArtifactToCache(image string) error { 672 fmt.Printf("Restoring %s...\n", image) 673 dest := strings.Split(image, "/") 674 destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1)) 675 p.CrioRoot = p.ImageCacheDir 676 restore := p.PodmanNoEvents([]string{"load", "-q", "-i", destName}) 677 restore.WaitWithDefaultTimeout() 678 return nil 679 } 680 681 func populateCache(podman *PodmanTestIntegration) { 682 for _, image := range CACHE_IMAGES { 683 podman.RestoreArtifactToCache(image) 684 } 685 // logformatter uses this to recognize the first test 686 fmt.Printf("-----------------------------\n") 687 } 688 689 func removeCache() { 690 // Remove cache dirs 691 if err := os.RemoveAll(ImageCacheDir); err != nil { 692 fmt.Printf("%q\n", err) 693 } 694 } 695 696 // PodmanNoCache calls the podman command with no configured imagecache 697 func (p *PodmanTestIntegration) PodmanNoCache(args []string) *PodmanSessionIntegration { 698 podmanSession := p.PodmanBase(args, false, true) 699 return &PodmanSessionIntegration{podmanSession} 700 } 701 702 func PodmanTestSetup(tempDir string) *PodmanTestIntegration { 703 return PodmanTestCreateUtil(tempDir, false) 704 } 705 706 // PodmanNoEvents calls the Podman command without an imagecache and without an 707 // events backend. It is used mostly for caching and uncaching images. 708 func (p *PodmanTestIntegration) PodmanNoEvents(args []string) *PodmanSessionIntegration { 709 podmanSession := p.PodmanBase(args, true, true) 710 return &PodmanSessionIntegration{podmanSession} 711 } 712 713 // MakeOptions assembles all the podman main options 714 func (p *PodmanTestIntegration) makeOptions(args []string, noEvents, noCache bool) []string { 715 if p.RemoteTest { 716 return args 717 } 718 var debug string 719 if _, ok := os.LookupEnv("DEBUG"); ok { 720 debug = "--log-level=debug --syslog=true " 721 } 722 723 eventsType := "file" 724 if noEvents { 725 eventsType = "none" 726 } 727 728 podmanOptions := strings.Split(fmt.Sprintf("%s--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s --tmpdir %s --events-backend %s", 729 debug, p.CrioRoot, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager, p.TmpDir, eventsType), " ") 730 if os.Getenv("HOOK_OPTION") != "" { 731 podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) 732 } 733 734 podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...) 735 if !noCache { 736 cacheOptions := []string{"--storage-opt", 737 fmt.Sprintf("%s.imagestore=%s", p.PodmanTest.ImageCacheFS, p.PodmanTest.ImageCacheDir)} 738 podmanOptions = append(cacheOptions, podmanOptions...) 739 } 740 podmanOptions = append(podmanOptions, args...) 741 return podmanOptions 742 } 743 744 func writeConf(conf []byte, confPath string) { 745 if err := ioutil.WriteFile(confPath, conf, 777); err != nil { 746 fmt.Println(err) 747 } 748 } 749 750 func removeConf(confPath string) { 751 if err := os.Remove(confPath); err != nil { 752 fmt.Println(err) 753 } 754 } 755 756 // generateNetworkConfig generates a cni config with a random name 757 // it returns the network name and the filepath 758 func generateNetworkConfig(p *PodmanTestIntegration) (string, string) { 759 // generate a random name to prevent conflicts with other tests 760 name := "net" + stringid.GenerateNonCryptoID() 761 path := filepath.Join(p.CNIConfigDir, fmt.Sprintf("%s.conflist", name)) 762 conf := fmt.Sprintf(`{ 763 "cniVersion": "0.3.0", 764 "name": "%s", 765 "plugins": [ 766 { 767 "type": "bridge", 768 "bridge": "cni1", 769 "isGateway": true, 770 "ipMasq": true, 771 "ipam": { 772 "type": "host-local", 773 "subnet": "10.99.0.0/16", 774 "routes": [ 775 { "dst": "0.0.0.0/0" } 776 ] 777 } 778 }, 779 { 780 "type": "portmap", 781 "capabilities": { 782 "portMappings": true 783 } 784 } 785 ] 786 }`, name) 787 writeConf([]byte(conf), path) 788 789 return name, path 790 }