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

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"time"
     7  
     8  	. "github.com/containers/podman/v5/test/utils"
     9  	. "github.com/onsi/ginkgo/v2"
    10  	. "github.com/onsi/gomega"
    11  )
    12  
    13  // TODO: we need to check the output. Currently, we only check the exit codes
    14  // which is not enough.
    15  var _ = Describe("Podman stats", func() {
    16  
    17  	BeforeEach(func() {
    18  		SkipIfRootlessCgroupsV1("stats not supported on cgroupv1 for rootless users")
    19  		if isContainerized() {
    20  			SkipIfCgroupV1("stats not supported inside cgroupv1 container environment")
    21  		}
    22  	})
    23  
    24  	It("podman stats with bogus container", func() {
    25  		session := podmanTest.Podman([]string{"stats", "--no-stream", "123"})
    26  		session.WaitWithDefaultTimeout()
    27  		expect := `unable to get list of containers: unable to look up container 123: no container with name or ID "123" found: no such container`
    28  		// FIXME: #22612
    29  		if IsRemote() {
    30  			expect = "types.ContainerStatsReport.Error: decode non empty interface: can not unmarshal into nil, error found in #9 byte"
    31  		}
    32  		Expect(session).Should(ExitWithError(125, expect))
    33  	})
    34  
    35  	It("podman stats on a running container", func() {
    36  		session := podmanTest.RunTopContainer("")
    37  		session.WaitWithDefaultTimeout()
    38  		Expect(session).Should(ExitCleanly())
    39  		cid := session.OutputToString()
    40  		session = podmanTest.Podman([]string{"stats", "--no-stream", cid})
    41  		session.WaitWithDefaultTimeout()
    42  		Expect(session).Should(ExitCleanly())
    43  	})
    44  
    45  	It("podman stats on all containers", func() {
    46  		session := podmanTest.RunTopContainer("")
    47  		session.WaitWithDefaultTimeout()
    48  		Expect(session).Should(ExitCleanly())
    49  		session = podmanTest.Podman([]string{"stats", "--no-stream", "-a"})
    50  		session.WaitWithDefaultTimeout()
    51  		Expect(session).Should(ExitCleanly())
    52  	})
    53  
    54  	It("podman stats on all running containers", func() {
    55  		session := podmanTest.RunTopContainer("")
    56  		session.WaitWithDefaultTimeout()
    57  		Expect(session).Should(ExitCleanly())
    58  		session = podmanTest.Podman([]string{"stats", "--no-stream"})
    59  		session.WaitWithDefaultTimeout()
    60  		Expect(session).Should(ExitCleanly())
    61  	})
    62  
    63  	It("podman stats only output cids", func() {
    64  		session := podmanTest.RunTopContainer("")
    65  		session.WaitWithDefaultTimeout()
    66  		Expect(session).Should(ExitCleanly())
    67  		session = podmanTest.Podman([]string{"stats", "--all", "--no-trunc", "--no-stream", "--format", "\"{{.ID}}\""})
    68  		session.WaitWithDefaultTimeout()
    69  		Expect(session).Should(ExitCleanly())
    70  		Expect(len(session.OutputToStringArray()[0])).Should(BeEquivalentTo(66))
    71  	})
    72  
    73  	It("podman stats with GO template", func() {
    74  		session := podmanTest.RunTopContainer("")
    75  		session.WaitWithDefaultTimeout()
    76  		Expect(session).Should(ExitCleanly())
    77  		stats := podmanTest.Podman([]string{"stats", "-a", "--no-reset", "--no-stream", "--format", "table {{.ID}} {{.AVGCPU}} {{.MemUsage}} {{.CPU}} {{.NetIO}} {{.BlockIO}} {{.PIDS}}"})
    78  		stats.WaitWithDefaultTimeout()
    79  		Expect(stats).To(ExitCleanly())
    80  	})
    81  
    82  	It("podman stats with invalid GO template", func() {
    83  		session := podmanTest.RunTopContainer("")
    84  		session.WaitWithDefaultTimeout()
    85  		Expect(session).Should(ExitCleanly())
    86  		stats := podmanTest.Podman([]string{"stats", "-a", "--no-reset", "--no-stream", "--format", "\"table {{.ID}} {{.NoSuchField}} \""})
    87  		stats.WaitWithDefaultTimeout()
    88  		Expect(stats).To(ExitWithError(125, `template: stats:1:28: executing "stats" at <.NoSuchField>: can't evaluate field NoSuchField in type containers.containerStats`))
    89  	})
    90  
    91  	It("podman stats with negative interval", func() {
    92  		session := podmanTest.RunTopContainer("")
    93  		session.WaitWithDefaultTimeout()
    94  		Expect(session).Should(ExitCleanly())
    95  		stats := podmanTest.Podman([]string{"stats", "-a", "--no-reset", "--no-stream", "--interval=-1"})
    96  		stats.WaitWithDefaultTimeout()
    97  		Expect(stats).To(ExitWithError(125, "invalid interval, must be a positive number greater zero"))
    98  	})
    99  
   100  	It("podman stats with zero interval", func() {
   101  		session := podmanTest.RunTopContainer("")
   102  		session.WaitWithDefaultTimeout()
   103  		Expect(session).Should(ExitCleanly())
   104  		stats := podmanTest.Podman([]string{"stats", "-a", "--no-reset", "--no-stream", "--interval=0"})
   105  		stats.WaitWithDefaultTimeout()
   106  		Expect(stats).To(ExitWithError(125, "invalid interval, must be a positive number greater zero"))
   107  	})
   108  
   109  	It("podman stats with interval", func() {
   110  		session := podmanTest.RunTopContainer("")
   111  		session.WaitWithDefaultTimeout()
   112  		Expect(session).Should(ExitCleanly())
   113  		stats := podmanTest.Podman([]string{"stats", "-a", "--no-reset", "--no-stream", "--interval=5"})
   114  		stats.WaitWithDefaultTimeout()
   115  		Expect(stats).Should(ExitCleanly())
   116  	})
   117  
   118  	It("podman stats with json output", func() {
   119  		var found bool
   120  		session := podmanTest.RunTopContainer("")
   121  		session.WaitWithDefaultTimeout()
   122  		Expect(session).Should(ExitCleanly())
   123  		for i := 0; i < 5; i++ {
   124  			ps := podmanTest.Podman([]string{"ps", "-q"})
   125  			ps.WaitWithDefaultTimeout()
   126  			if len(ps.OutputToStringArray()) == 1 {
   127  				found = true
   128  				break
   129  			}
   130  			time.Sleep(time.Second)
   131  		}
   132  		Expect(found).To(BeTrue(), "container has started")
   133  		stats := podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "json"})
   134  		stats.WaitWithDefaultTimeout()
   135  		Expect(stats).Should(ExitCleanly())
   136  		Expect(stats.OutputToString()).To(BeValidJSON())
   137  	})
   138  
   139  	It("podman stats on a container with no net ns", func() {
   140  		session := podmanTest.Podman([]string{"run", "-d", "--net", "none", ALPINE, "top"})
   141  		session.WaitWithDefaultTimeout()
   142  		Expect(session).Should(ExitCleanly())
   143  		session = podmanTest.Podman([]string{"stats", "--no-stream", "-a"})
   144  		session.WaitWithDefaultTimeout()
   145  		Expect(session).Should(ExitCleanly())
   146  	})
   147  
   148  	It("podman stats on a container that joined another's net ns", func() {
   149  		session := podmanTest.RunTopContainer("")
   150  		session.WaitWithDefaultTimeout()
   151  		Expect(session).Should(ExitCleanly())
   152  		cid := session.OutputToString()
   153  
   154  		session = podmanTest.Podman([]string{"run", "-d", "--net", fmt.Sprintf("container:%s", cid), ALPINE, "top"})
   155  		session.WaitWithDefaultTimeout()
   156  		Expect(session).Should(ExitCleanly())
   157  
   158  		session = podmanTest.Podman([]string{"stats", "--no-stream", "-a"})
   159  		session.WaitWithDefaultTimeout()
   160  		Expect(session).Should(ExitCleanly())
   161  	})
   162  
   163  	It("podman stats on container with forced slirp4netns", func() {
   164  		// This will force the slirp4netns net mode to be tested as root
   165  		session := podmanTest.Podman([]string{"run", "-d", "--net", "slirp4netns", ALPINE, "top"})
   166  		session.WaitWithDefaultTimeout()
   167  		Expect(session).Should(ExitCleanly())
   168  		session = podmanTest.Podman([]string{"stats", "--no-stream", "-a"})
   169  		session.WaitWithDefaultTimeout()
   170  		Expect(session).Should(ExitCleanly())
   171  	})
   172  
   173  	It("podman reads slirp4netns network stats", func() {
   174  		session := podmanTest.Podman([]string{"run", "-d", "--network", "slirp4netns", ALPINE, "top"})
   175  		session.WaitWithDefaultTimeout()
   176  		Expect(session).Should(ExitCleanly())
   177  
   178  		cid := session.OutputToString()
   179  
   180  		stats := podmanTest.Podman([]string{"stats", "--format", "'{{.NetIO}}'", "--no-stream", cid})
   181  		stats.WaitWithDefaultTimeout()
   182  		Expect(stats).Should(ExitCleanly())
   183  		Expect(stats.OutputToString()).To(Not(ContainSubstring("-- / --")))
   184  	})
   185  
   186  	// Regression test for #8265
   187  	It("podman stats with custom memory limits", func() {
   188  		// Run three containers. One with a memory limit.  Make sure
   189  		// that the limits are different and the limited one has a
   190  		// lower limit.
   191  		ctrNoLimit0 := "no-limit-0"
   192  		ctrNoLimit1 := "no-limit-1"
   193  		ctrWithLimit := "with-limit"
   194  
   195  		session := podmanTest.Podman([]string{"run", "-d", "--name", ctrNoLimit0, ALPINE, "top"})
   196  		session.WaitWithDefaultTimeout()
   197  		Expect(session).Should(ExitCleanly())
   198  
   199  		session = podmanTest.Podman([]string{"run", "-d", "--name", ctrNoLimit1, ALPINE, "top"})
   200  		session.WaitWithDefaultTimeout()
   201  		Expect(session).Should(ExitCleanly())
   202  
   203  		session = podmanTest.Podman([]string{"run", "-d", "--name", ctrWithLimit, "--memory", "50m", ALPINE, "top"})
   204  		session.WaitWithDefaultTimeout()
   205  		Expect(session).Should(ExitCleanly())
   206  
   207  		session = podmanTest.Podman([]string{"stats", "--no-stream", "--format", "{{.MemLimit}}", ctrNoLimit0, ctrNoLimit1, ctrWithLimit})
   208  		session.WaitWithDefaultTimeout()
   209  		Expect(session).Should(ExitCleanly())
   210  
   211  		// We have three containers.  The unlimited ones need to have
   212  		// the same limit, the limited one a lower one.
   213  		limits := session.OutputToStringArray()
   214  		Expect(limits).To(HaveLen(3))
   215  		Expect(limits[0]).To(Equal(limits[1]))
   216  		Expect(limits[0]).ToNot(Equal(limits[2]))
   217  
   218  		defaultLimit, err := strconv.Atoi(limits[0])
   219  		Expect(err).ToNot(HaveOccurred())
   220  		customLimit, err := strconv.Atoi(limits[2])
   221  		Expect(err).ToNot(HaveOccurred())
   222  
   223  		Expect(customLimit).To(BeNumerically("<", defaultLimit))
   224  	})
   225  
   226  	It("podman stats with a container that is not running", func() {
   227  		ctr := "created_container"
   228  		session := podmanTest.Podman([]string{"create", "--name", ctr, ALPINE})
   229  		session.WaitWithDefaultTimeout()
   230  		Expect(session).Should(ExitCleanly())
   231  
   232  		session = podmanTest.Podman([]string{"stats", "--no-stream", ctr})
   233  		session.WaitWithDefaultTimeout()
   234  		Expect(session).Should(ExitCleanly())
   235  	})
   236  
   237  	It("podman stats show cgroup memory limit", func() {
   238  		ctrWithLimit := "with-limit"
   239  
   240  		session := podmanTest.Podman([]string{"run", "-d", "--name", ctrWithLimit, "--memory", "50m", ALPINE, "top"})
   241  		session.WaitWithDefaultTimeout()
   242  		Expect(session).Should(ExitCleanly())
   243  
   244  		session = podmanTest.Podman([]string{"stats", "--no-stream", "--format", "{{.MemLimit}}", ctrWithLimit})
   245  		session.WaitWithDefaultTimeout()
   246  		Expect(session).Should(ExitCleanly())
   247  
   248  		limit, err := strconv.Atoi(session.OutputToString())
   249  		Expect(err).ToNot(HaveOccurred())
   250  		Expect(limit).To(BeNumerically("==", 50*1024*1024))
   251  
   252  		session = podmanTest.Podman([]string{"container", "update", ctrWithLimit, "--memory", "100m"})
   253  		session.WaitWithDefaultTimeout()
   254  		Expect(session).Should(ExitCleanly())
   255  
   256  		session = podmanTest.Podman([]string{"stats", "--no-stream", "--format", "{{.MemLimit}}", ctrWithLimit})
   257  		session.WaitWithDefaultTimeout()
   258  		Expect(session).Should(ExitCleanly())
   259  
   260  		limit, err = strconv.Atoi(session.OutputToString())
   261  		Expect(err).ToNot(HaveOccurred())
   262  		Expect(limit).To(BeNumerically("==", 100*1024*1024))
   263  	})
   264  
   265  	It("podman stats --all", func() {
   266  		runningContainersession := podmanTest.RunTopContainer("")
   267  		runningContainersession.WaitWithDefaultTimeout()
   268  		Expect(runningContainersession).Should(ExitCleanly())
   269  		runningCtrID := runningContainersession.OutputToString()[0:12]
   270  
   271  		createdContainerSession, _, _ := podmanTest.CreatePod(map[string][]string{
   272  			"--infra": {"true"},
   273  		})
   274  
   275  		createdContainerSession.WaitWithDefaultTimeout()
   276  		Expect(createdContainerSession).Should(ExitCleanly())
   277  
   278  		sessionAll := podmanTest.Podman([]string{"stats", "--no-stream", "--format", "{{.ID}}"})
   279  		sessionAll.WaitWithDefaultTimeout()
   280  		Expect(sessionAll).Should(ExitCleanly())
   281  		Expect(sessionAll.OutputToString()).Should(Equal(runningCtrID))
   282  
   283  		sessionAll = podmanTest.Podman([]string{"stats", "--no-stream", "--all=false", "--format", "{{.ID}}"})
   284  		sessionAll.WaitWithDefaultTimeout()
   285  		Expect(sessionAll).Should(ExitCleanly())
   286  		Expect(sessionAll.OutputToString()).Should(Equal(runningCtrID))
   287  
   288  		sessionAll = podmanTest.Podman([]string{"stats", "--all=true", "--no-stream", "--format", "{{.ID}}"})
   289  		sessionAll.WaitWithDefaultTimeout()
   290  		Expect(sessionAll).Should(ExitCleanly())
   291  		Expect(sessionAll.OutputToStringArray()).Should(HaveLen(2))
   292  
   293  		sessionAll = podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "{{.ID}}"})
   294  		sessionAll.WaitWithDefaultTimeout()
   295  		Expect(sessionAll).Should(ExitCleanly())
   296  		Expect(sessionAll.OutputToStringArray()).Should(HaveLen(2))
   297  	})
   298  })