dash 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/dash/cli/doctor/host_checks.rb +25 -4
- data/lib/dash/cli/proxy.rb +4 -0
- data/lib/dash/commands/base.rb +28 -0
- data/lib/dash/commands/loadbalancer.rb +19 -5
- data/lib/dash/commands/proxy.rb +16 -33
- data/lib/dash/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d2fca4cca966b5e857e1d537799367c1493701a1e18e48a691c53dddac6b2c36
|
|
4
|
+
data.tar.gz: 2627d3e285ddbee1da9b4bc0705c38fb3825345f554b3b7e8f85598810c0b354
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d40d1805b3f3b1ed9f0a79bf53a6d96709ea7c3693cc0d8319791e92b10c345aaa2743ef8fdbc568cf9b79de5b37659fb2fbbb75b7d4fac0f111322bc2f807c2
|
|
7
|
+
data.tar.gz: 2972113fc39cd3dcbdd6476d91634e29f757989ca4c84e9dbd1dac6443f6169b967a3f3c9b9c5d7ed9913d212e18d8239c1cd142981a7a14f90dea56769fca1b
|
|
@@ -61,12 +61,17 @@ class Dash::Cli::Doctor::HostChecks
|
|
|
61
61
|
|
|
62
62
|
def proxy_checks
|
|
63
63
|
version, version_error = capture_proxy_version
|
|
64
|
+
# A host that has not been through the stage-3c rename is still running
|
|
65
|
+
# kamal-proxy. Without asking about it too, the version check reports "not
|
|
66
|
+
# running" and the ports check blames a foreign process for the ports that
|
|
67
|
+
# container legitimately holds — failing the very deploy that migrates it.
|
|
68
|
+
legacy_version = version.present? ? nil : capture_legacy_proxy_version
|
|
64
69
|
|
|
65
70
|
{
|
|
66
71
|
proxy_image: proxy_image_check,
|
|
67
|
-
proxy_version: proxy_version_check(version, version_error),
|
|
72
|
+
proxy_version: proxy_version_check(version, version_error, legacy_version),
|
|
68
73
|
proxy_socket: proxy_socket_check(proxy_running: version.present?),
|
|
69
|
-
ports: ports_check(proxy_running: version.present?)
|
|
74
|
+
ports: ports_check(proxy_running: version.present?, legacy_proxy_running: legacy_version.present?)
|
|
70
75
|
}
|
|
71
76
|
end
|
|
72
77
|
|
|
@@ -76,6 +81,14 @@ class Dash::Cli::Doctor::HostChecks
|
|
|
76
81
|
[ nil, e ]
|
|
77
82
|
end
|
|
78
83
|
|
|
84
|
+
# Best-effort: a host with no legacy container simply reports nothing, and
|
|
85
|
+
# any error here must not turn into a failing check of its own.
|
|
86
|
+
def capture_legacy_proxy_version
|
|
87
|
+
capture_with_info(*DASH.proxy(host).version(name: Dash::Configuration::Proxy::LEGACY_CONTAINER_NAME)).strip.presence
|
|
88
|
+
rescue StandardError
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
|
|
79
92
|
def proxy_image_check
|
|
80
93
|
image = expected_proxy_image
|
|
81
94
|
|
|
@@ -88,11 +101,15 @@ class Dash::Cli::Doctor::HostChecks
|
|
|
88
101
|
result :proxy_image, :fail, "#{e.class}: #{e.message}"
|
|
89
102
|
end
|
|
90
103
|
|
|
91
|
-
def proxy_version_check(version, error)
|
|
104
|
+
def proxy_version_check(version, error, legacy_version = nil)
|
|
92
105
|
minimum = Dash::Configuration::Proxy::Run::MINIMUM_VERSION
|
|
93
106
|
|
|
94
107
|
if error
|
|
95
108
|
result :proxy_version, :warn, "could not determine the running version (#{error.message})"
|
|
109
|
+
elsif version.nil? && legacy_version.present?
|
|
110
|
+
result :proxy_version, :ok,
|
|
111
|
+
"#{Dash::Configuration::Proxy::LEGACY_CONTAINER_NAME} #{legacy_version} is running; it is renamed to " \
|
|
112
|
+
"#{Dash::Configuration::Proxy::CONTAINER_NAME} on the next deploy, which briefly interrupts this host"
|
|
96
113
|
elsif version.nil?
|
|
97
114
|
result :proxy_version, :ok, "not running (will be started on deploy)"
|
|
98
115
|
elsif Dash::Utils.older_version?(version, minimum)
|
|
@@ -146,7 +163,7 @@ class Dash::Cli::Doctor::HostChecks
|
|
|
146
163
|
DASH.config.roles.any? { |role| role.running_proxy? && role.proxy.proxy_config["sleep"].present? }
|
|
147
164
|
end
|
|
148
165
|
|
|
149
|
-
def ports_check(proxy_running:)
|
|
166
|
+
def ports_check(proxy_running:, legacy_proxy_running: false)
|
|
150
167
|
run_config = DASH.config.proxy_run(host)
|
|
151
168
|
return result(:ports, :ok, "proxy ports are not published, nothing to check") if run_config && !run_config.publish?
|
|
152
169
|
|
|
@@ -155,6 +172,10 @@ class Dash::Cli::Doctor::HostChecks
|
|
|
155
172
|
|
|
156
173
|
if proxy_running
|
|
157
174
|
result :ports, :ok, "ports #{http_port}/#{https_port} held by the running dash-proxy"
|
|
175
|
+
elsif legacy_proxy_running
|
|
176
|
+
result :ports, :ok,
|
|
177
|
+
"ports #{http_port}/#{https_port} held by the running #{Dash::Configuration::Proxy::LEGACY_CONTAINER_NAME}, " \
|
|
178
|
+
"replaced on the next deploy"
|
|
158
179
|
elsif (busy = busy_ports(http_port, https_port)).any?
|
|
159
180
|
result :ports, :fail, "port(s) #{busy.join(", ")} already in use by another process"
|
|
160
181
|
else
|
data/lib/dash/cli/proxy.rb
CHANGED
|
@@ -76,6 +76,10 @@ class Dash::Cli::Proxy < Dash::Cli::Base
|
|
|
76
76
|
info "Starting loadbalancer on #{host}..."
|
|
77
77
|
execute *DASH.registry.login
|
|
78
78
|
|
|
79
|
+
# Bring a pre-rename volume across before the container can be created
|
|
80
|
+
# against an empty one. A no-op once it has been.
|
|
81
|
+
execute *DASH.loadbalancer.copy_legacy_config_volume
|
|
82
|
+
|
|
79
83
|
# The load balancer terminates TLS and owns the cache, so its host
|
|
80
84
|
# needs the proxy secrets (acme credentials, cache store) just like
|
|
81
85
|
# the proxy hosts do.
|
data/lib/dash/commands/base.rb
CHANGED
|
@@ -126,6 +126,34 @@ module Dash::Commands
|
|
|
126
126
|
[ :sh, "-c", "'#{command.flatten.join(" ").gsub("'", "'\\\\''")}'" ]
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
+
# Adopts a pre-rename docker volume: creates `volume` from `legacy` if, and
|
|
130
|
+
# only if, `volume` is absent and `legacy` is present. A host with neither
|
|
131
|
+
# exits 0. The first word must be a program, never `!` — see
|
|
132
|
+
# Dash::Commands::Proxy#copy_legacy_config_volume.
|
|
133
|
+
def copy_legacy_volume(legacy:, volume:, image:)
|
|
134
|
+
any \
|
|
135
|
+
volume_exists(volume),
|
|
136
|
+
negate(volume_exists(legacy)),
|
|
137
|
+
[ "(", *combine(docker(:volume, :create, volume), copy_between_volumes(legacy, volume, image: image)), ")" ]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def negate(command)
|
|
141
|
+
[ "!", *command ]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def volume_exists(name)
|
|
145
|
+
docker :volume, :inspect, name, ">", "/dev/null", "2>&1"
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def copy_between_volumes(from, to, image:)
|
|
149
|
+
docker \
|
|
150
|
+
:run, "--rm", "--user", "root", "--entrypoint", "sh",
|
|
151
|
+
"--volume", "#{from}:/from",
|
|
152
|
+
"--volume", "#{to}:/to",
|
|
153
|
+
image,
|
|
154
|
+
"-c", "'cp -a /from/. /to/'"
|
|
155
|
+
end
|
|
156
|
+
|
|
129
157
|
def docker(*args)
|
|
130
158
|
args.compact.unshift :docker
|
|
131
159
|
end
|
|
@@ -37,6 +37,16 @@ class Dash::Commands::Loadbalancer < Dash::Commands::Base
|
|
|
37
37
|
combine start, run, by: "||"
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# A dedicated load balancer host went through the 4.0 rename with nothing
|
|
41
|
+
# adopting its `kamal-loadbalancer-config` volume: the per-host proxies got
|
|
42
|
+
# Dash::Cli::Proxy::LegacyRename, the load balancer got a fresh empty volume
|
|
43
|
+
# and lost its routing table, dynamic domains and ACME cache. On a shared
|
|
44
|
+
# proxy host the volume is the proxy's own and LegacyRename already copied
|
|
45
|
+
# it, so this is a no-op there.
|
|
46
|
+
def copy_legacy_config_volume
|
|
47
|
+
copy_legacy_volume(legacy: legacy_config_volume_name, volume: config_volume_name, image: loadbalancer_config.run.image)
|
|
48
|
+
end
|
|
49
|
+
|
|
40
50
|
def deploy(targets: [])
|
|
41
51
|
docker :exec, container_name, "dash-proxy", "deploy", loadbalancer_config.config.service,
|
|
42
52
|
*loadbalancer_config.deploy_command_args(targets: targets)
|
|
@@ -196,11 +206,15 @@ class Dash::Commands::Loadbalancer < Dash::Commands::Base
|
|
|
196
206
|
# load balancer and a shared proxy host never fight over the same volume.
|
|
197
207
|
# (The apps-config mount comes with run_args, via the proxy's run surface.)
|
|
198
208
|
def config_volume
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
209
|
+
[ "--volume", "#{config_volume_name}:/home/dash-proxy/.config/dash-proxy" ]
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def config_volume_name
|
|
213
|
+
on_proxy_host? ? Dash::Configuration::Proxy::CONFIG_VOLUME : Dash::Configuration::Proxy::LOADBALANCER_CONFIG_VOLUME
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def legacy_config_volume_name
|
|
217
|
+
on_proxy_host? ? Dash::Configuration::Proxy::LEGACY_CONFIG_VOLUME : Dash::Configuration::Proxy::LEGACY_LOADBALANCER_CONFIG_VOLUME
|
|
204
218
|
end
|
|
205
219
|
|
|
206
220
|
# The certificate store lives in whichever config volume this loadbalancer
|
data/lib/dash/commands/proxy.rb
CHANGED
|
@@ -51,21 +51,18 @@ class Dash::Commands::Proxy < Dash::Commands::Base
|
|
|
51
51
|
# boot sequence, and its ubuntu base has sh and cp. `--user root` because the
|
|
52
52
|
# image's own user cannot write the destination volume; `cp -a` preserves the
|
|
53
53
|
# uid, which the rename leaves at 1001.
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
# `
|
|
58
|
-
#
|
|
59
|
-
#
|
|
54
|
+
#
|
|
55
|
+
# Shape: `exists || ! legacy_exists || ( create && copy )`. The chain has to
|
|
56
|
+
# start with a real program: SSHKit prefixes the first word with
|
|
57
|
+
# `/usr/bin/env`, and `env !` is "No such file or directory" (exit 127), not
|
|
58
|
+
# shell negation. 4.0.0 led with `! docker volume inspect …`, so the whole
|
|
59
|
+
# chain failed silently into `|| true`, the proxy booted onto a volume docker
|
|
60
|
+
# created empty, and every host lost its routing table and ACME cache on the
|
|
61
|
+
# first deploy. The subshell groups create-and-copy because `&&` and `||`
|
|
62
|
+
# share precedence and associate left — without it a host that already has
|
|
63
|
+
# the new volume would still run the copy over live state.
|
|
60
64
|
def copy_legacy_config_volume(volume: Dash::Configuration::Proxy::CONFIG_VOLUME, legacy: Dash::Configuration::Proxy::LEGACY_CONFIG_VOLUME)
|
|
61
|
-
|
|
62
|
-
combine(
|
|
63
|
-
negate(volume_exists(volume)),
|
|
64
|
-
volume_exists(legacy),
|
|
65
|
-
docker(:volume, :create, volume),
|
|
66
|
-
copy_between_volumes(legacy, volume)
|
|
67
|
-
),
|
|
68
|
-
[ :true ]
|
|
65
|
+
copy_legacy_volume(legacy: legacy, volume: volume, image: proxy_image)
|
|
69
66
|
end
|
|
70
67
|
|
|
71
68
|
# Stops and removes a pre-rename proxy container so the renamed one can claim
|
|
@@ -106,9 +103,12 @@ class Dash::Commands::Proxy < Dash::Commands::Base
|
|
|
106
103
|
docker :ps, "--filter", "'name=^#{container_name}$'"
|
|
107
104
|
end
|
|
108
105
|
|
|
109
|
-
|
|
106
|
+
# `name:` so the doctor can also ask about the pre-rename container: during
|
|
107
|
+
# the stage-3c transition a host still runs kamal-proxy, and a check that only
|
|
108
|
+
# ever looks at dash-proxy concludes no proxy is running.
|
|
109
|
+
def version(name: container_name)
|
|
110
110
|
pipe \
|
|
111
|
-
docker(:inspect,
|
|
111
|
+
docker(:inspect, name, "--format '{{.Config.Image}}'"),
|
|
112
112
|
[ :awk, "-F:", "'{print \$NF}'" ]
|
|
113
113
|
end
|
|
114
114
|
|
|
@@ -323,27 +323,10 @@ class Dash::Commands::Proxy < Dash::Commands::Base
|
|
|
323
323
|
[ "--label", "#{CONFIG_DIGEST_LABEL}=#{digest}" ] if digest
|
|
324
324
|
end
|
|
325
325
|
|
|
326
|
-
def negate(command)
|
|
327
|
-
[ "!", *command ]
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
def volume_exists(name)
|
|
331
|
-
docker :volume, :inspect, name, ">", "/dev/null", "2>&1"
|
|
332
|
-
end
|
|
333
|
-
|
|
334
326
|
def container_exists(name)
|
|
335
327
|
docker :container, :inspect, name, ">", "/dev/null", "2>&1"
|
|
336
328
|
end
|
|
337
329
|
|
|
338
|
-
def copy_between_volumes(from, to)
|
|
339
|
-
docker \
|
|
340
|
-
:run, "--rm", "--user", "root", "--entrypoint", "sh",
|
|
341
|
-
"--volume", "#{from}:/from",
|
|
342
|
-
"--volume", "#{to}:/to",
|
|
343
|
-
proxy_image,
|
|
344
|
-
"-c", "'cp -a /from/. /to/'"
|
|
345
|
-
end
|
|
346
|
-
|
|
347
330
|
# The image the volume copy borrows. The proxy this gem is pinned to is
|
|
348
331
|
# already pulled by the time the copy runs, and `rake release` gates on
|
|
349
332
|
# MINIMUM_VERSION being published, so this is always resolvable — unlike
|
data/lib/dash/version.rb
CHANGED