dash 3.2.1 → 4.0.0

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dash/cli/app/boot.rb +2 -2
  3. data/lib/dash/cli/app.rb +1 -1
  4. data/lib/dash/cli/base.rb +1 -1
  5. data/lib/dash/cli/doctor/endpoint_checks.rb +1 -1
  6. data/lib/dash/cli/doctor/host_checks.rb +4 -4
  7. data/lib/dash/cli/main.rb +5 -5
  8. data/lib/dash/cli/proxy/legacy_rename.rb +58 -0
  9. data/lib/dash/cli/proxy/loadbalancer_reboot.rb +1 -1
  10. data/lib/dash/cli/proxy/reboot.rb +8 -8
  11. data/lib/dash/cli/proxy.rb +14 -10
  12. data/lib/dash/commander.rb +1 -1
  13. data/lib/dash/commands/accessory/proxy.rb +1 -1
  14. data/lib/dash/commands/app/execution.rb +1 -1
  15. data/lib/dash/commands/app/proxy.rb +1 -1
  16. data/lib/dash/commands/app.rb +1 -1
  17. data/lib/dash/commands/docker.rb +35 -1
  18. data/lib/dash/commands/loadbalancer.rb +47 -17
  19. data/lib/dash/commands/lock.rb +1 -1
  20. data/lib/dash/commands/proxy/cert_transfer.rb +4 -4
  21. data/lib/dash/commands/proxy.rb +112 -13
  22. data/lib/dash/commands/prune.rb +1 -1
  23. data/lib/dash/configuration/accessory.rb +2 -2
  24. data/lib/dash/configuration/docs/accessory.yml +3 -3
  25. data/lib/dash/configuration/docs/configuration.yml +1 -1
  26. data/lib/dash/configuration/docs/proxy.yml +38 -38
  27. data/lib/dash/configuration/loadbalancer.rb +2 -2
  28. data/lib/dash/configuration/proxy/acme.rb +5 -5
  29. data/lib/dash/configuration/proxy/boot.rb +2 -4
  30. data/lib/dash/configuration/proxy/run.rb +10 -10
  31. data/lib/dash/configuration/proxy.rb +36 -14
  32. data/lib/dash/configuration/role.rb +2 -2
  33. data/lib/dash/configuration/validator/proxy.rb +23 -23
  34. data/lib/dash/configuration.rb +8 -8
  35. data/lib/dash/utils.rb +1 -1
  36. data/lib/dash/version.rb +1 -1
  37. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3a110ddc9f31ad566bce549f84ef6b216a395d9201e02747f1e062d89406f07
4
- data.tar.gz: 40fcfdf62082cf07a8e7e19455fd9398567e6ace96be7426165d27309f0ef29e
3
+ metadata.gz: 749c8e286224f96b085fc8c325affcfde1cafaa18824e1405f880cc1aea966b1
4
+ data.tar.gz: 0dab0ae01b69f742e58551caaeee3352f98548c5a6265e98fcbe2de3025b50d1
5
5
  SHA512:
6
- metadata.gz: c9a19af8c3f5c210d01d8aa9dcdee7e2ad76018050cf7df70ca3bc04a85089702a8ec32b14eab38701e48ffa2306880333e5fd2309e109fb83b720ea27041f33
7
- data.tar.gz: bf7739b92e6685eb9bc62453eed18c7ba127faf29d42c15023b890632b4c2f3b8e1481e9fc3481b189b27a86dd39c04a57d08d5c00b46fe89b2a294ed807144e
6
+ metadata.gz: 7b8a1e07a72a34388817185a8e476b4c400a90061292fe9d143a9a67ab1e5e5d2a87cba154077d151922a306f577dce9d04d60ecef371296ca9b2e3c49a277cb
7
+ data.tar.gz: 5b396df37122ed76ff2e5b7b2b694940a9eb1bcaa5bf31ed0de3f01039bf59836224f225da0a59acc24445f1d6a3dfe19165f2c83fd2e4a4023e68a1ec41c2c6
@@ -58,7 +58,7 @@ class Dash::Cli::App::Boot
58
58
  raise Dash::Cli::BootError, "Failed to get endpoint for #{role} on #{host}, did the container boot?" if endpoint.empty?
59
59
 
60
60
  run_hook "pre-proxy-deploy", hosts: host.to_s, role: role.name
61
- info "Deploying #{role} on #{host} via kamal-proxy (waiting up to #{DASH.config.deploy_timeout}s for it to become healthy)..."
61
+ info "Deploying #{role} on #{host} via dash-proxy (waiting up to #{DASH.config.deploy_timeout}s for it to become healthy)..."
62
62
  execute *app.deploy(target: endpoint)
63
63
  run_hook "post-proxy-deploy", hosts: host.to_s, role: role.name
64
64
  else
@@ -84,7 +84,7 @@ class Dash::Cli::App::Boot
84
84
  end
85
85
 
86
86
  # Every failed boot gets the container log, and the health probe history when the
87
- # container declares a healthcheck — non-primary roles have no kamal-proxy report to fall back on.
87
+ # container declares a healthcheck — non-primary roles have no dash-proxy report to fall back on.
88
88
  def dump_diagnostics
89
89
  error capture_with_info(*app.logs(container_id: app.container_id_for_version(version)))
90
90
 
data/lib/dash/cli/app.rb CHANGED
@@ -283,7 +283,7 @@ class Dash::Cli::App < Dash::Cli::Base
283
283
  end
284
284
  end
285
285
 
286
- desc "rollout <deploy|set|stop>", "Manage a canary rollout of a new version through kamal-proxy"
286
+ desc "rollout <deploy|set|stop>", "Manage a canary rollout of a new version through dash-proxy"
287
287
  option :percent, type: :numeric, desc: "Percentage of traffic to send to the rollout target"
288
288
  option :list, type: :array, desc: "Send requests whose kamal-rollout cookie matches these values to the rollout target"
289
289
  def rollout(action)
data/lib/dash/cli/base.rb CHANGED
@@ -170,7 +170,7 @@ module Dash::Cli
170
170
  raw ? DASH.with_verbosity(:error, &block) : block.call
171
171
  end
172
172
 
173
- # kamal-proxy is one container per host, shared by every destination
173
+ # dash-proxy is one container per host, shared by every destination
174
174
  # deployed there, but the deploy lock is per-destination — so two
175
175
  # destinations deploying at once take different locks and both mutate the
176
176
  # same proxy. Anything touching the proxy takes this lock as well.
@@ -2,7 +2,7 @@ require "resolv"
2
2
  require "socket"
3
3
  require "openssl"
4
4
 
5
- # Local (no SSH) readiness checks for the domains kamal-proxy will serve:
5
+ # Local (no SSH) readiness checks for the domains dash-proxy will serve:
6
6
  # DNS resolution against the configured hosts and TLS certificate expiry.
7
7
  class Dash::Cli::Doctor::EndpointChecks
8
8
  CERTIFICATE_EXPIRY_WARN_DAYS = 14
@@ -127,13 +127,13 @@ class Dash::Cli::Doctor::HostChecks
127
127
  if mounted.include?(expected)
128
128
  result :proxy_socket, :ok, "docker socket #{expected} is mounted"
129
129
  elsif sleep_configured?
130
- result :proxy_socket, :fail, "the running kamal-proxy has no #{expected} mount, so sleeping services never wake - run `dash proxy reboot`"
130
+ result :proxy_socket, :fail, "the running dash-proxy has no #{expected} mount, so sleeping services never wake - run `dash proxy reboot`"
131
131
  else
132
132
  # Nothing sleeps yet, so nothing hangs - drift rather than breakage.
133
- result :proxy_socket, :warn, "the running kamal-proxy has no #{expected} mount - run `dash proxy reboot` to apply the current configuration"
133
+ result :proxy_socket, :warn, "the running dash-proxy has no #{expected} mount - run `dash proxy reboot` to apply the current configuration"
134
134
  end
135
135
  elsif (stray = mounted.grep(DOCKER_SOCKET_PATTERN).first)
136
- result :proxy_socket, :warn, "the running kamal-proxy mounts #{stray} but the config no longer asks for it - " \
136
+ result :proxy_socket, :warn, "the running dash-proxy mounts #{stray} but the config no longer asks for it - " \
137
137
  "the socket is root-equivalent host access; `dash proxy reboot` removes it"
138
138
  else
139
139
  result :proxy_socket, :ok, "no docker socket configured or mounted"
@@ -154,7 +154,7 @@ class Dash::Cli::Doctor::HostChecks
154
154
  https_port = run_config&.https_port || Dash::Configuration::Proxy::Run::DEFAULT_HTTPS_PORT
155
155
 
156
156
  if proxy_running
157
- result :ports, :ok, "ports #{http_port}/#{https_port} held by the running kamal-proxy"
157
+ result :ports, :ok, "ports #{http_port}/#{https_port} held by the running dash-proxy"
158
158
  elsif (busy = busy_ports(http_port, https_port)).any?
159
159
  result :ports, :fail, "port(s) #{busy.join(", ")} already in use by another process"
160
160
  else
data/lib/dash/cli/main.rb CHANGED
@@ -39,7 +39,7 @@ class Dash::Cli::Main < Dash::Cli::Base
39
39
  modify(lock: true) do
40
40
  run_hook "pre-deploy", secrets: true
41
41
 
42
- say "Ensure kamal-proxy is running...", :magenta
42
+ say "Ensure dash-proxy is running...", :magenta
43
43
  invoke "dash:cli:proxy:boot", [], invoke_options
44
44
 
45
45
  invoke "dash:cli:accessory:boot", [ "all" ], invoke_options if boot_accessories
@@ -63,7 +63,7 @@ class Dash::Cli::Main < Dash::Cli::Base
63
63
  end
64
64
  end
65
65
 
66
- desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy and pruning"
66
+ desc "redeploy", "Deploy app to servers without bootstrapping servers, starting dash-proxy and pruning"
67
67
  option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
68
68
  option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
69
69
  def redeploy
@@ -226,7 +226,7 @@ class Dash::Cli::Main < Dash::Cli::Base
226
226
  end
227
227
  end
228
228
 
229
- desc "remove", "Remove kamal-proxy, app, accessories, and registry session from servers"
229
+ desc "remove", "Remove dash-proxy, app, accessories, and registry session from servers"
230
230
  option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
231
231
  def remove
232
232
  confirming "This will remove all containers and images. Are you sure?" do
@@ -249,7 +249,7 @@ class Dash::Cli::Main < Dash::Cli::Base
249
249
  option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
250
250
  option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
251
251
  def upgrade
252
- confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
252
+ confirming "This will replace Traefik with dash-proxy and restart all accessories" do
253
253
  modify(lock: true) do
254
254
  if options[:rolling]
255
255
  DASH.hosts.each do |host|
@@ -293,7 +293,7 @@ class Dash::Cli::Main < Dash::Cli::Base
293
293
  desc "lock", "Manage the deploy lock"
294
294
  subcommand "lock", Dash::Cli::Lock
295
295
 
296
- desc "proxy", "Manage kamal-proxy"
296
+ desc "proxy", "Manage dash-proxy"
297
297
  subcommand "proxy", Dash::Cli::Proxy
298
298
 
299
299
  desc "prune", "Prune old application images and containers"
@@ -0,0 +1,58 @@
1
+ # Stage 3c migration: brings a host that still carries pre-rename container
2
+ # identity onto the renamed one.
3
+ #
4
+ # Three steps, run in this order on each proxy host before the normal boot:
5
+ #
6
+ # 1. Bridge the network. Docker cannot rename one, so `dash` is created
7
+ # alongside `kamal` and everything still attached to the old network joins
8
+ # the new one. App containers would be replaced by the next deploy anyway;
9
+ # accessories are not, which is the whole reason this exists — without it a
10
+ # renamed proxy cannot reach `db` or `redis`.
11
+ #
12
+ # 2. Copy the config volume. It holds the routing table and the ACME account
13
+ # and certificate cache, so losing it means re-issuing every certificate
14
+ # and spending Let's Encrypt rate limits to get back to where we were. This
15
+ # must happen before the new container starts.
16
+ #
17
+ # 3. Replace the legacy container. A rename means the old container has to
18
+ # release ports 80/443 before the new one can claim them, and no
19
+ # port-holder handoff spans two container names — so this stage accepts a
20
+ # brief outage per host. Deliberate; see zoolutions/dash#124.
21
+ #
22
+ # Every step is idempotent and guarded on its destination not already existing,
23
+ # so a second deploy is a no-op. Nothing here removes the legacy network or
24
+ # volume: an operator who wants them gone removes them by hand, and stage 3d
25
+ # deletes this class outright.
26
+ class Dash::Cli::Proxy::LegacyRename
27
+ attr_reader :host, :sshkit
28
+ delegate :execute, to: :sshkit
29
+
30
+ def initialize(host, sshkit)
31
+ @host = host
32
+ @sshkit = sshkit
33
+ end
34
+
35
+ def run
36
+ bridge_network
37
+ adopt_config_volume
38
+ replace_legacy_container
39
+ end
40
+
41
+ private
42
+ def bridge_network
43
+ execute *DASH.docker.connect_legacy_network_containers
44
+ end
45
+
46
+ def adopt_config_volume
47
+ execute *DASH.proxy(host).copy_legacy_config_volume
48
+ end
49
+
50
+ # The drain timeout the proxy is configured with, so a busy host is not cut
51
+ # off mid-request any more abruptly than a normal reboot would.
52
+ def replace_legacy_container
53
+ proxy = DASH.proxy(host)
54
+
55
+ execute *proxy.remove_legacy_container(timeout: DASH.config.drain_timeout)
56
+ execute *proxy.remove_legacy_holder_container
57
+ end
58
+ end
@@ -38,7 +38,7 @@ class Dash::Cli::Proxy::LoadbalancerReboot
38
38
  wait_until_ready
39
39
  verify_service if re_register_service
40
40
 
41
- # kamal-proxy keeps its service state in the config volume, which the
41
+ # dash-proxy keeps its service state in the config volume, which the
42
42
  # replacement container re-mounts - every app's routes survive.
43
43
  services = capture_with_info(*DASH.loadbalancer.list).strip
44
44
  info "Services registered on the load balancer at #{host} after reboot:\n#{services}"
@@ -31,7 +31,7 @@ class Dash::Cli::Proxy::Reboot
31
31
  # Pull before stopping the old container: a registry outage or rate limit
32
32
  # can then no longer strand the host with no proxy at all.
33
33
  def pull_image
34
- info "Pulling kamal-proxy image on #{host}..."
34
+ info "Pulling dash-proxy image on #{host}..."
35
35
  execute *proxy.pull
36
36
  end
37
37
 
@@ -64,7 +64,7 @@ class Dash::Cli::Proxy::Reboot
64
64
 
65
65
  # Phase 1 replacement: stop the old container, start the new one. Brief gap.
66
66
  def stop_and_replace
67
- info "Stopping and removing kamal-proxy on #{host}, if running..."
67
+ info "Stopping and removing dash-proxy on #{host}, if running..."
68
68
  execute *proxy.stop(timeout: DASH.config.drain_timeout + 10), raise_on_non_zero_exit: false
69
69
  execute *proxy.remove_container
70
70
 
@@ -87,7 +87,7 @@ class Dash::Cli::Proxy::Reboot
87
87
  end
88
88
 
89
89
  def handoff_generation
90
- info "Handing off kamal-proxy on #{host} to a new generation (zero downtime)..."
90
+ info "Handing off dash-proxy on #{host} to a new generation (zero downtime)..."
91
91
  execute *proxy.remove_stopped_container(name: proxy.next_container_name), raise_on_non_zero_exit: false
92
92
  execute *proxy.run(digest: drift.expected_digest, name: proxy.next_container_name)
93
93
  wait_until_ready(name: proxy.next_container_name)
@@ -102,7 +102,7 @@ class Dash::Cli::Proxy::Reboot
102
102
  # The old proxy still owns the published ports, so the holder cannot bind
103
103
  # them until it is gone. One final replacement with a brief gap.
104
104
  def migrate_to_holder
105
- info "Migrating kamal-proxy on #{host} to the port-holder architecture (brief gap)..."
105
+ info "Migrating dash-proxy on #{host} to the port-holder architecture (brief gap)..."
106
106
  execute *proxy.stop(timeout: DASH.config.drain_timeout + 10), raise_on_non_zero_exit: false
107
107
  execute *proxy.remove_container
108
108
 
@@ -124,7 +124,7 @@ class Dash::Cli::Proxy::Reboot
124
124
  begin
125
125
  capture_with_info(*proxy.list(**{ name: name }.compact), verbosity: :debug)
126
126
  rescue SSHKit::Command::Failed
127
- raise Dash::Cli::BootError, "kamal-proxy on #{host} did not become ready within #{READY_TIMEOUT} seconds" if Time.now >= deadline
127
+ raise Dash::Cli::BootError, "dash-proxy on #{host} did not become ready within #{READY_TIMEOUT} seconds" if Time.now >= deadline
128
128
  sleep 0.5
129
129
  retry
130
130
  end
@@ -146,7 +146,7 @@ class Dash::Cli::Proxy::Reboot
146
146
  endpoint = capture_with_info(*app.container_id_for_version(version, only_running: true), raise_on_non_zero_exit: false).strip.presence
147
147
  next unless endpoint
148
148
 
149
- info "Re-registering #{role.container_prefix} with kamal-proxy on #{host}..."
149
+ info "Re-registering #{role.container_prefix} with dash-proxy on #{host}..."
150
150
  execute *app.deploy(target: endpoint)
151
151
  registered_services << role.container_prefix
152
152
  end
@@ -158,7 +158,7 @@ class Dash::Cli::Proxy::Reboot
158
158
  target = capture_with_info(*accessory.container_id_for(container_name: accessory_config.service_name, only_running: true), raise_on_non_zero_exit: false).strip.presence
159
159
  next unless target
160
160
 
161
- info "Re-registering #{accessory_config.service_name} with kamal-proxy on #{host}..."
161
+ info "Re-registering #{accessory_config.service_name} with dash-proxy on #{host}..."
162
162
  execute *accessory.deploy(target: target)
163
163
  registered_services << accessory_config.service_name
164
164
  end
@@ -176,7 +176,7 @@ class Dash::Cli::Proxy::Reboot
176
176
  missing = registered_services - listed
177
177
 
178
178
  if missing.any?
179
- raise Dash::Cli::BootError, "kamal-proxy on #{host} is missing services after reboot: #{missing.join(", ")}"
179
+ raise Dash::Cli::BootError, "dash-proxy on #{host} is missing services after reboot: #{missing.join(", ")}"
180
180
  end
181
181
  end
182
182
  end
@@ -21,6 +21,10 @@ class Dash::Cli::Proxy < Dash::Cli::Base
21
21
  on(proxy_hosts) do |host|
22
22
  execute *DASH.registry.login
23
23
 
24
+ # Before anything reads the new container, volume or network: bring a
25
+ # host still on pre-rename identity across. A no-op once it has been.
26
+ Dash::Cli::Proxy::LegacyRename.new(host, self).run
27
+
24
28
  proxy = DASH.proxy(host)
25
29
  drift = Dash::Cli::Proxy::Drift.new(host, self)
26
30
 
@@ -33,7 +37,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
33
37
  version = capture_with_info(*proxy.version).strip.presence
34
38
 
35
39
  if version && Dash::Utils.older_version?(version, Dash::Configuration::Proxy::Run::MINIMUM_VERSION)
36
- raise "kamal-proxy version #{version} is too old, run `dash proxy reboot` in order to update to at least #{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}"
40
+ raise "dash-proxy version #{version} is too old, run `dash proxy reboot` in order to update to at least #{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}"
37
41
  end
38
42
 
39
43
  if (run_config = proxy.proxy_run_config)&.secrets?
@@ -51,12 +55,12 @@ class Dash::Cli::Proxy < Dash::Cli::Base
51
55
  end
52
56
 
53
57
  if stale_hosts.any?
54
- say "kamal-proxy on #{stale_hosts.sort.join(", ")} is running with a configuration that no longer matches the deploy config. " \
58
+ say "dash-proxy on #{stale_hosts.sort.join(", ")} is running with a configuration that no longer matches the deploy config. " \
55
59
  "Automatic reboot is disabled (proxy: reboot_on_deploy: false) - run `dash proxy reboot` to apply the new configuration.", :yellow
56
60
  end
57
61
 
58
62
  drifted_hosts.sort.each do |host|
59
- say "kamal-proxy configuration changed, rebooting on #{host}...", :magenta
63
+ say "dash-proxy configuration changed, rebooting on #{host}...", :magenta
60
64
  run_hook "pre-proxy-reboot", hosts: host
61
65
  on(host) do |h|
62
66
  Dash::Cli::Proxy::Reboot.new(h, self).run
@@ -129,7 +133,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
129
133
  end
130
134
  end
131
135
 
132
- desc "boot_config <set|get|reset>", "Manage kamal-proxy boot configuration"
136
+ desc "boot_config <set|get|reset>", "Manage dash-proxy boot configuration"
133
137
  option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host"
134
138
  option :publish_host_ip, type: :string, repeatable: true, default: nil, desc: "Host IP address to bind HTTP/HTTPS traffic to. Defaults to all interfaces"
135
139
  option :http_port, type: :numeric, default: Dash::Configuration::Proxy::Run::DEFAULT_HTTP_PORT, desc: "HTTP port to publish on the host"
@@ -163,7 +167,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
163
167
  image_version = options[:image_version]
164
168
 
165
169
  run_command_options = { debug: options[:debug] || nil, "metrics-port": options[:metrics_port] }.compact
166
- run_command = "kamal-proxy run #{Dash::Utils.optionize(run_command_options).join(" ")}" if run_command_options.any?
170
+ run_command = "dash-proxy run #{Dash::Utils.optionize(run_command_options).join(" ")}" if run_command_options.any?
167
171
 
168
172
  on(DASH.proxy_hosts) do |host|
169
173
  proxy = DASH.proxy(host)
@@ -229,7 +233,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
229
233
  host_list = Array(hosts).join(",")
230
234
  run_hook "pre-proxy-reboot", hosts: host_list
231
235
  on(hosts) do |host|
232
- info "Rebooting kamal-proxy on #{host}..."
236
+ info "Rebooting dash-proxy on #{host}..."
233
237
  Dash::Cli::Proxy::Reboot.new(host, self).run
234
238
  end
235
239
  run_hook "post-proxy-reboot", hosts: host_list
@@ -249,7 +253,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
249
253
  end
250
254
  end
251
255
 
252
- desc "upgrade", "Upgrade to kamal-proxy on servers (stop container, remove container, start new container, reboot app)", hide: true
256
+ desc "upgrade", "Upgrade to dash-proxy on servers (stop container, remove container, start new container, reboot app)", hide: true
253
257
  option :rolling, type: :boolean, default: false, desc: "Reboot proxy on hosts in sequence, rather than in parallel"
254
258
  option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
255
259
  def upgrade
@@ -269,7 +273,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
269
273
  info "Stopping and removing Traefik on #{host}, if running..."
270
274
  execute *proxy.cleanup_traefik
271
275
 
272
- info "Stopping and removing kamal-proxy on #{host}, if running..."
276
+ info "Stopping and removing dash-proxy on #{host}, if running..."
273
277
  execute *proxy.stop, raise_on_non_zero_exit: false
274
278
  execute *proxy.remove_container
275
279
  execute *proxy.remove_image
@@ -566,7 +570,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
566
570
  on(cert_store_host) do |host|
567
571
  commands = load_balancing ? DASH.loadbalancer : DASH.proxy(host)
568
572
 
569
- # kamal-proxy import runs offline against the data directory - importing
573
+ # dash-proxy import runs offline against the data directory - importing
570
574
  # under a live proxy risks a torn store. --verify only reads the archive.
571
575
  unless verify
572
576
  if capture_with_info(*commands.container_id(only_running: true), raise_on_non_zero_exit: false).strip.present?
@@ -652,7 +656,7 @@ class Dash::Cli::Proxy < Dash::Cli::Base
652
656
  DASH.config.proxy.load_balancing? ? DASH.config.proxy.effective_loadbalancer : DASH.primary_host
653
657
  end
654
658
 
655
- # Mirrors kamal-proxy's own flag groups (import.go), so a contradictory
659
+ # Mirrors dash-proxy's own flag groups (import.go), so a contradictory
656
660
  # invocation fails before anything is uploaded.
657
661
  def validate_import_certs_options!
658
662
  if options[:traefik_acme].present? == options[:archive].present?
@@ -110,7 +110,7 @@ class Dash::Commander
110
110
  @commands[:lock] ||= Dash::Commands::Lock.new(config)
111
111
  end
112
112
 
113
- # Guards the kamal-proxy container, which a host runs once for every
113
+ # Guards the dash-proxy container, which a host runs once for every
114
114
  # destination deployed onto it. Every destination contends for this one.
115
115
  def server_lock
116
116
  @commands[:server_lock] ||= Dash::Commands::Lock.new(config, scope: :server)
@@ -11,6 +11,6 @@ module Dash::Commands::Accessory::Proxy
11
11
 
12
12
  private
13
13
  def proxy_exec(*command)
14
- docker :exec, proxy_container_name, "kamal-proxy", *command
14
+ docker :exec, proxy_container_name, "dash-proxy", *command
15
15
  end
16
16
  end
@@ -13,7 +13,7 @@ module Dash::Commands::App::Execution
13
13
  ("--detach" if detach),
14
14
  ("--rm" unless detach),
15
15
  "--name", container_name_for_exec,
16
- "--network", "kamal",
16
+ "--network", "dash",
17
17
  *role&.env_args(host),
18
18
  *argumentize("--env", env),
19
19
  *role.logging_args,
@@ -39,6 +39,6 @@ module Dash::Commands::App::Proxy
39
39
 
40
40
  private
41
41
  def proxy_exec(*command)
42
- docker :exec, proxy_container_name, "kamal-proxy", *command
42
+ docker :exec, proxy_container_name, "dash-proxy", *command
43
43
  end
44
44
  end
@@ -18,7 +18,7 @@ class Dash::Commands::App < Dash::Commands::Base
18
18
  "--detach",
19
19
  "--restart", role.restart_policy,
20
20
  "--name", container_name,
21
- "--network", "kamal",
21
+ "--network", "dash",
22
22
  *([ "--hostname", hostname ] if hostname),
23
23
  "--env", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
24
24
  "--env", "KAMAL_VERSION=\"#{config.version}\"",
@@ -41,10 +41,44 @@ class Dash::Commands::Docker < Dash::Commands::Base
41
41
  end
42
42
 
43
43
  def create_network
44
- docker :network, :create, :kamal
44
+ docker :network, :create, Dash::Configuration::Proxy::NETWORK
45
+ end
46
+
47
+ # Stage 3c: docker cannot rename a network, so `dash` is created alongside
48
+ # `kamal` and everything still on the old one is joined to the new one.
49
+ #
50
+ # App containers would be replaced by the next deploy anyway; accessories are
51
+ # not, and that is the whole point — without this a renamed proxy cannot
52
+ # reach `db` or `redis`. Connecting a container that is already attached
53
+ # fails, so each connect tolerates its own failure rather than aborting the
54
+ # sweep. The old network is never removed; that is documented manual cleanup
55
+ # and stage 3d's code change.
56
+ def connect_legacy_network_containers
57
+ any \
58
+ combine(
59
+ legacy_network_exists,
60
+ pipe(legacy_network_container_names, connect_each_to_network)
61
+ ),
62
+ [ :true ]
45
63
  end
46
64
 
47
65
  private
66
+ def legacy_network_exists
67
+ docker :network, :inspect, Dash::Configuration::Proxy::LEGACY_NETWORK, ">", "/dev/null", "2>&1"
68
+ end
69
+
70
+ def legacy_network_container_names
71
+ docker :network, :inspect, Dash::Configuration::Proxy::LEGACY_NETWORK,
72
+ "--format", "'{{range .Containers}}{{.Name}}{{\"\\n\"}}{{end}}'"
73
+ end
74
+
75
+ # Already-attached containers make `network connect` fail; tolerate each
76
+ # one's failure rather than letting it abort the sweep.
77
+ def connect_each_to_network
78
+ [ :xargs, "-r", "-I{}", "sh", "-c",
79
+ "'docker network connect #{Dash::Configuration::Proxy::NETWORK} {} 2>/dev/null || true'" ]
80
+ end
81
+
48
82
  def get_docker
49
83
  shell \
50
84
  any \
@@ -14,7 +14,7 @@ class Dash::Commands::Loadbalancer < Dash::Commands::Base
14
14
  docker \
15
15
  :run,
16
16
  "--name", container_name,
17
- "--network", "kamal",
17
+ "--network", "dash",
18
18
  "--detach",
19
19
  "--restart", "unless-stopped",
20
20
  "--label", label,
@@ -38,28 +38,28 @@ class Dash::Commands::Loadbalancer < Dash::Commands::Base
38
38
  end
39
39
 
40
40
  def deploy(targets: [])
41
- docker :exec, container_name, "kamal-proxy", "deploy", loadbalancer_config.config.service,
41
+ docker :exec, container_name, "dash-proxy", "deploy", loadbalancer_config.config.service,
42
42
  *loadbalancer_config.deploy_command_args(targets: targets)
43
43
  end
44
44
 
45
45
  # `retry` takes a host, or --all; the rest take no arguments.
46
46
  def domains(subcommand, *args)
47
- docker :exec, container_name, "kamal-proxy", "domains", subcommand, *args
47
+ docker :exec, container_name, "dash-proxy", "domains", subcommand, *args
48
48
  end
49
49
 
50
50
  def list(json: false)
51
- docker :exec, container_name, "kamal-proxy", :list, *("--json" if json)
51
+ docker :exec, container_name, "dash-proxy", :list, *("--json" if json)
52
52
  end
53
53
 
54
54
  # Cache policy is edge-only under load balancing (see the layering contract),
55
55
  # so the cache admin surface lives here - registered under the bare service
56
56
  # name, unlike the per-role services on the proxy hosts.
57
57
  def cache_stats(count: false, json: false)
58
- docker :exec, container_name, "kamal-proxy", :cache, :stats, *optionize({ count: count || nil, json: json || nil }.compact)
58
+ docker :exec, container_name, "dash-proxy", :cache, :stats, *optionize({ count: count || nil, json: json || nil }.compact)
59
59
  end
60
60
 
61
61
  def cache_purge(service, path_prefix: nil)
62
- docker :exec, container_name, "kamal-proxy", :cache, :purge, service, *optionize({ "path-prefix": path_prefix }.compact)
62
+ docker :exec, container_name, "dash-proxy", :cache, :purge, service, *optionize({ "path-prefix": path_prefix }.compact)
63
63
  end
64
64
 
65
65
  def config_digest
@@ -94,16 +94,24 @@ class Dash::Commands::Loadbalancer < Dash::Commands::Base
94
94
  end
95
95
 
96
96
  # Prune by the label the container was actually created with - on a shared
97
- # proxy host that is the kamal-proxy title, and pruning by the loadbalancer
98
- # title would leave the container behind for `run` to collide with.
97
+ # proxy host that is the dash-proxy title, and pruning by the loadbalancer
98
+ # title would leave the container behind for `run` to collide with. Both the
99
+ # current and the pre-rename title are pruned, so a container created before
100
+ # the rename is not left behind to collide either.
99
101
  def remove_container
100
- docker :container, :prune, "--force", "--filter", "label=#{label}"
102
+ combine \
103
+ prune_containers_titled(image_title),
104
+ prune_containers_titled(legacy_image_title)
101
105
  end
102
106
 
103
107
  # Image label filters match labels baked into the image, and the load balancer
104
- # runs the kamal-proxy image whichever host it sits on.
108
+ # runs the dash-proxy image whichever host it sits on. Both titles are matched
109
+ # so a host still carrying a pre-rename image is cleaned up too; Docker ANDs
110
+ # multiple `--filter label=` values, so that is two commands.
105
111
  def remove_image
106
- docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy"
112
+ combine \
113
+ prune_images_titled(Dash::Configuration::Proxy::IMAGE_TITLE),
114
+ prune_images_titled(Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE)
107
115
  end
108
116
 
109
117
  def ensure_directory
@@ -153,28 +161,50 @@ class Dash::Commands::Loadbalancer < Dash::Commands::Base
153
161
  loadbalancer_config.on_proxy_host?
154
162
  end
155
163
 
164
+ # The full `key=value` the container is created with, so `--label #{label}`
165
+ # stays correct. The prune helpers take a bare title instead.
156
166
  def label
167
+ "org.opencontainers.image.title=#{image_title}"
168
+ end
169
+
170
+ def image_title
157
171
  if on_proxy_host?
158
- "org.opencontainers.image.title=kamal-proxy"
172
+ Dash::Configuration::Proxy::IMAGE_TITLE
159
173
  else
160
- "org.opencontainers.image.title=kamal-loadbalancer"
174
+ Dash::Configuration::Proxy::LOADBALANCER_IMAGE_TITLE
161
175
  end
162
176
  end
163
177
 
164
- # kamal-proxy keeps its state under /home/kamal-proxy/.config/kamal-proxy
178
+ def legacy_image_title
179
+ if on_proxy_host?
180
+ Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE
181
+ else
182
+ Dash::Configuration::Proxy::LEGACY_LOADBALANCER_IMAGE_TITLE
183
+ end
184
+ end
185
+
186
+ def prune_containers_titled(title)
187
+ docker :container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=#{title}"
188
+ end
189
+
190
+ def prune_images_titled(title)
191
+ docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=#{title}"
192
+ end
193
+
194
+ # dash-proxy keeps its state under /home/dash-proxy/.config/dash-proxy
165
195
  # whichever host it runs on - only the volume name differs, so a dedicated
166
196
  # load balancer and a shared proxy host never fight over the same volume.
167
197
  # (The apps-config mount comes with run_args, via the proxy's run surface.)
168
198
  def config_volume
169
199
  if on_proxy_host?
170
- [ "--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy" ]
200
+ [ "--volume", "dash-proxy-config:/home/dash-proxy/.config/dash-proxy" ]
171
201
  else
172
- [ "--volume", "kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy" ]
202
+ [ "--volume", "dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy" ]
173
203
  end
174
204
  end
175
205
 
176
206
  # The certificate store lives in whichever config volume this loadbalancer
177
- # actually mounts — the shared kamal-proxy one on a proxy host.
207
+ # actually mounts — the shared dash-proxy one on a proxy host.
178
208
  def cert_store_volume_args
179
209
  config_volume
180
210
  end
@@ -4,7 +4,7 @@ require "base64"
4
4
 
5
5
  class Dash::Commands::Lock < Dash::Commands::Base
6
6
  # The deploy lock is scoped to service+destination, so two destinations can
7
- # deploy at once. Server-scoped resources — above all the single kamal-proxy
7
+ # deploy at once. Server-scoped resources — above all the single dash-proxy
8
8
  # container a host runs for every destination on it — need a lock that every
9
9
  # destination contends for, hence :server.
10
10
  SCOPES = %i[ destination server ].freeze
@@ -18,7 +18,7 @@ module Dash::Commands::Proxy::CertTransfer
18
18
  # Through the RPC socket of the running container, under the proxy's own
19
19
  # certificate write lock, so a backup taken mid-renewal is never torn.
20
20
  def export_certs
21
- docker :exec, container_name, "kamal-proxy", :export, :certs, certs_archive_container_path
21
+ docker :exec, container_name, "dash-proxy", :export, :certs, certs_archive_container_path
22
22
  end
23
23
 
24
24
  # Reads the data directory offline over the config volume — only safe when
@@ -28,10 +28,10 @@ module Dash::Commands::Proxy::CertTransfer
28
28
  *cert_store_volume_args,
29
29
  *config.proxy_boot.apps_volume.docker_args,
30
30
  *one_off_image,
31
- "kamal-proxy", :export, :certs, certs_archive_container_path
31
+ "dash-proxy", :export, :certs, certs_archive_container_path
32
32
  end
33
33
 
34
- # Offline by design (kamal-proxy import has no RPC path): the one-off
34
+ # Offline by design (dash-proxy import has no RPC path): the one-off
35
35
  # container mounts the config volume — creating it when no proxy has booted
36
36
  # yet, which is the Traefik-migration case — and the staged source streams
37
37
  # through stdin.
@@ -42,7 +42,7 @@ module Dash::Commands::Proxy::CertTransfer
42
42
  # run whatever follows on the target host.
43
43
  import_command = shell [
44
44
  "cat > #{CONTAINER_IMPORT_PATH} &&",
45
- "kamal-proxy import certs",
45
+ "dash-proxy import certs",
46
46
  *optionize({ source_flag => CONTAINER_IMPORT_PATH, resolver: resolver, force: force || nil, verify: verify || nil }.compact, with: "=")
47
47
  ]
48
48