github.com/portworx/docker@v1.12.1/integration-cli/docker_cli_health_test.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"github.com/docker/docker/pkg/integration/checker"
     6  	"github.com/docker/engine-api/types"
     7  	"github.com/go-check/check"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  )
    12  
    13  func waitForStatus(c *check.C, name string, prev string, expected string) {
    14  	prev = prev + "\n"
    15  	expected = expected + "\n"
    16  	for {
    17  		out, _ := dockerCmd(c, "inspect", "--format={{.State.Status}}", name)
    18  		if out == expected {
    19  			return
    20  		}
    21  		c.Check(out, checker.Equals, prev)
    22  		if out != prev {
    23  			return
    24  		}
    25  		time.Sleep(100 * time.Millisecond)
    26  	}
    27  }
    28  
    29  func waitForHealthStatus(c *check.C, name string, prev string, expected string) {
    30  	prev = prev + "\n"
    31  	expected = expected + "\n"
    32  	for {
    33  		out, _ := dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name)
    34  		if out == expected {
    35  			return
    36  		}
    37  		c.Check(out, checker.Equals, prev)
    38  		if out != prev {
    39  			return
    40  		}
    41  		time.Sleep(100 * time.Millisecond)
    42  	}
    43  }
    44  
    45  func getHealth(c *check.C, name string) *types.Health {
    46  	out, _ := dockerCmd(c, "inspect", "--format={{json .State.Health}}", name)
    47  	var health types.Health
    48  	err := json.Unmarshal([]byte(out), &health)
    49  	c.Check(err, checker.Equals, nil)
    50  	return &health
    51  }
    52  
    53  func (s *DockerSuite) TestHealth(c *check.C) {
    54  	testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows
    55  
    56  	imageName := "testhealth"
    57  	_, err := buildImage(imageName,
    58  		`FROM busybox
    59  		RUN echo OK > /status
    60  		CMD ["/bin/sleep", "120"]
    61  		STOPSIGNAL SIGKILL
    62  		HEALTHCHECK --interval=1s --timeout=30s \
    63  		  CMD cat /status`,
    64  		true)
    65  
    66  	c.Check(err, check.IsNil)
    67  
    68  	// No health status before starting
    69  	name := "test_health"
    70  	dockerCmd(c, "create", "--name", name, imageName)
    71  	out, _ := dockerCmd(c, "ps", "-a", "--format={{.Status}}")
    72  	c.Check(out, checker.Equals, "Created\n")
    73  
    74  	// Inspect the options
    75  	out, _ = dockerCmd(c, "inspect",
    76  		"--format='timeout={{.Config.Healthcheck.Timeout}} "+
    77  			"interval={{.Config.Healthcheck.Interval}} "+
    78  			"retries={{.Config.Healthcheck.Retries}} "+
    79  			"test={{.Config.Healthcheck.Test}}'", name)
    80  	c.Check(out, checker.Equals, "timeout=30s interval=1s retries=0 test=[CMD-SHELL cat /status]\n")
    81  
    82  	// Start
    83  	dockerCmd(c, "start", name)
    84  	waitForHealthStatus(c, name, "starting", "healthy")
    85  
    86  	// Make it fail
    87  	dockerCmd(c, "exec", name, "rm", "/status")
    88  	waitForHealthStatus(c, name, "healthy", "unhealthy")
    89  
    90  	// Inspect the status
    91  	out, _ = dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name)
    92  	c.Check(out, checker.Equals, "unhealthy\n")
    93  
    94  	// Make it healthy again
    95  	dockerCmd(c, "exec", name, "touch", "/status")
    96  	waitForHealthStatus(c, name, "unhealthy", "healthy")
    97  
    98  	// Remove container
    99  	dockerCmd(c, "rm", "-f", name)
   100  
   101  	// Disable the check from the CLI
   102  	out, _ = dockerCmd(c, "create", "--name=noh", "--no-healthcheck", imageName)
   103  	out, _ = dockerCmd(c, "inspect", "--format={{.Config.Healthcheck.Test}}", "noh")
   104  	c.Check(out, checker.Equals, "[NONE]\n")
   105  	dockerCmd(c, "rm", "noh")
   106  
   107  	// Disable the check with a new build
   108  	_, err = buildImage("no_healthcheck",
   109  		`FROM testhealth
   110  		HEALTHCHECK NONE`, true)
   111  	c.Check(err, check.IsNil)
   112  
   113  	out, _ = dockerCmd(c, "inspect", "--format={{.ContainerConfig.Healthcheck.Test}}", "no_healthcheck")
   114  	c.Check(out, checker.Equals, "[NONE]\n")
   115  
   116  	// Enable the checks from the CLI
   117  	_, _ = dockerCmd(c, "run", "-d", "--name=fatal_healthcheck",
   118  		"--health-interval=0.5s",
   119  		"--health-retries=3",
   120  		"--health-cmd=cat /status",
   121  		"no_healthcheck")
   122  	waitForHealthStatus(c, "fatal_healthcheck", "starting", "healthy")
   123  	health := getHealth(c, "fatal_healthcheck")
   124  	c.Check(health.Status, checker.Equals, "healthy")
   125  	c.Check(health.FailingStreak, checker.Equals, 0)
   126  	last := health.Log[len(health.Log)-1]
   127  	c.Check(last.ExitCode, checker.Equals, 0)
   128  	c.Check(last.Output, checker.Equals, "OK\n")
   129  
   130  	// Fail the check
   131  	dockerCmd(c, "exec", "fatal_healthcheck", "rm", "/status")
   132  	waitForHealthStatus(c, "fatal_healthcheck", "healthy", "unhealthy")
   133  
   134  	failsStr, _ := dockerCmd(c, "inspect", "--format={{.State.Health.FailingStreak}}", "fatal_healthcheck")
   135  	fails, err := strconv.Atoi(strings.TrimSpace(failsStr))
   136  	c.Check(err, check.IsNil)
   137  	c.Check(fails >= 3, checker.Equals, true)
   138  	dockerCmd(c, "rm", "-f", "fatal_healthcheck")
   139  
   140  	// Check timeout
   141  	// Note: if the interval is too small, it seems that Docker spends all its time running health
   142  	// checks and never gets around to killing it.
   143  	_, _ = dockerCmd(c, "run", "-d", "--name=test",
   144  		"--health-interval=1s", "--health-cmd=sleep 5m", "--health-timeout=1ms", imageName)
   145  	waitForHealthStatus(c, "test", "starting", "unhealthy")
   146  	health = getHealth(c, "test")
   147  	last = health.Log[len(health.Log)-1]
   148  	c.Check(health.Status, checker.Equals, "unhealthy")
   149  	c.Check(last.ExitCode, checker.Equals, -1)
   150  	c.Check(last.Output, checker.Equals, "Health check exceeded timeout (1ms)")
   151  	dockerCmd(c, "rm", "-f", "test")
   152  }