github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/test/e2e/healthcheck_run_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"time"
     9  
    10  	define "github.com/hanks177/podman/v4/libpod/define"
    11  	. "github.com/hanks177/podman/v4/test/utils"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/gexec"
    15  )
    16  
    17  var _ = Describe("Podman healthcheck run", func() {
    18  	var (
    19  		tempdir    string
    20  		err        error
    21  		podmanTest *PodmanTestIntegration
    22  	)
    23  
    24  	BeforeEach(func() {
    25  		tempdir, err = CreateTempDirInTempDir()
    26  		if err != nil {
    27  			os.Exit(1)
    28  		}
    29  		podmanTest = PodmanTestCreate(tempdir)
    30  		podmanTest.Setup()
    31  	})
    32  
    33  	AfterEach(func() {
    34  		podmanTest.Cleanup()
    35  		f := CurrentGinkgoTestDescription()
    36  		timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())
    37  		_, _ = GinkgoWriter.Write([]byte(timedResult))
    38  
    39  	})
    40  
    41  	It("podman healthcheck run bogus container", func() {
    42  		session := podmanTest.Podman([]string{"healthcheck", "run", "foobar"})
    43  		session.WaitWithDefaultTimeout()
    44  		Expect(session).To(ExitWithError())
    45  	})
    46  
    47  	It("podman disable healthcheck with --no-healthcheck on valid container", func() {
    48  		session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", healthcheck})
    49  		session.WaitWithDefaultTimeout()
    50  		Expect(session).Should(Exit(0))
    51  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
    52  		hc.WaitWithDefaultTimeout()
    53  		Expect(hc).Should(Exit(125))
    54  	})
    55  
    56  	It("podman disable healthcheck with --no-healthcheck must not show starting on status", func() {
    57  		session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", healthcheck})
    58  		session.WaitWithDefaultTimeout()
    59  		Expect(session).Should(Exit(0))
    60  		hc := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Health.Status}}", "hc"})
    61  		hc.WaitWithDefaultTimeout()
    62  		Expect(hc).Should(Exit(0))
    63  		Expect(hc.OutputToString()).To(Not(ContainSubstring("starting")))
    64  	})
    65  
    66  	It("podman run healthcheck and logs should contain healthcheck output", func() {
    67  		session := podmanTest.Podman([]string{"run", "--name", "test-logs", "-dt", "--health-interval", "1s", "--health-cmd", "echo working", "busybox", "sleep", "3600"})
    68  		session.WaitWithDefaultTimeout()
    69  		Expect(session).Should(Exit(0))
    70  
    71  		// Buy a little time to get container running
    72  		for i := 0; i < 5; i++ {
    73  			hc := podmanTest.Podman([]string{"healthcheck", "run", "test-logs"})
    74  			hc.WaitWithDefaultTimeout()
    75  			exitCode := hc.ExitCode()
    76  			if exitCode == 0 || i == 4 {
    77  				break
    78  			}
    79  			time.Sleep(1 * time.Second)
    80  		}
    81  
    82  		hc := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Healthcheck.Log}}", "test-logs"})
    83  		hc.WaitWithDefaultTimeout()
    84  		Expect(hc).Should(Exit(0))
    85  		Expect(hc.OutputToString()).To(ContainSubstring("working"))
    86  	})
    87  
    88  	It("podman healthcheck from image's config (not container config)", func() {
    89  		// Regression test for #12226: a health check may be defined in
    90  		// the container or the container-config of an image.
    91  		session := podmanTest.Podman([]string{"create", "--name", "hc", "quay.io/libpod/healthcheck:config-only", "ls"})
    92  		session.WaitWithDefaultTimeout()
    93  		Expect(session).Should(Exit(0))
    94  		hc := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Healthcheck}}", "hc"})
    95  		hc.WaitWithDefaultTimeout()
    96  		Expect(hc).Should(Exit(0))
    97  		Expect(hc.OutputToString()).To(Equal("{[CMD-SHELL curl -f http://localhost/ || exit 1] 0s 5m0s 3s 0}"))
    98  	})
    99  
   100  	It("podman disable healthcheck with --health-cmd=none on valid container", func() {
   101  		session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "none", "--name", "hc", healthcheck})
   102  		session.WaitWithDefaultTimeout()
   103  		Expect(session).Should(Exit(0))
   104  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   105  		hc.WaitWithDefaultTimeout()
   106  		Expect(hc).Should(Exit(125))
   107  	})
   108  
   109  	It("podman healthcheck on valid container", func() {
   110  		Skip("Extremely consistent flake - re-enable on debugging")
   111  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", healthcheck})
   112  		session.WaitWithDefaultTimeout()
   113  		Expect(session).Should(Exit(0))
   114  
   115  		exitCode := 999
   116  
   117  		// Buy a little time to get container running
   118  		for i := 0; i < 5; i++ {
   119  			hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   120  			hc.WaitWithDefaultTimeout()
   121  			exitCode = hc.ExitCode()
   122  			if exitCode == 0 || i == 4 {
   123  				break
   124  			}
   125  			time.Sleep(1 * time.Second)
   126  		}
   127  		Expect(exitCode).To(Equal(0))
   128  
   129  		ps := podmanTest.Podman([]string{"ps"})
   130  		ps.WaitWithDefaultTimeout()
   131  		Expect(ps).Should(Exit(0))
   132  		Expect(ps.OutputToString()).To(ContainSubstring("(healthy)"))
   133  	})
   134  
   135  	It("podman healthcheck that should fail", func() {
   136  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "quay.io/libpod/badhealthcheck:latest"})
   137  		session.WaitWithDefaultTimeout()
   138  		Expect(session).Should(Exit(0))
   139  
   140  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   141  		hc.WaitWithDefaultTimeout()
   142  		Expect(hc).Should(Exit(1))
   143  	})
   144  
   145  	It("podman healthcheck on stopped container", func() {
   146  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", healthcheck, "ls"})
   147  		session.WaitWithDefaultTimeout()
   148  		Expect(session).Should(Exit(0))
   149  
   150  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   151  		hc.WaitWithDefaultTimeout()
   152  		Expect(hc).Should(Exit(125))
   153  	})
   154  
   155  	It("podman healthcheck on container without healthcheck", func() {
   156  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", ALPINE, "top"})
   157  		session.WaitWithDefaultTimeout()
   158  		Expect(session).Should(Exit(0))
   159  
   160  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   161  		hc.WaitWithDefaultTimeout()
   162  		Expect(hc).Should(Exit(125))
   163  	})
   164  
   165  	It("podman healthcheck should be starting", func() {
   166  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
   167  		session.WaitWithDefaultTimeout()
   168  		Expect(session).Should(Exit(0))
   169  		inspect := podmanTest.InspectContainer("hc")
   170  		Expect(inspect[0].State.Health).To(HaveField("Status", "starting"))
   171  	})
   172  
   173  	It("podman healthcheck failed checks in start-period should not change status", func() {
   174  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-start-period", "2m", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
   175  		session.WaitWithDefaultTimeout()
   176  		Expect(session).Should(Exit(0))
   177  
   178  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   179  		hc.WaitWithDefaultTimeout()
   180  		Expect(hc).Should(Exit(1))
   181  
   182  		hc = podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   183  		hc.WaitWithDefaultTimeout()
   184  		Expect(hc).Should(Exit(1))
   185  
   186  		hc = podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   187  		hc.WaitWithDefaultTimeout()
   188  		Expect(hc).Should(Exit(1))
   189  
   190  		inspect := podmanTest.InspectContainer("hc")
   191  		Expect(inspect[0].State.Health).To(HaveField("Status", "starting"))
   192  		// test old podman compat (see #11645)
   193  		Expect(inspect[0].State.Healthcheck()).To(HaveField("Status", "starting"))
   194  	})
   195  
   196  	It("podman healthcheck failed checks must reach retries before unhealthy ", func() {
   197  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
   198  		session.WaitWithDefaultTimeout()
   199  		Expect(session).Should(Exit(0))
   200  
   201  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   202  		hc.WaitWithDefaultTimeout()
   203  		Expect(hc).Should(Exit(1))
   204  
   205  		inspect := podmanTest.InspectContainer("hc")
   206  		Expect(inspect[0].State.Health).To(HaveField("Status", "starting"))
   207  
   208  		hc = podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   209  		hc.WaitWithDefaultTimeout()
   210  		Expect(hc).Should(Exit(1))
   211  
   212  		inspect = podmanTest.InspectContainer("hc")
   213  		Expect(inspect[0].State.Health).To(HaveField("Status", define.HealthCheckUnhealthy))
   214  		// test old podman compat (see #11645)
   215  		Expect(inspect[0].State.Healthcheck()).To(HaveField("Status", define.HealthCheckUnhealthy))
   216  	})
   217  
   218  	It("podman healthcheck good check results in healthy even in start-period", func() {
   219  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-start-period", "2m", "--health-retries", "2", "--health-cmd", "ls || exit 1", ALPINE, "top"})
   220  		session.WaitWithDefaultTimeout()
   221  		Expect(session).Should(Exit(0))
   222  
   223  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   224  		hc.WaitWithDefaultTimeout()
   225  		Expect(hc).Should(Exit(0))
   226  
   227  		inspect := podmanTest.InspectContainer("hc")
   228  		Expect(inspect[0].State.Health).To(HaveField("Status", define.HealthCheckHealthy))
   229  	})
   230  
   231  	It("podman healthcheck unhealthy but valid arguments check", func() {
   232  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "[\"ls\", \"/foo\"]", ALPINE, "top"})
   233  		session.WaitWithDefaultTimeout()
   234  		Expect(session).Should(Exit(0))
   235  
   236  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   237  		hc.WaitWithDefaultTimeout()
   238  		Expect(hc).Should(Exit(1))
   239  	})
   240  
   241  	It("podman healthcheck single healthy result changes failed to healthy", func() {
   242  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-retries", "2", "--health-cmd", "ls /foo || exit 1", ALPINE, "top"})
   243  		session.WaitWithDefaultTimeout()
   244  		Expect(session).Should(Exit(0))
   245  
   246  		hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   247  		hc.WaitWithDefaultTimeout()
   248  		Expect(hc).Should(Exit(1))
   249  
   250  		inspect := podmanTest.InspectContainer("hc")
   251  		Expect(inspect[0].State.Health).To(HaveField("Status", "starting"))
   252  
   253  		hc = podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   254  		hc.WaitWithDefaultTimeout()
   255  		Expect(hc).Should(Exit(1))
   256  
   257  		inspect = podmanTest.InspectContainer("hc")
   258  		Expect(inspect[0].State.Health).To(HaveField("Status", define.HealthCheckUnhealthy))
   259  
   260  		foo := podmanTest.Podman([]string{"exec", "hc", "touch", "/foo"})
   261  		foo.WaitWithDefaultTimeout()
   262  		Expect(foo).Should(Exit(0))
   263  
   264  		hc = podmanTest.Podman([]string{"healthcheck", "run", "hc"})
   265  		hc.WaitWithDefaultTimeout()
   266  		Expect(hc).Should(Exit(0))
   267  
   268  		inspect = podmanTest.InspectContainer("hc")
   269  		Expect(inspect[0].State.Health).To(HaveField("Status", define.HealthCheckHealthy))
   270  
   271  		// Test podman ps --filter heath is working (#11687)
   272  		ps := podmanTest.Podman([]string{"ps", "--filter", "health=healthy"})
   273  		ps.WaitWithDefaultTimeout()
   274  		Expect(ps).Should(Exit(0))
   275  		Expect(ps.OutputToStringArray()).To(HaveLen(2))
   276  		Expect(ps.OutputToString()).To(ContainSubstring("hc"))
   277  	})
   278  
   279  	It("stopping and then starting a container with healthcheck cmd", func() {
   280  		session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", "--health-cmd", "[\"ls\", \"/foo\"]", ALPINE, "top"})
   281  		session.WaitWithDefaultTimeout()
   282  		Expect(session).Should(Exit(0))
   283  
   284  		stop := podmanTest.Podman([]string{"stop", "-t0", "hc"})
   285  		stop.WaitWithDefaultTimeout()
   286  		Expect(stop).Should(Exit(0))
   287  
   288  		startAgain := podmanTest.Podman([]string{"start", "hc"})
   289  		startAgain.WaitWithDefaultTimeout()
   290  		Expect(startAgain).Should(Exit(0))
   291  		Expect(startAgain.OutputToString()).To(Equal("hc"))
   292  		Expect(startAgain.ErrorToString()).To(Equal(""))
   293  	})
   294  
   295  	It("Verify default time is used and no utf-8 escapes", func() {
   296  		cwd, err := os.Getwd()
   297  		Expect(err).To(BeNil())
   298  
   299  		podmanTest.AddImageToRWStore(ALPINE)
   300  		// Write target and fake files
   301  		targetPath, err := CreateTempDirInTempDir()
   302  		Expect(err).To(BeNil())
   303  		containerfile := fmt.Sprintf(`FROM %s
   304  HEALTHCHECK CMD ls -l / 2>&1`, ALPINE)
   305  		containerfilePath := filepath.Join(targetPath, "Containerfile")
   306  		err = ioutil.WriteFile(containerfilePath, []byte(containerfile), 0644)
   307  		Expect(err).To(BeNil())
   308  		defer func() {
   309  			Expect(os.Chdir(cwd)).To(BeNil())
   310  			Expect(os.RemoveAll(targetPath)).To(BeNil())
   311  		}()
   312  
   313  		// make cwd as context root path
   314  		Expect(os.Chdir(targetPath)).To(BeNil())
   315  
   316  		session := podmanTest.Podman([]string{"build", "--format", "docker", "-t", "test", "."})
   317  		session.WaitWithDefaultTimeout()
   318  		Expect(session).Should(Exit(0))
   319  
   320  		run := podmanTest.Podman([]string{"run", "-dt", "--name", "hctest", "test", "ls"})
   321  		run.WaitWithDefaultTimeout()
   322  		Expect(run).Should(Exit(0))
   323  
   324  		inspect := podmanTest.InspectContainer("hctest")
   325  		// Check to make sure a default time value was added
   326  		Expect(inspect[0].Config.Healthcheck.Timeout).To(BeNumerically("==", 30000000000))
   327  		// Check to make sure a default time interval value was added
   328  		Expect(inspect[0].Config.Healthcheck.Interval).To(BeNumerically("==", 30000000000))
   329  		// Check to make sure characters were not coerced to utf8
   330  		Expect(inspect[0].Config.Healthcheck).To(HaveField("Test", []string{"CMD-SHELL", "ls -l / 2>&1"}))
   331  	})
   332  })