Merge branch 'main' into customizable-audit-broadcast

* main:
  Fix staging label bug
  Fix typo
  Capture container health log when unhealthy
  Bump version for 0.12.0
This commit is contained in:
Kevin McConnell
2023-05-05 11:39:45 +01:00
9 changed files with 26 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
PATH PATH
remote: . remote: .
specs: specs:
mrsk (0.11.0) mrsk (0.12.0)
activesupport (>= 7.0) activesupport (>= 7.0)
bcrypt_pbkdf (~> 1.0) bcrypt_pbkdf (~> 1.0)
dotenv (~> 2.8) dotenv (~> 2.8)

View File

@@ -308,7 +308,7 @@ You can specialize the default Traefik rules by setting labels on the containers
labels: labels:
traefik.http.routers.hey-web.rule: Host(`app.hey.com`) traefik.http.routers.hey-web.rule: Host(`app.hey.com`)
``` ```
Traefik rules are in the "service-role-destination" format. The default role will be `web` if no rule is specified. If the destination is not specified, it is not included. To give an example, the above rule would become "traefik.http.routers.hey-web.rule" if it was for the "staging" destination. Traefik rules are in the "service-role-destination" format. The default role will be `web` if no rule is specified. If the destination is not specified, it is not included. To give an example, the above rule would become "traefik.http.routers.hey-web-staging.rule" if it was for the "staging" destination.
Note: The backticks are needed to ensure the rule is passed in correctly and not treated as command substitution by Bash! Note: The backticks are needed to ensure the rule is passed in correctly and not treated as command substitution by Bash!
@@ -729,7 +729,7 @@ servers:
The healthcheck allows for an optional `max_attempts` setting, which will attempt the healthcheck up to the specified number of times before failing the deploy. This is useful for applications that take a while to start up. The default is 7. The healthcheck allows for an optional `max_attempts` setting, which will attempt the healthcheck up to the specified number of times before failing the deploy. This is useful for applications that take a while to start up. The default is 7.
Note that the HTTP health checks assume that the `curl` command is avilable inside the container. If that's not the case, use the healthcheck's `cmd` option to specify an alternative check that the container supports. Note: The HTTP health checks assume that the `curl` command is available inside the container. If that's not the case, use the healthcheck's `cmd` option to specify an alternative check that the container supports.
## Commands ## Commands

View File

@@ -9,6 +9,7 @@ class Mrsk::Cli::Healthcheck < Mrsk::Cli::Base
Mrsk::Utils::HealthcheckPoller.wait_for_healthy { capture_with_info(*MRSK.healthcheck.status) } Mrsk::Utils::HealthcheckPoller.wait_for_healthy { capture_with_info(*MRSK.healthcheck.status) }
rescue Mrsk::Utils::HealthcheckPoller::HealthcheckError => e rescue Mrsk::Utils::HealthcheckPoller::HealthcheckError => e
error capture_with_info(*MRSK.healthcheck.logs) error capture_with_info(*MRSK.healthcheck.logs)
error capture_with_pretty_json(*MRSK.healthcheck.container_health_log)
raise raise
ensure ensure
execute *MRSK.healthcheck.stop, raise_on_non_zero_exit: false execute *MRSK.healthcheck.stop, raise_on_non_zero_exit: false

View File

@@ -3,6 +3,7 @@ module Mrsk::Commands
delegate :sensitive, :argumentize, to: Mrsk::Utils delegate :sensitive, :argumentize, to: Mrsk::Utils
DOCKER_HEALTH_STATUS_FORMAT = "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'" DOCKER_HEALTH_STATUS_FORMAT = "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'"
DOCKER_HEALTH_LOG_FORMAT = "'{{json .State.Health}}'"
attr_accessor :config attr_accessor :config

View File

@@ -22,6 +22,10 @@ class Mrsk::Commands::Healthcheck < Mrsk::Commands::Base
pipe container_id, xargs(docker(:inspect, "--format", DOCKER_HEALTH_STATUS_FORMAT)) pipe container_id, xargs(docker(:inspect, "--format", DOCKER_HEALTH_STATUS_FORMAT))
end end
def container_health_log
pipe container_id, xargs(docker(:inspect, "--format", DOCKER_HEALTH_LOG_FORMAT))
end
def logs def logs
pipe container_id, xargs(docker(:logs, "--tail", 50, "2>&1")) pipe container_id, xargs(docker(:logs, "--tail", 50, "2>&1"))
end end

View File

@@ -1,12 +1,17 @@
require "sshkit" require "sshkit"
require "sshkit/dsl" require "sshkit/dsl"
require "active_support/core_ext/hash/deep_merge" require "active_support/core_ext/hash/deep_merge"
require "json"
class SSHKit::Backend::Abstract class SSHKit::Backend::Abstract
def capture_with_info(*args, **kwargs) def capture_with_info(*args, **kwargs)
capture(*args, **kwargs, verbosity: Logger::INFO) capture(*args, **kwargs, verbosity: Logger::INFO)
end end
def capture_with_pretty_json(*args, **kwargs)
JSON.pretty_generate(JSON.parse(capture(*args, **kwargs)))
end
def puts_by_host(host, output, type: "App") def puts_by_host(host, output, type: "App")
puts "#{type} Host: #{host}\n#{output}\n\n" puts "#{type} Host: #{host}\n#{output}\n\n"
end end

View File

@@ -1,3 +1,3 @@
module Mrsk module Mrsk
VERSION = "0.11.0" VERSION = "0.12.0"
end end

View File

@@ -53,6 +53,11 @@ class CliHealthcheckTest < CliTestCase
.with(:docker, :container, :ls, "--all", "--filter", "name=^healthcheck-app-999$", "--quiet", "|", :xargs, :docker, :logs, "--tail", 50, "2>&1") .with(:docker, :container, :ls, "--all", "--filter", "name=^healthcheck-app-999$", "--quiet", "|", :xargs, :docker, :logs, "--tail", 50, "2>&1")
.returns("some log output") .returns("some log output")
# Capture container health log when failing
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_pretty_json)
.with(:docker, :container, :ls, "--all", "--filter", "name=^healthcheck-app-999$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{json .State.Health}}'")
.returns('{"Status":"unhealthy","Log":[{"ExitCode": 1,"Output": "/bin/sh: 1: curl: not found\n"}]}"')
exception = assert_raises do exception = assert_raises do
run_command("perform") run_command("perform")
end end

View File

@@ -51,6 +51,12 @@ class CommandsHealthcheckTest < ActiveSupport::TestCase
new_command.status.join(" ") new_command.status.join(" ")
end end
test "container_health_log" do
assert_equal \
"docker container ls --all --filter name=^healthcheck-app-123$ --quiet | xargs docker inspect --format '{{json .State.Health}}'",
new_command.container_health_log.join(" ")
end
test "stop" do test "stop" do
assert_equal \ assert_equal \
"docker container ls --all --filter name=^healthcheck-app-123$ --quiet | xargs docker stop", "docker container ls --all --filter name=^healthcheck-app-123$ --quiet | xargs docker stop",