github.com/containers/podman/v4@v4.9.4/pkg/bindings/test/common_test.go (about)

     1  package bindings_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/containers/podman/v4/libpod/define"
    13  	. "github.com/containers/podman/v4/pkg/bindings"
    14  	"github.com/containers/podman/v4/pkg/bindings/containers"
    15  	"github.com/containers/podman/v4/pkg/specgen"
    16  	"github.com/onsi/ginkgo/v2"
    17  	. "github.com/onsi/gomega"
    18  	. "github.com/onsi/gomega/gexec"
    19  )
    20  
    21  type testImage struct {
    22  	name        string
    23  	shortName   string
    24  	tarballName string
    25  }
    26  
    27  const (
    28  	devPodmanBinaryLocation     string = "../../../bin/podman"
    29  	defaultPodmanBinaryLocation string = "/usr/bin/podman"
    30  )
    31  
    32  func getPodmanBinary() string {
    33  	_, err := os.Stat(devPodmanBinaryLocation)
    34  	if os.IsNotExist(err) {
    35  		return defaultPodmanBinaryLocation
    36  	}
    37  	return devPodmanBinaryLocation
    38  }
    39  
    40  var (
    41  	ImageCacheDir = "/tmp/podman/imagecachedir"
    42  	LockTmpDir    string
    43  	alpine        = testImage{
    44  		name:        "docker.io/library/alpine:latest",
    45  		shortName:   "alpine",
    46  		tarballName: "alpine.tar",
    47  	}
    48  	busybox = testImage{
    49  		name:        "docker.io/library/busybox:latest",
    50  		shortName:   "busybox",
    51  		tarballName: "busybox.tar",
    52  	}
    53  	CACHE_IMAGES = []testImage{alpine, busybox} //nolint:revive,stylecheck
    54  )
    55  
    56  type bindingTest struct {
    57  	artifactDirPath string
    58  	imageCacheDir   string
    59  	sock            string
    60  	tempDirPath     string
    61  	runRoot         string
    62  	crioRoot        string
    63  	conn            context.Context
    64  }
    65  
    66  func (b *bindingTest) NewConnection() error {
    67  	connText, err := NewConnection(context.Background(), b.sock)
    68  	if err != nil {
    69  		return err
    70  	}
    71  	b.conn = connText
    72  	return nil
    73  }
    74  
    75  func (b *bindingTest) runPodman(command []string) *Session {
    76  	var cmd []string
    77  	podmanBinary := getPodmanBinary()
    78  	val, ok := os.LookupEnv("PODMAN_BINARY")
    79  	if ok {
    80  		podmanBinary = val
    81  	}
    82  	val, ok = os.LookupEnv("CGROUP_MANAGER")
    83  	if ok {
    84  		cmd = append(cmd, "--cgroup-manager", val)
    85  	}
    86  	val, ok = os.LookupEnv("CNI_CONFIG_DIR")
    87  	if ok {
    88  		cmd = append(cmd, "--network-config-dir", val)
    89  	}
    90  	val, ok = os.LookupEnv("CONMON")
    91  	if ok {
    92  		cmd = append(cmd, "--conmon", val)
    93  	}
    94  	val, ok = os.LookupEnv("ROOT")
    95  	if ok {
    96  		cmd = append(cmd, "--root", val)
    97  	} else {
    98  		cmd = append(cmd, "--root", b.crioRoot)
    99  	}
   100  	val, ok = os.LookupEnv("OCI_RUNTIME")
   101  	if ok {
   102  		cmd = append(cmd, "--runtime", val)
   103  	}
   104  	val, ok = os.LookupEnv("RUNROOT")
   105  	if ok {
   106  		cmd = append(cmd, "--runroot", val)
   107  	} else {
   108  		cmd = append(cmd, "--runroot", b.runRoot)
   109  	}
   110  	val, ok = os.LookupEnv("TEMPDIR")
   111  	if ok {
   112  		cmd = append(cmd, "--tmpdir", val)
   113  	} else {
   114  		cmd = append(cmd, "--tmpdir", b.tempDirPath)
   115  	}
   116  	val, ok = os.LookupEnv("STORAGE_DRIVER")
   117  	if ok {
   118  		cmd = append(cmd, "--storage-driver", val)
   119  	}
   120  	val, ok = os.LookupEnv("STORAGE_OPTIONS")
   121  	if ok {
   122  		cmd = append(cmd, "--storage", val)
   123  	}
   124  	cmd = append(cmd, command...)
   125  	c := exec.Command(podmanBinary, cmd...)
   126  	fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(cmd, " "))
   127  	session, err := Start(c, ginkgo.GinkgoWriter, ginkgo.GinkgoWriter)
   128  	if err != nil {
   129  		panic(fmt.Errorf("unable to run podman command: %q", cmd))
   130  	}
   131  	return session
   132  }
   133  
   134  func newBindingTest() *bindingTest {
   135  	tmpPath, _ := createTempDirInTempDir()
   136  	b := bindingTest{
   137  		crioRoot:        filepath.Join(tmpPath, "crio"),
   138  		runRoot:         filepath.Join(tmpPath, "run"),
   139  		artifactDirPath: "",
   140  		imageCacheDir:   "",
   141  		sock:            fmt.Sprintf("unix://%s", filepath.Join(tmpPath, "api.sock")),
   142  		tempDirPath:     tmpPath,
   143  	}
   144  	return &b
   145  }
   146  
   147  // createTempDirinTempDir create a temp dir with prefix podman_test
   148  func createTempDirInTempDir() (string, error) {
   149  	return os.MkdirTemp("", "libpod_api")
   150  }
   151  
   152  func (b *bindingTest) startAPIService() *Session {
   153  	cmd := []string{"--log-level=debug", "system", "service", "--timeout=0", b.sock}
   154  	session := b.runPodman(cmd)
   155  
   156  	sock := strings.TrimPrefix(b.sock, "unix://")
   157  	for i := 0; i < 10; i++ {
   158  		if _, err := os.Stat(sock); err != nil {
   159  			if !os.IsNotExist(err) {
   160  				break
   161  			}
   162  			time.Sleep(time.Second)
   163  			continue
   164  		}
   165  		break
   166  	}
   167  	return session
   168  }
   169  
   170  func (b *bindingTest) cleanup() {
   171  	s := b.runPodman([]string{"stop", "-a", "-t", "0"})
   172  	s.Wait(45)
   173  	if err := os.RemoveAll(b.tempDirPath); err != nil {
   174  		fmt.Println(err)
   175  	}
   176  }
   177  
   178  // Pull is a helper function to pull in images
   179  func (b *bindingTest) Pull(name string) {
   180  	p := b.runPodman([]string{"pull", name})
   181  	p.Wait(45)
   182  	Expect(p).To(Exit(0))
   183  }
   184  
   185  func (b *bindingTest) Save(i testImage) {
   186  	p := b.runPodman([]string{"save", "-o", filepath.Join(ImageCacheDir, i.tarballName), i.name})
   187  	p.Wait(45)
   188  	Expect(p).To(Exit(0))
   189  }
   190  
   191  func (b *bindingTest) RestoreImagesFromCache() {
   192  	for _, i := range CACHE_IMAGES {
   193  		b.restoreImageFromCache(i)
   194  	}
   195  }
   196  func (b *bindingTest) restoreImageFromCache(i testImage) {
   197  	p := b.runPodman([]string{"load", "-i", filepath.Join(ImageCacheDir, i.tarballName)})
   198  	p.Wait(45)
   199  	Expect(p).To(Exit(0))
   200  }
   201  
   202  // Run a container within or without a pod
   203  // and add or append the alpine image to it
   204  func (b *bindingTest) RunTopContainer(containerName *string, podName *string) (string, error) {
   205  	s := specgen.NewSpecGenerator(alpine.name, false)
   206  	s.Terminal = false
   207  	s.Command = []string{"/usr/bin/top"}
   208  	if containerName != nil {
   209  		s.Name = *containerName
   210  	}
   211  	if podName != nil {
   212  		s.Pod = *podName
   213  	}
   214  	ctr, err := containers.CreateWithSpec(b.conn, s, nil)
   215  	if err != nil {
   216  		return "", err
   217  	}
   218  	err = containers.Start(b.conn, ctr.ID, nil)
   219  	if err != nil {
   220  		return "", err
   221  	}
   222  	wait := define.ContainerStateRunning
   223  	_, err = containers.Wait(b.conn, ctr.ID, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{wait}))
   224  	return ctr.ID, err
   225  }
   226  
   227  // This method creates a pod with the given pod name.
   228  // Podname is an optional parameter
   229  func (b *bindingTest) Podcreate(name *string) {
   230  	b.PodcreateAndExpose(name, nil)
   231  }
   232  
   233  // This method creates a pod with the given pod name and publish port.
   234  // Podname is an optional parameter
   235  // port is an optional parameter
   236  func (b *bindingTest) PodcreateAndExpose(name *string, port *string) {
   237  	command := []string{"pod", "create"}
   238  	if name != nil {
   239  		podname := *name
   240  		command = append(command, "--name", podname)
   241  	}
   242  	if port != nil {
   243  		podport := *port
   244  		command = append(command, "--publish", podport)
   245  	}
   246  	b.runPodman(command).Wait(45)
   247  }
   248  
   249  // StringInSlice returns a boolean based on whether a given
   250  // string is in a given slice
   251  func StringInSlice(s string, sl []string) bool {
   252  	for _, val := range sl {
   253  		if s == val {
   254  			return true
   255  		}
   256  	}
   257  	return false
   258  }
   259  
   260  var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
   261  	// make cache dir
   262  	err := os.MkdirAll(ImageCacheDir, 0777)
   263  	Expect(err).ToNot(HaveOccurred())
   264  
   265  	// If running localized tests, the cache dir is created and populated. if the
   266  	// tests are remote, this is a no-op
   267  	createCache()
   268  	path, err := os.MkdirTemp("", "libpodlock")
   269  	Expect(err).ToNot(HaveOccurred())
   270  
   271  	return []byte(path)
   272  }, func(data []byte) {
   273  	LockTmpDir = string(data)
   274  })
   275  
   276  func createCache() {
   277  	b := newBindingTest()
   278  	for _, i := range CACHE_IMAGES {
   279  		_, err := os.Stat(filepath.Join(ImageCacheDir, i.tarballName))
   280  		if os.IsNotExist(err) {
   281  			//	pull the image
   282  			b.Pull(i.name)
   283  			b.Save(i)
   284  		}
   285  	}
   286  	b.cleanup()
   287  }
   288  
   289  func isStopped(state string) bool {
   290  	return state == "exited" || state == "stopped"
   291  }