Class: Dash::Commands::Base
- Inherits:
-
Object
- Object
- Dash::Commands::Base
- Defined in:
- lib/dash/commands/base.rb
Direct Known Subclasses
Accessory, App, Auditor, Builder, Dash::Commands::Builder::Base, Docker, Hook, Loadbalancer, Lock, Proxy, Prune, Registry, Server
Constant Summary collapse
- NO_HEALTHCHECK =
Prefixed onto the docker state when the container declares no healthcheck at all, so "nothing is probing this container" stays distinguishable from "the probe passed" — both used to reach the poller as
running. The state is kept after the prefix so a healthcheck-less container that died still reports why. "no-healthcheck"- DOCKER_HEALTH_STATUS_FORMAT =
"'{{if .State.Health}}{{.State.Health.Status}}{{else}}#{NO_HEALTHCHECK}:{{.State.Status}}{{end}}'"- READY_STATUSES =
The statuses a boot accepts as ready. Dash::Cli::Healthcheck::Poller decides what a status means; Dash::Commands::App#wait_for_ready only decides when to stop looking, and it stops on exactly these. The two must agree: a status the host loop returned early for that the poller would not accept fails a boot the old client-side poll would have waited out.
[ "healthy", "#{NO_HEALTHCHECK}:running" ].freeze
- EXEC_PROBE_FAILED =
What a
healthcheck: exec:probe reports when it exits non-zero. Produced by the host-side wait, read back by the poller, so it is a wire format, not a message. "exec probe exited non-zero"- READINESS_PROGRESS_PREFIX =
The line #wait_for_ready prints to stderr on every attempt, read back by Dash::Cli::Healthcheck::ProgressReporter. stderr, because a capture returns stdout alone - which keeps the captured value the final status and nothing else.
"dash-readiness"
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
Instance Method Summary collapse
-
#confirmed_empty?(list_command) ⇒ Boolean
True only when
list_command's own output is confirmed empty - never inferred from a failure. - #container_id_for(container_name:, only_running: false) ⇒ Object
- #ensure_docker_installed ⇒ Object
-
#ensure_run_directory ⇒ Object
Creates the run directory, renaming a pre-3b
.kamalinto place first. -
#initialize(config) ⇒ Base
constructor
A new instance of Base.
- #make_directory(path) ⇒ Object
- #make_directory_for(remote_file) ⇒ Object
- #read_file(file, default: nil) ⇒ Object
- #remove_directory(path) ⇒ Object
- #remove_file(path) ⇒ Object
- #run_over_ssh(*command, host:) ⇒ Object
Constructor Details
#initialize(config) ⇒ Base
Returns a new instance of Base.
31 32 33 |
# File 'lib/dash/commands/base.rb', line 31 def initialize(config) @config = config end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
29 30 31 |
# File 'lib/dash/commands/base.rb', line 29 def config @config end |
Instance Method Details
#confirmed_empty?(list_command) ⇒ Boolean
True only when list_command's own output is confirmed empty - never inferred from
a failure. docker container inspect name > /dev/null 2>&1 (negated) cannot tell
"no such container" from "the daemon could not be asked" - both exit non-zero - so a
transient failure there reads as confirmed absence. A list exits 0 whichever way
the match went and non-zero only on a genuine failure, so result=$(list) && [ -z "$result" ] fails closed: result=$(list) carries list's own exit status (POSIX;
verified against sh and bash), so a failed list stops the chain before the test runs.
list_command must be a listing (docker container/volume ls), never an inspect.
51 52 53 |
# File 'lib/dash/commands/base.rb', line 51 def confirmed_empty?(list_command) [ "result=$(#{list_command.join(" ")})", "&&", "[", "-z", "\"$result\"", "]" ] end |
#container_id_for(container_name:, only_running: false) ⇒ Object
39 40 41 |
# File 'lib/dash/commands/base.rb', line 39 def container_id_for(container_name:, only_running: false) docker :container, :ls, *("--all" unless only_running), "--filter", "'name=^#{container_name}$'", "--quiet" end |
#ensure_docker_installed ⇒ Object
101 102 103 104 105 |
# File 'lib/dash/commands/base.rb', line 101 def ensure_docker_installed combine \ ensure_local_docker_installed, ensure_local_buildx_installed end |
#ensure_run_directory ⇒ Object
Creates the run directory, renaming a pre-3b .kamal into place first.
Lives on Base because two unlocked paths reach the run directory before
Dash::Cli::Base#ensure_run_directory does — the auditor records "Pulled
image" during build:pull, and every mkdir -p .dash/... underneath it
creates the parent. If any of them made the directory with a bare mkdir,
.dash would exist by the time the guard ran and the legacy tree would be
stranded. Everything that can be first must run the same command.
The migration is safe to repeat on every command:
- Idempotent - once
.dashexists the second guard is false forever. - Atomic - the two are siblings in the SSH user's home, so this is a rename within one filesystem, never a copy.
- Invisible to running containers - a bind mount resolves to an inode, so the live proxy keeps serving from the renamed directory and only picks up the new path when it is next recreated.
test leads deliberately: SSHKit's command map passes if/test/time/
exec through untouched and prefixes everything else with /usr/bin/env.
The trailing || true keeps the exit status zero when there is nothing to
migrate, since callers execute this with raise_on_non_zero_exit on.
85 86 87 |
# File 'lib/dash/commands/base.rb', line 85 def ensure_run_directory combine migrate_legacy_run_directory, make_directory(config.run_directory) end |
#make_directory(path) ⇒ Object
59 60 61 |
# File 'lib/dash/commands/base.rb', line 59 def make_directory(path) [ :mkdir, "-p", path ] end |
#make_directory_for(remote_file) ⇒ Object
55 56 57 |
# File 'lib/dash/commands/base.rb', line 55 def make_directory_for(remote_file) make_directory Pathname.new(remote_file).dirname.to_s end |
#read_file(file, default: nil) ⇒ Object
97 98 99 |
# File 'lib/dash/commands/base.rb', line 97 def read_file(file, default: nil) combine [ :cat, file, "2>", "/dev/null" ], [ :echo, "\"#{default}\"" ], by: "||" end |
#remove_directory(path) ⇒ Object
89 90 91 |
# File 'lib/dash/commands/base.rb', line 89 def remove_directory(path) [ :rm, "-r", path ] end |
#remove_file(path) ⇒ Object
93 94 95 |
# File 'lib/dash/commands/base.rb', line 93 def remove_file(path) [ :rm, path ] end |
#run_over_ssh(*command, host:) ⇒ Object
35 36 37 |
# File 'lib/dash/commands/base.rb', line 35 def run_over_ssh(*command, host:) "ssh#{ssh_config_args}#{ssh_proxy_args}#{ssh_keys_args} -t #{config.ssh.user}@#{host} -p #{config.ssh.port} '#{command.join(" ").gsub("'", "'\\\\''")}'" end |