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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 749c8e286224f96b085fc8c325affcfde1cafaa18824e1405f880cc1aea966b1
4
- data.tar.gz: 0dab0ae01b69f742e58551caaeee3352f98548c5a6265e98fcbe2de3025b50d1
3
+ metadata.gz: d2fca4cca966b5e857e1d537799367c1493701a1e18e48a691c53dddac6b2c36
4
+ data.tar.gz: 2627d3e285ddbee1da9b4bc0705c38fb3825345f554b3b7e8f85598810c0b354
5
5
  SHA512:
6
- metadata.gz: 7b8a1e07a72a34388817185a8e476b4c400a90061292fe9d143a9a67ab1e5e5d2a87cba154077d151922a306f577dce9d04d60ecef371296ca9b2e3c49a277cb
7
- data.tar.gz: 5b396df37122ed76ff2e5b7b2b694940a9eb1bcaa5bf31ed0de3f01039bf59836224f225da0a59acc24445f1d6a3dfe19165f2c83fd2e4a4023e68a1ec41c2c6
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
@@ -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.
@@ -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
- if on_proxy_host?
200
- [ "--volume", "dash-proxy-config:/home/dash-proxy/.config/dash-proxy" ]
201
- else
202
- [ "--volume", "dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy" ]
203
- end
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
@@ -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
- # The guard is negated and leads the chain, with `|| true` last, because
55
- # shell `&&` and `||` share precedence and associate left: written as
56
- # `exists || legacy_exists && create && copy` it would parse as
57
- # `((exists || legacy_exists) && create) && copy` and re-copy the legacy
58
- # volume over live state on every deploy. Leading with `! exists` makes the
59
- # whole chain a single left-associative AND, which short-circuits correctly.
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
- any \
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
- def version
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, container_name, "--format '{{.Config.Image}}'"),
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
@@ -1,3 +1,3 @@
1
1
  module Dash
2
- VERSION = "4.0.0"
2
+ VERSION = "4.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dash
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson