github.com/containers/podman/v5@v5.1.0-rc1/test/system/220-healthcheck.bats (about)

     1  #!/usr/bin/env bats   -*- bats -*-
     2  #
     3  # tests for podman healthcheck
     4  #
     5  #
     6  
     7  load helpers
     8  
     9  
    10  # Helper function: run 'podman inspect' and check various given fields
    11  function _check_health {
    12      local testname="$1"
    13      local tests="$2"
    14      local since="$3"
    15      local hc_status="$4"
    16  
    17      run_podman inspect --format "{{json .State.Healthcheck}}" healthcheck_c
    18  
    19      parse_table "$tests" | while read field expect;do
    20          actual=$(jq ".$field" <<<"$output")
    21          is "$actual" "$expect" "$testname - .State.Healthcheck.$field"
    22      done
    23  
    24      # Make sure we can read the healthcheck event in podman events (#20342)
    25      run_podman events --filter container=healthcheck_c --filter event=health_status \
    26          --since "$since" --stream=false --format "{{.HealthStatus}}"
    27      # Because the assert below would fail with "lines: bad array subscript" when
    28      # there are no events lets special case this to provide a more meaningful error.
    29      if [[ -z "$output" ]]; then
    30          die "no healthcheck events"
    31      fi
    32      assert "${lines[-1]}" == "$hc_status" "$testname - podman events health status"
    33  }
    34  
    35  @test "podman healthcheck" {
    36      run_podman run -d --name healthcheck_c             \
    37                 --health-cmd /home/podman/healthcheck   \
    38                 --health-interval 1s                    \
    39                 --health-retries 3                      \
    40                 --health-on-failure=kill                \
    41                 $IMAGE /home/podman/pause
    42  
    43      run_podman inspect healthcheck_c --format "{{.Config.HealthcheckOnFailureAction}}"
    44      is "$output" "kill" "on-failure action is set to kill"
    45  
    46      current_time=$(date --iso-8601=seconds)
    47      # We can't check for 'starting' because a 1-second interval is too
    48      # short; it could run healthcheck before we get to our first check.
    49      #
    50      # So, just force a healthcheck run, then confirm that it's running.
    51      run_podman healthcheck run healthcheck_c
    52      is "$output" "" "output from 'podman healthcheck run'"
    53  
    54      _check_health "All healthy" "
    55  Status           | \"healthy\"
    56  FailingStreak    | 0
    57  Log[-1].ExitCode | 0
    58  Log[-1].Output   | \"Life is Good on stdout\\\nLife is Good on stderr\"
    59  " "$current_time" "healthy"
    60  
    61      current_time=$(date --iso-8601=seconds)
    62      # Force a failure
    63      run_podman exec healthcheck_c touch /uh-oh
    64      sleep 2
    65  
    66      _check_health "First failure" "
    67  Status           | \"healthy\"
    68  FailingStreak    | [123]
    69  Log[-1].ExitCode | 1
    70  Log[-1].Output   | \"Uh-oh on stdout!\\\nUh-oh on stderr!\"
    71  " "$current_time" "healthy"
    72  
    73      current_time=$(date --iso-8601=seconds)
    74      # After three successive failures, container should no longer be healthy
    75      sleep 5
    76      _check_health "Three or more failures" "
    77  Status           | \"unhealthy\"
    78  FailingStreak    | [3456]
    79  Log[-1].ExitCode | 1
    80  Log[-1].Output   | \"Uh-oh on stdout!\\\nUh-oh on stderr!\"
    81  " "$current_time" "unhealthy"
    82  
    83      # now the on-failure should kick in and kill the container
    84      run_podman wait healthcheck_c
    85  
    86      # Clean up
    87      run_podman rm -t 0 -f healthcheck_c
    88  }
    89  
    90  @test "podman healthcheck - restart cleans up old state" {
    91      ctr="healthcheck_c"
    92  
    93      run_podman run -d --name $ctr                  \
    94             --health-cmd /home/podman/healthcheck   \
    95             --health-retries=3                      \
    96             --health-interval=disable               \
    97             $IMAGE /home/podman/pause
    98  
    99      run_podman container inspect $ctr --format "{{.State.Healthcheck.FailingStreak}}"
   100      is "$output" "0" "Failing streak of fresh container should be 0"
   101  
   102      # Get the healthcheck to fail
   103      run_podman exec $ctr touch /uh-oh-only-once
   104      run_podman 1 healthcheck run $ctr
   105      is "$output" "unhealthy" "output from 'podman healthcheck run'"
   106      run_podman container inspect $ctr --format "{{.State.Healthcheck.FailingStreak}}"
   107      is "$output" "1" "Failing streak after one failed healthcheck should be 1"
   108  
   109      run_podman container restart $ctr
   110      run_podman container inspect $ctr --format "{{.State.Healthcheck.FailingStreak}}"
   111      is "$output" "0" "Failing streak of restarted container should be 0 again"
   112  
   113      run_podman rm -f -t0 $ctr
   114  }
   115  
   116  @test "podman wait --condition={healthy,unhealthy}" {
   117      ctr="healthcheck_c"
   118  
   119      wait_file="$PODMAN_TMPDIR/$(random_string).wait_for_me"
   120  
   121      for condition in healthy unhealthy;do
   122          rm -f $wait_file
   123          run_podman run -d --name $ctr                  \
   124                 --health-cmd /home/podman/healthcheck   \
   125                 --health-retries=1                      \
   126                 --health-interval=disable               \
   127                 $IMAGE /home/podman/pause
   128          if [[ $condition == "unhealthy" ]];then
   129              # create the uh-oh file to let the health check fail
   130              run_podman exec $ctr touch /uh-oh
   131          fi
   132  
   133          # Wait for the container in the background and create the $wait_file to
   134          # signal the specified wait condition was met.
   135          (timeout --foreground -v --kill=5 5 $PODMAN wait --condition=$condition $ctr && touch $wait_file) &
   136  
   137          # Sleep 1 second to make sure above commands are running
   138          sleep 1
   139          if [[ -f $wait_file ]]; then
   140              die "the wait file should only be created after the container turned healthy"
   141          fi
   142  
   143          if [[ $condition == "healthy" ]];then
   144              run_podman healthcheck run $ctr
   145          else
   146              run_podman 1 healthcheck run $ctr
   147          fi
   148          wait_for_file $wait_file
   149          run_podman rm -f -t0 $ctr
   150      done
   151  }
   152  
   153  @test "podman healthcheck --health-on-failure" {
   154      run_podman 125 create --health-on-failure=kill $IMAGE
   155      is "$output" "Error: cannot set on-failure action to kill without a health check"
   156  
   157      ctr="healthcheck_c"
   158  
   159      for policy in none kill restart stop;do
   160          uhoh=/uh-oh
   161          if [[ $policy != "none" ]];then
   162              # only fail the first run
   163              uhoh=/uh-oh-only-once
   164          fi
   165  
   166          # Run healthcheck image.
   167          run_podman run -d --name $ctr                 \
   168                 --health-cmd /home/podman/healthcheck  \
   169                 --health-retries=1                     \
   170                 --health-on-failure=$policy            \
   171                 --health-interval=disable              \
   172                 $IMAGE /home/podman/pause
   173  
   174          # healthcheck should succeed
   175          run_podman healthcheck run $ctr
   176  
   177          # Now cause the healthcheck to fail
   178          run_podman exec $ctr touch $uhoh
   179  
   180          # healthcheck should now fail, with exit status 1 and 'unhealthy' output
   181          run_podman 1 healthcheck run $ctr
   182          is "$output" "unhealthy" "output from 'podman healthcheck run' (policy: $policy)"
   183  
   184          if [[ $policy == "restart" ]];then
   185             # Make sure the container transitions back to running
   186             run_podman wait --condition=running $ctr
   187             run_podman inspect $ctr --format "{{.RestartCount}}"
   188             assert "${#lines[@]}" != 0 "Container has been restarted at least once"
   189             run_podman container inspect $ctr --format "{{.State.Healthcheck.FailingStreak}}"
   190             is "$output" "0" "Failing streak of restarted container should be 0 again"
   191             run_podman healthcheck run $ctr
   192          elif [[ $policy == "none" ]];then
   193              run_podman inspect $ctr --format "{{.State.Status}} {{.Config.HealthcheckOnFailureAction}}"
   194              # Container is still running and health check still broken
   195              is "$output" "running $policy" "container continued running"
   196              run_podman 1 healthcheck run $ctr
   197              is "$output" "unhealthy" "output from 'podman healthcheck run' (policy: $policy)"
   198          else
   199              run_podman inspect $ctr --format "{{.State.Status}} {{.Config.HealthcheckOnFailureAction}}"
   200              # kill and stop yield the container into a non-running state
   201              is "$output" ".* $policy" "container was stopped/killed (policy: $policy)"
   202              assert "$output" != "running $policy"
   203              # also make sure that it's not stuck in the stopping state
   204              assert "$output" != "stopping $policy"
   205          fi
   206  
   207          run_podman rm -f -t0 $ctr
   208      done
   209  }
   210  
   211  @test "podman healthcheck --health-on-failure with interval" {
   212      ctr="healthcheck_c"
   213  
   214      for policy in stop kill restart ;do
   215          t0=$(date --iso-8601=seconds)
   216          run_podman run -d --name $ctr      \
   217                 --health-cmd /bin/false     \
   218                 --health-retries=1          \
   219                 --health-on-failure=$policy \
   220                 --health-interval=1s        \
   221                 $IMAGE top
   222  
   223          if [[ $policy == "restart" ]];then
   224              # Sleeping for 2 seconds makes the test much faster than using
   225              # podman-wait which would compete with the container getting
   226              # restarted.
   227              sleep 2
   228              # Make sure the container transitions back to running
   229              run_podman wait --condition=running $ctr
   230              run_podman inspect $ctr --format "{{.RestartCount}}"
   231              assert "${#lines[@]}" != 0 "Container has been restarted at least once"
   232          else
   233              # kill and stop yield the container into a non-running state
   234              run_podman wait $ctr
   235              run_podman inspect $ctr --format "{{.State.Status}} {{.Config.HealthcheckOnFailureAction}}"
   236              is "$output" ".* $policy" "container was stopped/killed (policy: $policy)"
   237              assert "$output" != "running $policy"
   238              # also make sure that it's not stuck in the stopping state
   239              assert "$output" != "stopping $policy"
   240          fi
   241  
   242          run_podman rm -f -t0 $ctr
   243      done
   244  }
   245  
   246  # vim: filetype=sh