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  }