github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/info_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"os/user"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strconv"
    11  
    12  	. "github.com/containers/podman/v5/test/utils"
    13  	. "github.com/onsi/ginkgo/v2"
    14  	. "github.com/onsi/gomega"
    15  	. "github.com/onsi/gomega/gexec"
    16  )
    17  
    18  var _ = Describe("Podman Info", func() {
    19  
    20  	It("podman info --format json", func() {
    21  		tests := []struct {
    22  			input    string
    23  			success  bool
    24  			exitCode int
    25  		}{
    26  			{"json", true, 0},
    27  			{" json", true, 0},
    28  			{"json ", true, 0},
    29  			{"  json   ", true, 0},
    30  			{"{{json .}}", true, 0},
    31  			{"{{ json .}}", true, 0},
    32  			{"{{json .   }}", true, 0},
    33  			{"  {{  json .    }}   ", true, 0},
    34  			{"{{json }}", true, 0},
    35  			{"{{json .", false, 125},
    36  			{"json . }}", false, 0}, // without opening {{ template seen as string literal
    37  		}
    38  		for _, tt := range tests {
    39  			session := podmanTest.Podman([]string{"info", "--format", tt.input})
    40  			session.WaitWithDefaultTimeout()
    41  
    42  			desc := fmt.Sprintf("JSON test(%q)", tt.input)
    43  			Expect(session).Should(Exit(tt.exitCode), desc)
    44  			Expect(session.IsJSONOutputValid()).To(Equal(tt.success), desc)
    45  		}
    46  	})
    47  
    48  	It("podman info --format GO template", func() {
    49  		session := podmanTest.Podman([]string{"info", "--format", "{{.Store.GraphRoot}}"})
    50  		session.WaitWithDefaultTimeout()
    51  		Expect(session).Should(ExitCleanly())
    52  	})
    53  
    54  	It("podman info --format GO template", func() {
    55  		session := podmanTest.Podman([]string{"info", "--format", "{{.Registries}}"})
    56  		session.WaitWithDefaultTimeout()
    57  		Expect(session).Should(ExitCleanly())
    58  		Expect(session.OutputToString()).To(ContainSubstring("registry"))
    59  	})
    60  
    61  	It("podman info --format GO template plugins", func() {
    62  		session := podmanTest.Podman([]string{"info", "--format", "{{.Plugins}}"})
    63  		session.WaitWithDefaultTimeout()
    64  		Expect(session).Should(ExitCleanly())
    65  		Expect(session.OutputToString()).To(ContainSubstring("local"))
    66  		Expect(session.OutputToString()).To(ContainSubstring("journald"))
    67  		Expect(session.OutputToString()).To(ContainSubstring("bridge"))
    68  	})
    69  
    70  	It("podman info rootless storage path", func() {
    71  		SkipIfNotRootless("test of rootless_storage_path is only meaningful as rootless")
    72  		SkipIfRemote("Only tests storage on local client")
    73  		configPath := filepath.Join(podmanTest.TempDir, ".config", "containers", "storage.conf")
    74  		os.Setenv("CONTAINERS_STORAGE_CONF", configPath)
    75  		defer func() {
    76  			os.Unsetenv("CONTAINERS_STORAGE_CONF")
    77  		}()
    78  		err := os.RemoveAll(filepath.Dir(configPath))
    79  		Expect(err).ToNot(HaveOccurred())
    80  
    81  		err = os.MkdirAll(filepath.Dir(configPath), os.ModePerm)
    82  		Expect(err).ToNot(HaveOccurred())
    83  
    84  		rootlessStoragePath := `"/tmp/$HOME/$USER/$UID/storage"`
    85  		driver := `"overlay"`
    86  		storageConf := []byte(fmt.Sprintf("[storage]\ndriver=%s\nrootless_storage_path=%s\n[storage.options]\n", driver, rootlessStoragePath))
    87  		err = os.WriteFile(configPath, storageConf, os.ModePerm)
    88  		Expect(err).ToNot(HaveOccurred())
    89  		// Failures in this test are impossible to debug without breadcrumbs
    90  		GinkgoWriter.Printf("CONTAINERS_STORAGE_CONF=%s:\n%s\n", configPath, storageConf)
    91  
    92  		u, err := user.Current()
    93  		Expect(err).ToNot(HaveOccurred())
    94  
    95  		// Cannot use podmanTest.Podman() and test for storage path
    96  		expect := filepath.Join("/tmp", os.Getenv("HOME"), u.Username, u.Uid, "storage")
    97  		podmanPath := podmanTest.PodmanTest.PodmanBinary
    98  		cmd := exec.Command(podmanPath, "info", "--format", "{{.Store.GraphRoot -}}")
    99  		out, err := cmd.CombinedOutput()
   100  		GinkgoWriter.Printf("Running: podman info --format {{.Store.GraphRoot -}}\nOutput: %s\n", string(out))
   101  		Expect(err).ToNot(HaveOccurred(), "podman info")
   102  		Expect(string(out)).To(Equal(expect), "output from podman info")
   103  	})
   104  
   105  	It("check RemoteSocket ", func() {
   106  		session := podmanTest.Podman([]string{"info", "--format", "{{.Host.RemoteSocket.Path}}"})
   107  		session.WaitWithDefaultTimeout()
   108  		Expect(session).Should(ExitCleanly())
   109  		Expect(session.OutputToString()).To(MatchRegexp("/run/.*podman.*sock"))
   110  
   111  		session = podmanTest.Podman([]string{"info", "--format", "{{.Host.ServiceIsRemote}}"})
   112  		session.WaitWithDefaultTimeout()
   113  		Expect(session).Should(ExitCleanly())
   114  		if podmanTest.RemoteTest {
   115  			Expect(session.OutputToString()).To(Equal("true"))
   116  		} else {
   117  			Expect(session.OutputToString()).To(Equal("false"))
   118  		}
   119  
   120  		session = podmanTest.Podman([]string{"info", "--format", "{{.Host.RemoteSocket.Exists}}"})
   121  		session.WaitWithDefaultTimeout()
   122  		Expect(session).Should(ExitCleanly())
   123  		if IsRemote() {
   124  			Expect(session.OutputToString()).To(ContainSubstring("true"))
   125  		} else {
   126  			Expect(session.OutputToString()).To(ContainSubstring("false"))
   127  		}
   128  
   129  	})
   130  
   131  	It("Podman info must contain cgroupControllers with RelevantControllers", func() {
   132  		SkipIfRootless("Hard to tell which controllers are going to be enabled for rootless")
   133  		SkipIfRootlessCgroupsV1("Disable cgroups not supported on cgroupv1 for rootless users")
   134  		session := podmanTest.Podman([]string{"info", "--format", "{{.Host.CgroupControllers}}"})
   135  		session.WaitWithDefaultTimeout()
   136  		Expect(session).To(ExitCleanly())
   137  		Expect(session.OutputToString()).To(ContainSubstring("memory"))
   138  		Expect(session.OutputToString()).To(ContainSubstring("pids"))
   139  	})
   140  
   141  	It("Podman info: check desired runtime", func() {
   142  		// defined in .cirrus.yml
   143  		want := os.Getenv("CI_DESIRED_RUNTIME")
   144  		if want == "" {
   145  			if os.Getenv("CIRRUS_CI") == "" {
   146  				Skip("CI_DESIRED_RUNTIME is not set--this is OK because we're not running under Cirrus")
   147  			}
   148  			Fail("CIRRUS_CI is set, but CI_DESIRED_RUNTIME is not! See #14912")
   149  		}
   150  		session := podmanTest.Podman([]string{"info", "--format", "{{.Host.OCIRuntime.Name}}"})
   151  		session.WaitWithDefaultTimeout()
   152  		Expect(session).To(ExitCleanly())
   153  		Expect(session.OutputToString()).To(Equal(want))
   154  	})
   155  
   156  	It("Podman info: check desired network backend", func() {
   157  		session := podmanTest.Podman([]string{"info", "--format", "{{.Host.NetworkBackend}}"})
   158  		session.WaitWithDefaultTimeout()
   159  		Expect(session).To(ExitCleanly())
   160  		Expect(session.OutputToString()).To(Equal("netavark"))
   161  
   162  		session = podmanTest.Podman([]string{"info", "--format", "{{.Host.NetworkBackendInfo.Backend}}"})
   163  		session.WaitWithDefaultTimeout()
   164  		Expect(session).To(ExitCleanly())
   165  		Expect(session.OutputToString()).To(Equal("netavark"))
   166  	})
   167  
   168  	It("Podman info: check desired database backend", func() {
   169  		// defined in .cirrus.yml
   170  		want := os.Getenv("CI_DESIRED_DATABASE")
   171  		if want == "" {
   172  			if os.Getenv("CIRRUS_CI") == "" {
   173  				Skip("CI_DESIRED_DATABASE is not set--this is OK because we're not running under Cirrus")
   174  			}
   175  			Fail("CIRRUS_CI is set, but CI_DESIRED_DATABASE is not! See #16389")
   176  		}
   177  		session := podmanTest.Podman([]string{"info", "--format", "{{.Host.DatabaseBackend}}"})
   178  		session.WaitWithDefaultTimeout()
   179  		Expect(session).To(ExitCleanly())
   180  		Expect(session.OutputToString()).To(Equal(want))
   181  	})
   182  
   183  	It("podman --db-backend info basic check", Serial, func() {
   184  		SkipIfRemote("--db-backend only supported on the local client")
   185  
   186  		const desiredDB = "CI_DESIRED_DATABASE"
   187  
   188  		type argWant struct {
   189  			arg  string
   190  			want string
   191  		}
   192  		backends := []argWant{
   193  			// default should be sqlite
   194  			{arg: "", want: "sqlite"},
   195  			{arg: "boltdb", want: "boltdb"},
   196  			// now because a boltdb exists it should use boltdb when default is requested
   197  			{arg: "", want: "boltdb"},
   198  			{arg: "sqlite", want: "sqlite"},
   199  			// just because we requested sqlite doesn't mean it stays that way.
   200  			// once a boltdb exists, podman will forevermore stick with it
   201  			{arg: "", want: "boltdb"},
   202  		}
   203  
   204  		for _, tt := range backends {
   205  			oldDesiredDB := os.Getenv(desiredDB)
   206  			if tt.arg == "boltdb" {
   207  				err := os.Setenv(desiredDB, "boltdb")
   208  				Expect(err).To(Not(HaveOccurred()))
   209  				defer os.Setenv(desiredDB, oldDesiredDB)
   210  			}
   211  
   212  			session := podmanTest.Podman([]string{"--db-backend", tt.arg, "--log-level=info", "info", "--format", "{{.Host.DatabaseBackend}}"})
   213  			session.WaitWithDefaultTimeout()
   214  			Expect(session).To(Exit(0))
   215  			Expect(session.OutputToString()).To(Equal(tt.want))
   216  			Expect(session.ErrorToString()).To(ContainSubstring("Using %s as database backend", tt.want))
   217  
   218  			if tt.arg == "boltdb" {
   219  				err := os.Setenv(desiredDB, oldDesiredDB)
   220  				Expect(err).To(Not(HaveOccurred()))
   221  			}
   222  		}
   223  
   224  		// make sure we get an error for bogus values
   225  		session := podmanTest.Podman([]string{"--db-backend", "bogus", "info", "--format", "{{.Host.DatabaseBackend}}"})
   226  		session.WaitWithDefaultTimeout()
   227  		Expect(session).To(Exit(125))
   228  		Expect(session.ErrorToString()).To(Equal("Error: unsupported database backend: \"bogus\""))
   229  	})
   230  
   231  	It("Podman info: check desired storage driver", func() {
   232  		// defined in .cirrus.yml
   233  		want := os.Getenv("CI_DESIRED_STORAGE")
   234  		if want == "" {
   235  			if os.Getenv("CIRRUS_CI") == "" {
   236  				Skip("CI_DESIRED_STORAGE is not set--this is OK because we're not running under Cirrus")
   237  			}
   238  			Fail("CIRRUS_CI is set, but CI_DESIRED_STORAGE is not! See #20161")
   239  		}
   240  		session := podmanTest.Podman([]string{"info", "--format", "{{.Store.GraphDriverName}}"})
   241  		session.WaitWithDefaultTimeout()
   242  		Expect(session).To(ExitCleanly())
   243  		Expect(session.OutputToString()).To(Equal(want), ".Store.GraphDriverName from podman info")
   244  	})
   245  
   246  	It("Podman info: check lock count", Serial, func() {
   247  		// This should not run on architectures and OSes that use the file locks backend.
   248  		// Which, for now, is Linux + RISCV and FreeBSD, neither of which are in CI - so
   249  		// no skips.
   250  		info1 := podmanTest.Podman([]string{"info", "--format", "{{ .Host.FreeLocks }}"})
   251  		info1.WaitWithDefaultTimeout()
   252  		Expect(info1).To(ExitCleanly())
   253  		free1, err := strconv.Atoi(info1.OutputToString())
   254  		Expect(err).To(Not(HaveOccurred()))
   255  
   256  		ctr := podmanTest.Podman([]string{"create", ALPINE, "top"})
   257  		ctr.WaitWithDefaultTimeout()
   258  		Expect(ctr).To(ExitCleanly())
   259  
   260  		info2 := podmanTest.Podman([]string{"info", "--format", "{{ .Host.FreeLocks }}"})
   261  		info2.WaitWithDefaultTimeout()
   262  		Expect(info2).To(ExitCleanly())
   263  		free2, err := strconv.Atoi(info2.OutputToString())
   264  		Expect(err).To(Not(HaveOccurred()))
   265  
   266  		// Effectively, we are checking that 1 lock has been taken.
   267  		// We do this by comparing the number of locks after (plus 1), to the number of locks before.
   268  		// Don't check absolute numbers because there is a decent chance of contamination, containers that were never removed properly, etc.
   269  		Expect(free1).To(Equal(free2 + 1))
   270  	})
   271  
   272  	It("Podman info: check for client information when no system service", func() {
   273  		// the output for this information is not really something we can marshall
   274  		want := runtime.GOOS + "/" + runtime.GOARCH
   275  		podmanTest.StopRemoteService()
   276  		SkipIfNotRemote("Specifically testing a failed remote connection")
   277  		info := podmanTest.Podman([]string{"info"})
   278  		info.WaitWithDefaultTimeout()
   279  		Expect(info.OutputToString()).To(ContainSubstring(want))
   280  		Expect(info).ToNot(ExitCleanly())
   281  		podmanTest.StartRemoteService() // Start service again so teardown runs clean
   282  	})
   283  })