diff --git a/bin/sync-proxy-flags b/bin/sync-proxy-flags index 402caeb1..5c8c0f0f 100755 --- a/bin/sync-proxy-flags +++ b/bin/sync-proxy-flags @@ -7,7 +7,7 @@ # forgetting is loud rather than silent. # # bin/sync-proxy-flags # pull the image at MINIMUM_VERSION -# bin/sync-proxy-flags --binary ./kamal-proxy # use a locally built binary +# bin/sync-proxy-flags --binary ./dash-proxy # use a locally built binary # # The flag list comes from Cobra's own `--help` output, not from a regex over the # Go source. That is deliberate: the source has flags registered via Int64Var, @@ -43,7 +43,7 @@ def flags_for(invocation, subcommand) help.scan(/^\s+(?:-\w, )?--([a-z0-9-]+)/).flatten.uniq.sort - BUILTIN_FLAGS end -# The DNS providers kamal-proxy will accept for --acme-dns-provider, read off the +# The DNS providers dash-proxy will accept for --acme-dns-provider, read off the # parenthesised list in the flag's own usage text. The gem validates # proxy/run/acme/dns_provider against this, and rejecting a provider the proxy # supports blocks a deploy - so the list has to move with the image, not with @@ -69,7 +69,7 @@ invocation = image = "ghcr.io/zoolutions/dash-proxy:#{version}" warn "Pulling #{image}..." run!("docker", "pull", "--quiet", image) - [ "docker", "run", "--rm", image, "kamal-proxy" ] + [ "docker", "run", "--rm", image, "dash-proxy" ] end manifest = { diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index f87d68a0..95ba7e55 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - dash (3.2.0) + dash (3.2.1) activesupport (>= 7.0, < 10) base64 (~> 0.2) bcrypt_pbkdf (~> 1.0) @@ -445,7 +445,7 @@ CHECKSUMS connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a crass (1.0.7) sha256=94868719948664c89ddcaf0a37c65048413dfcb1c869470a5f7a7ceb5390b295 daisyui (1.2.1) sha256=597b52d19fbfd4e06d08a72ac45c62379caedd6b0d68dcbfe7ed5623009c14b3 - dash (3.2.0) + dash (3.2.1) date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0 debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6 diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 diff --git a/docs/app/views/docs/pages/config/proxy.rb b/docs/app/views/docs/pages/config/proxy.rb index f1c413e9..d2432bb5 100644 --- a/docs/app/views/docs/pages/config/proxy.rb +++ b/docs/app/views/docs/pages/config/proxy.rb @@ -5,5 +5,5 @@ class Views::Docs::Pages::Config::Proxy < Views::Docs::Pages::ConfigPage config_doc "proxy" - def lead = "kamal-proxy deploy options — hosts, SSL, load balancing, caching, traffic shaping, and more." + def lead = "dash-proxy deploy options — hosts, SSL, load balancing, caching, traffic shaping, and more." end diff --git a/docs/app/views/docs/pages/from_kamal.rb b/docs/app/views/docs/pages/from_kamal.rb index ee03fb1a..455f19eb 100644 --- a/docs/app/views/docs/pages/from_kamal.rb +++ b/docs/app/views/docs/pages/from_kamal.rb @@ -46,7 +46,7 @@ def what_stays [ [ :code, "config/deploy.yml" ], [ :md, "Keys unchanged — dash's config is a superset of kamal 2.x; every dash-only key is optional. ERB that calls into the gem needs `Kamal::` renamed to `Dash::` (see below)." ] ], [ [ :code, ".kamal/secrets" ], [ :md, "Still read — the default is now `.dash/secrets`, but dash falls back to `.kamal/` when that is the only directory present. Run `dash migrate` to move it." ] ], [ [ :md, "`.kamal/` on the servers" ], [ :md, "Renamed to `.dash/` in 3.4 — dash moves it for you, in place, the first time it takes a lock on the host. Locks, audit log, proxy boot files and app env all come along; nothing is rebooted." ] ], - [ [ :md, "`kamal-proxy` container" ], [ :md, "Same container name; dash manages the one kamal booted." ] ], + [ [ :md, "`kamal-proxy` container" ], [ :md, "Renamed to `dash-proxy` in 4.0, along with the `kamal` network and the `kamal-proxy-config` volume. dash migrates each host on the next deploy: it copies the config volume so certificates are not re-issued, joins everything on the `kamal` network to `dash`, then replaces the container. **Replacing it costs a short outage on that host** — the old container has to release ports 80/443 before the new one can bind them." ] ], [ [ :md, "`KAMAL_*` env vars & secrets" ], [ :md, "Still set — dash writes `DASH_*` and `KAMAL_*` side by side, so existing hooks and apps keep working. The `KAMAL_*` names go away in dash 5.0." ] ], [ [ :md, "Hooks (`.kamal/hooks/`)" ], [ :md, "Still read — same hook names, same environment, with `.dash/hooks/` as the new default location." ] ] ] @@ -68,7 +68,8 @@ def the_proxy [dash-proxy](https://github.com/zoolutions/dash-proxy) (`ghcr.io/zoolutions/dash-proxy`) — a superset of kamal-proxy that adds load balancing, SAN batching, wildcard certs, caching, and traffic - shaping. The container keeps the `kamal-proxy` name. + shaping. From 4.0 the container is named `dash-proxy`; dash renames an + existing `kamal-proxy` container for you on the next deploy. dash reads the running proxy's version from its image tag and compares it with the minimum version this gem requires. On your first diff --git a/docs/app/views/docs/pages/overview.rb b/docs/app/views/docs/pages/overview.rb index 4aca9026..fd34425a 100644 --- a/docs/app/views/docs/pages/overview.rb +++ b/docs/app/views/docs/pages/overview.rb @@ -31,11 +31,13 @@ def what_is_dash merge — proxy load balancing, readiness gates, response caching, traffic shaping, SAN certificate batching, wildcard certificates — and moves at its own pace. Existing kamal deployments **upgrade in place**: the - `kamal-proxy` container is untouched, the server's `.kamal/` directory - renames itself to `.dash/` on the next deploy, `KAMAL_*` env vars are - still set alongside their `DASH_*` twins, and a `.kamal/` directory in - your repo is still read. See [From kamal](/docs/from-kamal) for the - migration story. + server's `.kamal/` directory renames itself to `.dash/` on the next + deploy, `KAMAL_*` env vars are still set alongside their `DASH_*` + twins, and a `.kamal/` directory in your repo is still read. In 4.0 the + proxy container, network and volumes are renamed too — dash migrates + each host itself, carrying the certificate store across, at the cost of + a short outage per host while the container is replaced. See + [From kamal](/docs/from-kamal) for the migration story. MD end end diff --git a/lib/dash/cli/app.rb b/lib/dash/cli/app.rb index c3af1cfd..c3c61844 100644 --- a/lib/dash/cli/app.rb +++ b/lib/dash/cli/app.rb @@ -283,7 +283,7 @@ def maintenance end end - desc "rollout ", "Manage a canary rollout of a new version through kamal-proxy" + desc "rollout ", "Manage a canary rollout of a new version through dash-proxy" option :percent, type: :numeric, desc: "Percentage of traffic to send to the rollout target" option :list, type: :array, desc: "Send requests whose kamal-rollout cookie matches these values to the rollout target" def rollout(action) diff --git a/lib/dash/cli/app/boot.rb b/lib/dash/cli/app/boot.rb index 6e11ed85..d16b105d 100644 --- a/lib/dash/cli/app/boot.rb +++ b/lib/dash/cli/app/boot.rb @@ -58,7 +58,7 @@ def start_new_version raise Dash::Cli::BootError, "Failed to get endpoint for #{role} on #{host}, did the container boot?" if endpoint.empty? run_hook "pre-proxy-deploy", hosts: host.to_s, role: role.name - info "Deploying #{role} on #{host} via kamal-proxy (waiting up to #{DASH.config.deploy_timeout}s for it to become healthy)..." + info "Deploying #{role} on #{host} via dash-proxy (waiting up to #{DASH.config.deploy_timeout}s for it to become healthy)..." execute *app.deploy(target: endpoint) run_hook "post-proxy-deploy", hosts: host.to_s, role: role.name else @@ -84,7 +84,7 @@ def exec_probe_status end # Every failed boot gets the container log, and the health probe history when the - # container declares a healthcheck — non-primary roles have no kamal-proxy report to fall back on. + # container declares a healthcheck — non-primary roles have no dash-proxy report to fall back on. def dump_diagnostics error capture_with_info(*app.logs(container_id: app.container_id_for_version(version))) diff --git a/lib/dash/cli/base.rb b/lib/dash/cli/base.rb index d1f3a4f9..1e10ea21 100644 --- a/lib/dash/cli/base.rb +++ b/lib/dash/cli/base.rb @@ -170,7 +170,7 @@ def with_raw_output(raw, &block) raw ? DASH.with_verbosity(:error, &block) : block.call end - # kamal-proxy is one container per host, shared by every destination + # dash-proxy is one container per host, shared by every destination # deployed there, but the deploy lock is per-destination — so two # destinations deploying at once take different locks and both mutate the # same proxy. Anything touching the proxy takes this lock as well. diff --git a/lib/dash/cli/doctor/endpoint_checks.rb b/lib/dash/cli/doctor/endpoint_checks.rb index 151f1e4e..157714d3 100644 --- a/lib/dash/cli/doctor/endpoint_checks.rb +++ b/lib/dash/cli/doctor/endpoint_checks.rb @@ -2,7 +2,7 @@ require "socket" require "openssl" -# Local (no SSH) readiness checks for the domains kamal-proxy will serve: +# Local (no SSH) readiness checks for the domains dash-proxy will serve: # DNS resolution against the configured hosts and TLS certificate expiry. class Dash::Cli::Doctor::EndpointChecks CERTIFICATE_EXPIRY_WARN_DAYS = 14 diff --git a/lib/dash/cli/doctor/host_checks.rb b/lib/dash/cli/doctor/host_checks.rb index f8bee739..5af1d6b3 100644 --- a/lib/dash/cli/doctor/host_checks.rb +++ b/lib/dash/cli/doctor/host_checks.rb @@ -127,13 +127,13 @@ def proxy_socket_check(proxy_running:) if mounted.include?(expected) result :proxy_socket, :ok, "docker socket #{expected} is mounted" elsif sleep_configured? - result :proxy_socket, :fail, "the running kamal-proxy has no #{expected} mount, so sleeping services never wake - run `dash proxy reboot`" + result :proxy_socket, :fail, "the running dash-proxy has no #{expected} mount, so sleeping services never wake - run `dash proxy reboot`" else # Nothing sleeps yet, so nothing hangs - drift rather than breakage. - result :proxy_socket, :warn, "the running kamal-proxy has no #{expected} mount - run `dash proxy reboot` to apply the current configuration" + result :proxy_socket, :warn, "the running dash-proxy has no #{expected} mount - run `dash proxy reboot` to apply the current configuration" end elsif (stray = mounted.grep(DOCKER_SOCKET_PATTERN).first) - result :proxy_socket, :warn, "the running kamal-proxy mounts #{stray} but the config no longer asks for it - " \ + result :proxy_socket, :warn, "the running dash-proxy mounts #{stray} but the config no longer asks for it - " \ "the socket is root-equivalent host access; `dash proxy reboot` removes it" else result :proxy_socket, :ok, "no docker socket configured or mounted" @@ -154,7 +154,7 @@ def ports_check(proxy_running:) https_port = run_config&.https_port || Dash::Configuration::Proxy::Run::DEFAULT_HTTPS_PORT if proxy_running - result :ports, :ok, "ports #{http_port}/#{https_port} held by the running kamal-proxy" + result :ports, :ok, "ports #{http_port}/#{https_port} held by the running dash-proxy" elsif (busy = busy_ports(http_port, https_port)).any? result :ports, :fail, "port(s) #{busy.join(", ")} already in use by another process" else diff --git a/lib/dash/cli/main.rb b/lib/dash/cli/main.rb index e43197f8..236e5327 100644 --- a/lib/dash/cli/main.rb +++ b/lib/dash/cli/main.rb @@ -39,7 +39,7 @@ def deploy(boot_accessories: false) modify(lock: true) do run_hook "pre-deploy", secrets: true - say "Ensure kamal-proxy is running...", :magenta + say "Ensure dash-proxy is running...", :magenta invoke "dash:cli:proxy:boot", [], invoke_options invoke "dash:cli:accessory:boot", [ "all" ], invoke_options if boot_accessories @@ -63,7 +63,7 @@ def deploy(boot_accessories: false) end end - desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy and pruning" + desc "redeploy", "Deploy app to servers without bootstrapping servers, starting dash-proxy and pruning" option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push" option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache" def redeploy @@ -226,7 +226,7 @@ def init end end - desc "remove", "Remove kamal-proxy, app, accessories, and registry session from servers" + desc "remove", "Remove dash-proxy, app, accessories, and registry session from servers" option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question" def remove confirming "This will remove all containers and images. Are you sure?" do @@ -249,7 +249,7 @@ def migrate option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question" option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time" def upgrade - confirming "This will replace Traefik with kamal-proxy and restart all accessories" do + confirming "This will replace Traefik with dash-proxy and restart all accessories" do modify(lock: true) do if options[:rolling] DASH.hosts.each do |host| @@ -293,7 +293,7 @@ def version desc "lock", "Manage the deploy lock" subcommand "lock", Dash::Cli::Lock - desc "proxy", "Manage kamal-proxy" + desc "proxy", "Manage dash-proxy" subcommand "proxy", Dash::Cli::Proxy desc "prune", "Prune old application images and containers" diff --git a/lib/dash/cli/proxy.rb b/lib/dash/cli/proxy.rb index 1dc9efad..b55d0969 100644 --- a/lib/dash/cli/proxy.rb +++ b/lib/dash/cli/proxy.rb @@ -21,6 +21,10 @@ def boot on(proxy_hosts) do |host| execute *DASH.registry.login + # Before anything reads the new container, volume or network: bring a + # host still on pre-rename identity across. A no-op once it has been. + Dash::Cli::Proxy::LegacyRename.new(host, self).run + proxy = DASH.proxy(host) drift = Dash::Cli::Proxy::Drift.new(host, self) @@ -33,7 +37,7 @@ def boot version = capture_with_info(*proxy.version).strip.presence if version && Dash::Utils.older_version?(version, Dash::Configuration::Proxy::Run::MINIMUM_VERSION) - 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}" + 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}" end if (run_config = proxy.proxy_run_config)&.secrets? @@ -51,12 +55,12 @@ def boot end if stale_hosts.any? - say "kamal-proxy on #{stale_hosts.sort.join(", ")} is running with a configuration that no longer matches the deploy config. " \ + say "dash-proxy on #{stale_hosts.sort.join(", ")} is running with a configuration that no longer matches the deploy config. " \ "Automatic reboot is disabled (proxy: reboot_on_deploy: false) - run `dash proxy reboot` to apply the new configuration.", :yellow end drifted_hosts.sort.each do |host| - say "kamal-proxy configuration changed, rebooting on #{host}...", :magenta + say "dash-proxy configuration changed, rebooting on #{host}...", :magenta run_hook "pre-proxy-reboot", hosts: host on(host) do |h| Dash::Cli::Proxy::Reboot.new(h, self).run @@ -129,7 +133,7 @@ def boot end end - desc "boot_config ", "Manage kamal-proxy boot configuration" + desc "boot_config ", "Manage dash-proxy boot configuration" option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host" option :publish_host_ip, type: :string, repeatable: true, default: nil, desc: "Host IP address to bind HTTP/HTTPS traffic to. Defaults to all interfaces" 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 @@ def boot_config(subcommand) image_version = options[:image_version] run_command_options = { debug: options[:debug] || nil, "metrics-port": options[:metrics_port] }.compact - run_command = "kamal-proxy run #{Dash::Utils.optionize(run_command_options).join(" ")}" if run_command_options.any? + run_command = "dash-proxy run #{Dash::Utils.optionize(run_command_options).join(" ")}" if run_command_options.any? on(DASH.proxy_hosts) do |host| proxy = DASH.proxy(host) @@ -229,7 +233,7 @@ def reboot host_list = Array(hosts).join(",") run_hook "pre-proxy-reboot", hosts: host_list on(hosts) do |host| - info "Rebooting kamal-proxy on #{host}..." + info "Rebooting dash-proxy on #{host}..." Dash::Cli::Proxy::Reboot.new(host, self).run end run_hook "post-proxy-reboot", hosts: host_list @@ -249,7 +253,7 @@ def reboot end end - desc "upgrade", "Upgrade to kamal-proxy on servers (stop container, remove container, start new container, reboot app)", hide: true + desc "upgrade", "Upgrade to dash-proxy on servers (stop container, remove container, start new container, reboot app)", hide: true option :rolling, type: :boolean, default: false, desc: "Reboot proxy on hosts in sequence, rather than in parallel" option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question" def upgrade @@ -269,7 +273,7 @@ def upgrade info "Stopping and removing Traefik on #{host}, if running..." execute *proxy.cleanup_traefik - info "Stopping and removing kamal-proxy on #{host}, if running..." + info "Stopping and removing dash-proxy on #{host}, if running..." execute *proxy.stop, raise_on_non_zero_exit: false execute *proxy.remove_container execute *proxy.remove_image @@ -566,7 +570,7 @@ def import_certs on(cert_store_host) do |host| commands = load_balancing ? DASH.loadbalancer : DASH.proxy(host) - # kamal-proxy import runs offline against the data directory - importing + # dash-proxy import runs offline against the data directory - importing # under a live proxy risks a torn store. --verify only reads the archive. unless verify if capture_with_info(*commands.container_id(only_running: true), raise_on_non_zero_exit: false).strip.present? @@ -652,7 +656,7 @@ def cert_store_host DASH.config.proxy.load_balancing? ? DASH.config.proxy.effective_loadbalancer : DASH.primary_host end - # Mirrors kamal-proxy's own flag groups (import.go), so a contradictory + # Mirrors dash-proxy's own flag groups (import.go), so a contradictory # invocation fails before anything is uploaded. def validate_import_certs_options! if options[:traefik_acme].present? == options[:archive].present? diff --git a/lib/dash/cli/proxy/legacy_rename.rb b/lib/dash/cli/proxy/legacy_rename.rb new file mode 100644 index 00000000..235d1e63 --- /dev/null +++ b/lib/dash/cli/proxy/legacy_rename.rb @@ -0,0 +1,58 @@ +# Stage 3c migration: brings a host that still carries pre-rename container +# identity onto the renamed one. +# +# Three steps, run in this order on each proxy host before the normal boot: +# +# 1. Bridge the network. Docker cannot rename one, so `dash` is created +# alongside `kamal` and everything still attached to the old network joins +# the new one. App containers would be replaced by the next deploy anyway; +# accessories are not, which is the whole reason this exists — without it a +# renamed proxy cannot reach `db` or `redis`. +# +# 2. Copy the config volume. It holds the routing table and the ACME account +# and certificate cache, so losing it means re-issuing every certificate +# and spending Let's Encrypt rate limits to get back to where we were. This +# must happen before the new container starts. +# +# 3. Replace the legacy container. A rename means the old container has to +# release ports 80/443 before the new one can claim them, and no +# port-holder handoff spans two container names — so this stage accepts a +# brief outage per host. Deliberate; see zoolutions/dash#124. +# +# Every step is idempotent and guarded on its destination not already existing, +# so a second deploy is a no-op. Nothing here removes the legacy network or +# volume: an operator who wants them gone removes them by hand, and stage 3d +# deletes this class outright. +class Dash::Cli::Proxy::LegacyRename + attr_reader :host, :sshkit + delegate :execute, to: :sshkit + + def initialize(host, sshkit) + @host = host + @sshkit = sshkit + end + + def run + bridge_network + adopt_config_volume + replace_legacy_container + end + + private + def bridge_network + execute *DASH.docker.connect_legacy_network_containers + end + + def adopt_config_volume + execute *DASH.proxy(host).copy_legacy_config_volume + end + + # The drain timeout the proxy is configured with, so a busy host is not cut + # off mid-request any more abruptly than a normal reboot would. + def replace_legacy_container + proxy = DASH.proxy(host) + + execute *proxy.remove_legacy_container(timeout: DASH.config.drain_timeout) + execute *proxy.remove_legacy_holder_container + end +end diff --git a/lib/dash/cli/proxy/loadbalancer_reboot.rb b/lib/dash/cli/proxy/loadbalancer_reboot.rb index ce226e61..ae2b942b 100644 --- a/lib/dash/cli/proxy/loadbalancer_reboot.rb +++ b/lib/dash/cli/proxy/loadbalancer_reboot.rb @@ -38,7 +38,7 @@ def run wait_until_ready verify_service if re_register_service - # kamal-proxy keeps its service state in the config volume, which the + # dash-proxy keeps its service state in the config volume, which the # replacement container re-mounts - every app's routes survive. services = capture_with_info(*DASH.loadbalancer.list).strip info "Services registered on the load balancer at #{host} after reboot:\n#{services}" diff --git a/lib/dash/cli/proxy/reboot.rb b/lib/dash/cli/proxy/reboot.rb index d8cef105..583d125d 100644 --- a/lib/dash/cli/proxy/reboot.rb +++ b/lib/dash/cli/proxy/reboot.rb @@ -31,7 +31,7 @@ def drift # Pull before stopping the old container: a registry outage or rate limit # can then no longer strand the host with no proxy at all. def pull_image - info "Pulling kamal-proxy image on #{host}..." + info "Pulling dash-proxy image on #{host}..." execute *proxy.pull end @@ -64,7 +64,7 @@ def sync_proxy_secrets # Phase 1 replacement: stop the old container, start the new one. Brief gap. def stop_and_replace - info "Stopping and removing kamal-proxy on #{host}, if running..." + info "Stopping and removing dash-proxy on #{host}, if running..." execute *proxy.stop(timeout: DASH.config.drain_timeout + 10), raise_on_non_zero_exit: false execute *proxy.remove_container @@ -87,7 +87,7 @@ def replace_generation end def handoff_generation - info "Handing off kamal-proxy on #{host} to a new generation (zero downtime)..." + info "Handing off dash-proxy on #{host} to a new generation (zero downtime)..." execute *proxy.remove_stopped_container(name: proxy.next_container_name), raise_on_non_zero_exit: false execute *proxy.run(digest: drift.expected_digest, name: proxy.next_container_name) wait_until_ready(name: proxy.next_container_name) @@ -102,7 +102,7 @@ def handoff_generation # The old proxy still owns the published ports, so the holder cannot bind # them until it is gone. One final replacement with a brief gap. def migrate_to_holder - info "Migrating kamal-proxy on #{host} to the port-holder architecture (brief gap)..." + info "Migrating dash-proxy on #{host} to the port-holder architecture (brief gap)..." execute *proxy.stop(timeout: DASH.config.drain_timeout + 10), raise_on_non_zero_exit: false execute *proxy.remove_container @@ -124,7 +124,7 @@ def wait_until_ready(name: nil) begin capture_with_info(*proxy.list(**{ name: name }.compact), verbosity: :debug) rescue SSHKit::Command::Failed - raise Dash::Cli::BootError, "kamal-proxy on #{host} did not become ready within #{READY_TIMEOUT} seconds" if Time.now >= deadline + raise Dash::Cli::BootError, "dash-proxy on #{host} did not become ready within #{READY_TIMEOUT} seconds" if Time.now >= deadline sleep 0.5 retry end @@ -146,7 +146,7 @@ def re_register_services endpoint = capture_with_info(*app.container_id_for_version(version, only_running: true), raise_on_non_zero_exit: false).strip.presence next unless endpoint - info "Re-registering #{role.container_prefix} with kamal-proxy on #{host}..." + info "Re-registering #{role.container_prefix} with dash-proxy on #{host}..." execute *app.deploy(target: endpoint) registered_services << role.container_prefix end @@ -158,7 +158,7 @@ def re_register_services 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 next unless target - info "Re-registering #{accessory_config.service_name} with kamal-proxy on #{host}..." + info "Re-registering #{accessory_config.service_name} with dash-proxy on #{host}..." execute *accessory.deploy(target: target) registered_services << accessory_config.service_name end @@ -176,7 +176,7 @@ def verify_services(registered_services) missing = registered_services - listed if missing.any? - raise Dash::Cli::BootError, "kamal-proxy on #{host} is missing services after reboot: #{missing.join(", ")}" + raise Dash::Cli::BootError, "dash-proxy on #{host} is missing services after reboot: #{missing.join(", ")}" end end end diff --git a/lib/dash/commander.rb b/lib/dash/commander.rb index 98e99d52..4ca03544 100644 --- a/lib/dash/commander.rb +++ b/lib/dash/commander.rb @@ -110,7 +110,7 @@ def lock @commands[:lock] ||= Dash::Commands::Lock.new(config) end - # Guards the kamal-proxy container, which a host runs once for every + # Guards the dash-proxy container, which a host runs once for every # destination deployed onto it. Every destination contends for this one. def server_lock @commands[:server_lock] ||= Dash::Commands::Lock.new(config, scope: :server) diff --git a/lib/dash/commands/accessory/proxy.rb b/lib/dash/commands/accessory/proxy.rb index e26dc3ca..0d7051fb 100644 --- a/lib/dash/commands/accessory/proxy.rb +++ b/lib/dash/commands/accessory/proxy.rb @@ -11,6 +11,6 @@ def remove private def proxy_exec(*command) - docker :exec, proxy_container_name, "kamal-proxy", *command + docker :exec, proxy_container_name, "dash-proxy", *command end end diff --git a/lib/dash/commands/app.rb b/lib/dash/commands/app.rb index 22001dc5..99be8f6f 100644 --- a/lib/dash/commands/app.rb +++ b/lib/dash/commands/app.rb @@ -18,7 +18,7 @@ def run(hostname: nil) "--detach", "--restart", role.restart_policy, "--name", container_name, - "--network", "kamal", + "--network", "dash", *([ "--hostname", hostname ] if hostname), "--env", "KAMAL_CONTAINER_NAME=\"#{container_name}\"", "--env", "KAMAL_VERSION=\"#{config.version}\"", diff --git a/lib/dash/commands/app/execution.rb b/lib/dash/commands/app/execution.rb index 9c66832d..5cb33700 100644 --- a/lib/dash/commands/app/execution.rb +++ b/lib/dash/commands/app/execution.rb @@ -13,7 +13,7 @@ def execute_in_new_container(*command, interactive: false, detach: false, env:) ("--detach" if detach), ("--rm" unless detach), "--name", container_name_for_exec, - "--network", "kamal", + "--network", "dash", *role&.env_args(host), *argumentize("--env", env), *role.logging_args, diff --git a/lib/dash/commands/app/proxy.rb b/lib/dash/commands/app/proxy.rb index 8f9407c5..bb641417 100644 --- a/lib/dash/commands/app/proxy.rb +++ b/lib/dash/commands/app/proxy.rb @@ -39,6 +39,6 @@ def create_ssl_directory private def proxy_exec(*command) - docker :exec, proxy_container_name, "kamal-proxy", *command + docker :exec, proxy_container_name, "dash-proxy", *command end end diff --git a/lib/dash/commands/docker.rb b/lib/dash/commands/docker.rb index 314c128a..8c54f438 100644 --- a/lib/dash/commands/docker.rb +++ b/lib/dash/commands/docker.rb @@ -41,10 +41,44 @@ def manifest_available?(image) end def create_network - docker :network, :create, :kamal + docker :network, :create, Dash::Configuration::Proxy::NETWORK + end + + # Stage 3c: docker cannot rename a network, so `dash` is created alongside + # `kamal` and everything still on the old one is joined to the new one. + # + # App containers would be replaced by the next deploy anyway; accessories are + # not, and that is the whole point — without this a renamed proxy cannot + # reach `db` or `redis`. Connecting a container that is already attached + # fails, so each connect tolerates its own failure rather than aborting the + # sweep. The old network is never removed; that is documented manual cleanup + # and stage 3d's code change. + def connect_legacy_network_containers + any \ + combine( + legacy_network_exists, + pipe(legacy_network_container_names, connect_each_to_network) + ), + [ :true ] end private + def legacy_network_exists + docker :network, :inspect, Dash::Configuration::Proxy::LEGACY_NETWORK, ">", "/dev/null", "2>&1" + end + + def legacy_network_container_names + docker :network, :inspect, Dash::Configuration::Proxy::LEGACY_NETWORK, + "--format", "'{{range .Containers}}{{.Name}}{{\"\\n\"}}{{end}}'" + end + + # Already-attached containers make `network connect` fail; tolerate each + # one's failure rather than letting it abort the sweep. + def connect_each_to_network + [ :xargs, "-r", "-I{}", "sh", "-c", + "'docker network connect #{Dash::Configuration::Proxy::NETWORK} {} 2>/dev/null || true'" ] + end + def get_docker shell \ any \ diff --git a/lib/dash/commands/loadbalancer.rb b/lib/dash/commands/loadbalancer.rb index cfe91b19..58e271ce 100644 --- a/lib/dash/commands/loadbalancer.rb +++ b/lib/dash/commands/loadbalancer.rb @@ -14,7 +14,7 @@ def run docker \ :run, "--name", container_name, - "--network", "kamal", + "--network", "dash", "--detach", "--restart", "unless-stopped", "--label", label, @@ -38,28 +38,28 @@ def start_or_run end def deploy(targets: []) - docker :exec, container_name, "kamal-proxy", "deploy", loadbalancer_config.config.service, + docker :exec, container_name, "dash-proxy", "deploy", loadbalancer_config.config.service, *loadbalancer_config.deploy_command_args(targets: targets) end # `retry` takes a host, or --all; the rest take no arguments. def domains(subcommand, *args) - docker :exec, container_name, "kamal-proxy", "domains", subcommand, *args + docker :exec, container_name, "dash-proxy", "domains", subcommand, *args end def list(json: false) - docker :exec, container_name, "kamal-proxy", :list, *("--json" if json) + docker :exec, container_name, "dash-proxy", :list, *("--json" if json) end # Cache policy is edge-only under load balancing (see the layering contract), # so the cache admin surface lives here - registered under the bare service # name, unlike the per-role services on the proxy hosts. def cache_stats(count: false, json: false) - docker :exec, container_name, "kamal-proxy", :cache, :stats, *optionize({ count: count || nil, json: json || nil }.compact) + docker :exec, container_name, "dash-proxy", :cache, :stats, *optionize({ count: count || nil, json: json || nil }.compact) end def cache_purge(service, path_prefix: nil) - docker :exec, container_name, "kamal-proxy", :cache, :purge, service, *optionize({ "path-prefix": path_prefix }.compact) + docker :exec, container_name, "dash-proxy", :cache, :purge, service, *optionize({ "path-prefix": path_prefix }.compact) end def config_digest @@ -94,16 +94,24 @@ def follow_logs(host:, timestamps: true, grep: nil, grep_options: nil) end # Prune by the label the container was actually created with - on a shared - # proxy host that is the kamal-proxy title, and pruning by the loadbalancer - # title would leave the container behind for `run` to collide with. + # proxy host that is the dash-proxy title, and pruning by the loadbalancer + # title would leave the container behind for `run` to collide with. Both the + # current and the pre-rename title are pruned, so a container created before + # the rename is not left behind to collide either. def remove_container - docker :container, :prune, "--force", "--filter", "label=#{label}" + combine \ + prune_containers_titled(image_title), + prune_containers_titled(legacy_image_title) end # Image label filters match labels baked into the image, and the load balancer - # runs the kamal-proxy image whichever host it sits on. + # runs the dash-proxy image whichever host it sits on. Both titles are matched + # so a host still carrying a pre-rename image is cleaned up too; Docker ANDs + # multiple `--filter label=` values, so that is two commands. def remove_image - docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy" + combine \ + prune_images_titled(Dash::Configuration::Proxy::IMAGE_TITLE), + prune_images_titled(Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE) end def ensure_directory @@ -153,28 +161,50 @@ def on_proxy_host? loadbalancer_config.on_proxy_host? end + # The full `key=value` the container is created with, so `--label #{label}` + # stays correct. The prune helpers take a bare title instead. def label + "org.opencontainers.image.title=#{image_title}" + end + + def image_title if on_proxy_host? - "org.opencontainers.image.title=kamal-proxy" + Dash::Configuration::Proxy::IMAGE_TITLE else - "org.opencontainers.image.title=kamal-loadbalancer" + Dash::Configuration::Proxy::LOADBALANCER_IMAGE_TITLE end end - # kamal-proxy keeps its state under /home/kamal-proxy/.config/kamal-proxy + def legacy_image_title + if on_proxy_host? + Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE + else + Dash::Configuration::Proxy::LEGACY_LOADBALANCER_IMAGE_TITLE + end + end + + def prune_containers_titled(title) + docker :container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=#{title}" + end + + def prune_images_titled(title) + docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=#{title}" + end + + # dash-proxy keeps its state under /home/dash-proxy/.config/dash-proxy # whichever host it runs on - only the volume name differs, so a dedicated # load balancer and a shared proxy host never fight over the same volume. # (The apps-config mount comes with run_args, via the proxy's run surface.) def config_volume if on_proxy_host? - [ "--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy" ] + [ "--volume", "dash-proxy-config:/home/dash-proxy/.config/dash-proxy" ] else - [ "--volume", "kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy" ] + [ "--volume", "dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy" ] end end # The certificate store lives in whichever config volume this loadbalancer - # actually mounts — the shared kamal-proxy one on a proxy host. + # actually mounts — the shared dash-proxy one on a proxy host. def cert_store_volume_args config_volume end diff --git a/lib/dash/commands/lock.rb b/lib/dash/commands/lock.rb index 94088c02..06dbaf3a 100644 --- a/lib/dash/commands/lock.rb +++ b/lib/dash/commands/lock.rb @@ -4,7 +4,7 @@ class Dash::Commands::Lock < Dash::Commands::Base # The deploy lock is scoped to service+destination, so two destinations can - # deploy at once. Server-scoped resources — above all the single kamal-proxy + # deploy at once. Server-scoped resources — above all the single dash-proxy # container a host runs for every destination on it — need a lock that every # destination contends for, hence :server. SCOPES = %i[ destination server ].freeze diff --git a/lib/dash/commands/proxy.rb b/lib/dash/commands/proxy.rb index 089adcb6..60fd95c8 100644 --- a/lib/dash/commands/proxy.rb +++ b/lib/dash/commands/proxy.rb @@ -28,7 +28,7 @@ def run(digest: nil, name: nil) *proxy_run_config.network_args, "--detach", "--restart", "unless-stopped", - "--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", + "--volume", "dash-proxy-config:/home/dash-proxy/.config/dash-proxy", *config_digest_label_args(digest), *proxy_run_config.docker_options_args, *proxy_run_config.image, @@ -38,6 +38,58 @@ def run(digest: nil, name: nil) end end + # Stage 3c migrations. All three are idempotent and guarded on the + # destination not existing, so a second deploy is a no-op. Stage 3d deletes + # them along with the legacy constants they read. + + # Copies the pre-rename config volume into the new one, before anything + # starts. The volume holds the routing table and the ACME account and + # certificate cache; losing it means re-issuing every certificate and + # spending Let's Encrypt rate limits to get back where we were. + # + # Runs in the dash-proxy image itself — already pulled by this point in the + # boot sequence, and its ubuntu base has sh and cp. `--user root` because the + # image's own user cannot write the destination volume; `cp -a` preserves the + # uid, which the rename leaves at 1001. + # The guard is negated and leads the chain, with `|| true` last, because + # shell `&&` and `||` share precedence and associate left: written as + # `exists || legacy_exists && create && copy` it would parse as + # `((exists || legacy_exists) && create) && copy` and re-copy the legacy + # volume over live state on every deploy. Leading with `! exists` makes the + # whole chain a single left-associative AND, which short-circuits correctly. + def copy_legacy_config_volume(volume: Dash::Configuration::Proxy::CONFIG_VOLUME, legacy: Dash::Configuration::Proxy::LEGACY_CONFIG_VOLUME) + any \ + combine( + negate(volume_exists(volume)), + volume_exists(legacy), + docker(:volume, :create, volume), + copy_between_volumes(legacy, volume) + ), + [ :true ] + end + + # Stops and removes a pre-rename proxy container so the renamed one can claim + # ports 80/443. No port-holder handoff spans two container names, which is + # why this stage accepts a brief outage per host. + def remove_legacy_container(timeout: nil) + any \ + combine( + container_exists(Dash::Configuration::Proxy::LEGACY_CONTAINER_NAME), + docker(:container, :stop, *("--time=#{timeout}" if timeout), Dash::Configuration::Proxy::LEGACY_CONTAINER_NAME), + docker(:container, :rm, Dash::Configuration::Proxy::LEGACY_CONTAINER_NAME) + ), + [ :true ] + end + + def remove_legacy_holder_container + any \ + combine( + container_exists(Dash::Configuration::Proxy::LEGACY_HOLDER_CONTAINER_NAME), + docker(:container, :rm, "--force", Dash::Configuration::Proxy::LEGACY_HOLDER_CONTAINER_NAME) + ), + [ :true ] + end + def start docker :container, :start, container_name end @@ -77,15 +129,15 @@ def pull end def list(name: container_name, json: false) - docker :exec, name, "kamal-proxy", :list, *("--json" if json) + docker :exec, name, "dash-proxy", :list, *("--json" if json) end def cache_stats(count: false, json: false) - docker :exec, container_name, "kamal-proxy", :cache, :stats, *optionize({ count: count || nil, json: json || nil }.compact) + docker :exec, container_name, "dash-proxy", :cache, :stats, *optionize({ count: count || nil, json: json || nil }.compact) end def cache_purge(service, path_prefix: nil) - docker :exec, container_name, "kamal-proxy", :cache, :purge, service, *optionize({ "path-prefix": path_prefix }.compact) + docker :exec, container_name, "dash-proxy", :cache, :purge, service, *optionize({ "path-prefix": path_prefix }.compact) end # One mount destination per line - what the running container was actually @@ -108,12 +160,12 @@ def run_holder docker \ :run, "--name", proxy_run_config.holder_container_name, - "--network", "kamal", + "--network", "dash", "--detach", "--restart", "unless-stopped", *proxy_run_config.holder_docker_args, *proxy_run_config.image, - "kamal-proxy", "hold" + "dash-proxy", "hold" end def start_holder_or_run @@ -131,7 +183,7 @@ def disable_restart end def drain(timeout: nil) - docker :exec, container_name, "kamal-proxy", :drain, *("--drain-timeout=#{timeout}s" if timeout) + docker :exec, container_name, "dash-proxy", :drain, *("--drain-timeout=#{timeout}s" if timeout) end def wait_for_exit(name: container_name) @@ -161,15 +213,24 @@ def follow_logs(host:, timestamps: true, grep: nil, grep_options: nil) # `retry` takes a host, or --all; the rest take no arguments. def domains(subcommand, *args) - docker :exec, container_name, "kamal-proxy", "domains", subcommand, *args + docker :exec, container_name, "dash-proxy", "domains", subcommand, *args end + # Docker ANDs multiple `--filter label=` values, so matching both the current + # and the pre-rename image title takes two commands rather than one filter + # with two values. Without the legacy pass, `dash proxy remove` on a host that + # has not yet been through the rename silently leaves the old container and + # image behind. Stage 3d drops the legacy half. def remove_container - docker :container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy" + combine \ + prune_containers_titled(Dash::Configuration::Proxy::IMAGE_TITLE), + prune_containers_titled(Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE) end def remove_image - docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy" + combine \ + prune_images_titled(Dash::Configuration::Proxy::IMAGE_TITLE), + prune_images_titled(Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE) end def cleanup_traefik @@ -245,7 +306,7 @@ def container_name end def cert_store_volume_args - [ "--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy" ] + [ "--volume", "dash-proxy-config:/home/dash-proxy/.config/dash-proxy" ] end # Same fallback as #pull: without a run config the image comes from the @@ -262,14 +323,52 @@ def config_digest_label_args(digest) [ "--label", "#{CONFIG_DIGEST_LABEL}=#{digest}" ] if digest end + def negate(command) + [ "!", *command ] + end + + def volume_exists(name) + docker :volume, :inspect, name, ">", "/dev/null", "2>&1" + end + + def container_exists(name) + docker :container, :inspect, name, ">", "/dev/null", "2>&1" + end + + def copy_between_volumes(from, to) + docker \ + :run, "--rm", "--user", "root", "--entrypoint", "sh", + "--volume", "#{from}:/from", + "--volume", "#{to}:/to", + proxy_image, + "-c", "'cp -a /from/. /to/'" + end + + # The image the volume copy borrows. The proxy this gem is pinned to is + # already pulled by the time the copy runs, and `rake release` gates on + # MINIMUM_VERSION being published, so this is always resolvable — unlike + # the legacy boot path's image, which is read from a file on the host. + def proxy_image + proxy_run_config&.image || + "#{config.proxy_boot.image_default}:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}" + end + + def prune_containers_titled(title) + docker :container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=#{title}" + end + + def prune_images_titled(title) + docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=#{title}" + end + def docker_run(digest: nil) docker \ :run, "--name", container_name, - "--network", "kamal", + "--network", "dash", "--detach", "--restart", "unless-stopped", - "--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", + "--volume", "dash-proxy-config:/home/dash-proxy/.config/dash-proxy", *config_digest_label_args(digest), *config.proxy_boot.apps_volume.docker_args end diff --git a/lib/dash/commands/proxy/cert_transfer.rb b/lib/dash/commands/proxy/cert_transfer.rb index c8fb2a03..326df845 100644 --- a/lib/dash/commands/proxy/cert_transfer.rb +++ b/lib/dash/commands/proxy/cert_transfer.rb @@ -18,7 +18,7 @@ module Dash::Commands::Proxy::CertTransfer # Through the RPC socket of the running container, under the proxy's own # certificate write lock, so a backup taken mid-renewal is never torn. def export_certs - docker :exec, container_name, "kamal-proxy", :export, :certs, certs_archive_container_path + docker :exec, container_name, "dash-proxy", :export, :certs, certs_archive_container_path end # Reads the data directory offline over the config volume — only safe when @@ -28,10 +28,10 @@ def export_certs_offline *cert_store_volume_args, *config.proxy_boot.apps_volume.docker_args, *one_off_image, - "kamal-proxy", :export, :certs, certs_archive_container_path + "dash-proxy", :export, :certs, certs_archive_container_path end - # Offline by design (kamal-proxy import has no RPC path): the one-off + # Offline by design (dash-proxy import has no RPC path): the one-off # container mounts the config volume — creating it when no proxy has booted # yet, which is the Traefik-migration case — and the staged source streams # through stdin. @@ -42,7 +42,7 @@ def import_certs(traefik_acme: false, resolver: nil, force: false, verify: false # run whatever follows on the target host. import_command = shell [ "cat > #{CONTAINER_IMPORT_PATH} &&", - "kamal-proxy import certs", + "dash-proxy import certs", *optionize({ source_flag => CONTAINER_IMPORT_PATH, resolver: resolver, force: force || nil, verify: verify || nil }.compact, with: "=") ] diff --git a/lib/dash/commands/prune.rb b/lib/dash/commands/prune.rb index 864f1522..742468ad 100644 --- a/lib/dash/commands/prune.rb +++ b/lib/dash/commands/prune.rb @@ -15,7 +15,7 @@ def tagged_images # Scoped to one role so a busy sibling role cannot push another role's newest # container past the retain window. That matters beyond disk hygiene: a - # container kamal-proxy has put to sleep is `exited`, so it is a removal + # container dash-proxy has put to sleep is `exited`, so it is a removal # candidate, and once it is gone every wake 404s. With `retain >= 1` a role's # newest container always survives, and the slept one is always the newest — # sleeping happens to the current release. diff --git a/lib/dash/configuration.rb b/lib/dash/configuration.rb index 658903d7..c3f85f2a 100644 --- a/lib/dash/configuration.rb +++ b/lib/dash/configuration.rb @@ -478,7 +478,7 @@ def ensure_proxy_protocol_names_its_peers return true if offenders.empty? warn "Host(s) #{offenders.sort.join(", ")}: proxy_protocol is enabled without proxy_protocol_allow_ips, " \ - "so kamal-proxy honours a PROXY header from any peer that can reach the port. That header sets the client " \ + "so dash-proxy honours a PROXY header from any peer that can reach the port. That header sets the client " \ "address `allow_ips`, `rate_limit` and the access log all use. Name the load balancers you actually run." true @@ -503,11 +503,11 @@ def ensure_sleep_has_a_docker_socket return true if offenders.empty? raise Dash::ConfigurationError, "Role(s) #{offenders.map(&:name).join(", ")}: " \ - "proxy/sleep requires proxy/run/docker_socket - kamal-proxy can only stop and start containers " \ + "proxy/sleep requires proxy/run/docker_socket - dash-proxy can only stop and start containers " \ "through the container runtime socket, and it is not mounted into the proxy without it" end - # kamal-proxy resolves a zero max_idle_conns to its default of 100 + # dash-proxy resolves a zero max_idle_conns to its default of 100 # (target_pool.go resolves defaults from zeros), so the one value an # operator writes to mean "keep none" is the one value that cannot mean it. # Legal, so warn rather than raise. @@ -518,14 +518,14 @@ def ensure_max_idle_conns_meaningful return true if offenders.empty? warn "Role(s) #{offenders.map(&:name).join(", ")}: target/max_idle_conns: 0 means the proxy default of 100, " \ - "not \"keep none\" - kamal-proxy resolves its defaults from zeros. Leave it unset for the default, " \ + "not \"keep none\" - dash-proxy resolves its defaults from zeros. Leave it unset for the default, " \ "or set 1 for the practical minimum." true end # `intercept_errors` discards the app's error body and renders the proxy's own - # page instead. With no pages to render, kamal-proxy falls back to a bare + # page instead. With no pages to render, dash-proxy falls back to a bare # plaintext status line — so the app's error page is thrown away and replaced # by the words "Bad Gateway". Legal, and almost never the intent. def ensure_intercepted_errors_have_pages @@ -535,7 +535,7 @@ def ensure_intercepted_errors_have_pages return true if offenders.empty? warn "Role(s) #{offenders.map(&:name).join(", ")}: intercept_errors is set but no error_pages_path is " \ - "configured, so kamal-proxy replaces the app's error page with a bare plaintext status line. " \ + "configured, so dash-proxy replaces the app's error page with a bare plaintext status line. " \ "Set `error_pages_path:` to serve your own pages, or remove `intercept_errors` to let the app's through." true @@ -543,7 +543,7 @@ def ensure_intercepted_errors_have_pages # Rate limiting and IP deny rules are only as correct as the address they key # on. `forward_headers: true` says something sits in front of the proxy, and - # without `trusted_proxies` kamal-proxy keys on that something's address + # without `trusted_proxies` dash-proxy keys on that something's address # rather than the client's — so the limiter throttles the whole world as one # client (or nobody), and a deny list denies nobody it was written for. Warn # rather than raise: the config is legal, just almost certainly not what was @@ -568,7 +568,7 @@ def ensure_rate_limit_can_identify_clients offenders.each do |role_name, features| warn "Role #{role_name}: #{features.join(" and ")} is set with forward_headers, " \ - "but no proxy/client_ip/trusted_proxies. kamal-proxy will key on the address of " \ + "but no proxy/client_ip/trusted_proxies. dash-proxy will key on the address of " \ "whatever sits in front of it, not on the client's — so the rules apply to every " \ "visitor as one client, or to none of them. Declare the proxies in front with " \ "`client_ip: trusted_proxies:`." diff --git a/lib/dash/configuration/accessory.rb b/lib/dash/configuration/accessory.rb index 43efa940..147b1a69 100644 --- a/lib/dash/configuration/accessory.rb +++ b/lib/dash/configuration/accessory.rb @@ -1,7 +1,7 @@ class Dash::Configuration::Accessory include Dash::Configuration::Validation - DEFAULT_NETWORK = "kamal" + DEFAULT_NETWORK = "dash" delegate :argumentize, :optionize, to: Dash::Utils @@ -129,7 +129,7 @@ def initialize_env # The load balancer fans the app's own service out to role targets only # (see Dash::Cli::Proxy#loadbalancer), so an accessory is never behind it - # and must keep the host/TLS it registers with kamal-proxy directly. + # and must keep the host/TLS it registers with dash-proxy directly. def initialize_proxy Dash::Configuration::Proxy.new \ config: config, diff --git a/lib/dash/configuration/docs/accessory.yml b/lib/dash/configuration/docs/accessory.yml index eefff059..9484e03d 100644 --- a/lib/dash/configuration/docs/accessory.yml +++ b/lib/dash/configuration/docs/accessory.yml @@ -150,7 +150,7 @@ accessories: # # The network the accessory will be attached to. # - # Defaults to kamal: + # Defaults to dash: network: custom # Proxy @@ -160,12 +160,12 @@ accessories: # app-level `proxy:` (see `dash docs proxy`), though root-only keys such as # `loadbalancer` and `reboot_on_deploy` have no effect inside an accessory. # Declaring a proxy here makes the accessory's hosts proxy hosts: - # `dash proxy boot` (and `dash deploy`) will run kamal-proxy on them + # `dash proxy boot` (and `dash deploy`) will run dash-proxy on them # automatically. # # Accessories are never load balanced. The loadbalancer fans the app's own # service out to its role targets, so an accessory always registers its - # hostname and TLS with the kamal-proxy on its own host — whether or not the + # hostname and TLS with the dash-proxy on its own host — whether or not the # loadbalancer is active for the app. Point the accessory's DNS record at the # accessory host, not at the loadbalancer. # diff --git a/lib/dash/configuration/docs/configuration.yml b/lib/dash/configuration/docs/configuration.yml index 2314d31d..9ee9dda5 100644 --- a/lib/dash/configuration/docs/configuration.yml +++ b/lib/dash/configuration/docs/configuration.yml @@ -201,7 +201,7 @@ accessories: # Proxy # -# Configuration for kamal-proxy, see dash docs proxy: +# Configuration for dash-proxy, see dash docs proxy: proxy: ... diff --git a/lib/dash/configuration/docs/proxy.yml b/lib/dash/configuration/docs/proxy.yml index f2a63876..d56e203a 100644 --- a/lib/dash/configuration/docs/proxy.yml +++ b/lib/dash/configuration/docs/proxy.yml @@ -1,6 +1,6 @@ # Proxy # -# Kamal uses [kamal-proxy](https://github.com/basecamp/kamal-proxy) to provide +# Kamal uses [dash-proxy](https://github.com/basecamp/dash-proxy) to provide # gapless deployments. It runs on ports 80 and 443 and forwards requests to the # application container. # @@ -74,13 +74,13 @@ proxy: # Sharing one loadbalancer between several dash apps # # More than one dash app may point `loadbalancer:` at the same host. Each app - # registers its own service on the shared kamal-proxy and keeps its own + # registers its own service on the shared dash-proxy and keeps its own # deploy.yml; the load balancer multiplexes them by hostname. # # The rules dash enforces for that topology: # - # * Service state survives a reboot. kamal-proxy persists its services in the - # `kamal-loadbalancer-config` volume (or `kamal-proxy-config` when the + # * Service state survives a reboot. dash-proxy persists its services in the + # `dash-loadbalancer-config` volume (or `dash-proxy-config` when the # loadbalancer shares a proxy host), and `dash proxy reboot` only replaces # the container. Rebooting from app A does not drop app B's routes — the # surviving service list is printed after the restart. @@ -104,7 +104,7 @@ proxy: # Automatic proxy reboot on deploy # - # When `dash deploy` detects that the running kamal-proxy container was + # When `dash deploy` detects that the running dash-proxy container was # started with a different image, version or run options than the current # configuration, it reboots the proxy automatically — one host at a time — # before booting the app. @@ -126,13 +126,13 @@ proxy: # SSL # - # kamal-proxy can provide automatic HTTPS for your application via Let's Encrypt. + # dash-proxy can provide automatic HTTPS for your application via Let's Encrypt. # # This requires that we are deploying to one server and the host option is set. # The host value must point to the server we are deploying to, and port 443 must be # open for the Let's Encrypt challenge to succeed. # - # If you set `ssl` to `true`, `kamal-proxy` will stop forwarding headers to your app, + # If you set `ssl` to `true`, `dash-proxy` will stop forwarding headers to your app, # unless you explicitly set `forward_headers: true` # # Defaults to `false`: @@ -156,7 +156,7 @@ proxy: # absolute http(s) URL is called directly. Answer 2xx to approve. On-demand TLS # replaces the static hostname list, so it cannot be combined with # `host`/`hosts`, with `certificate_pem`, or with `ssl_domains` — dash rejects - # those at config time, because kamal-proxy would reject the deploy and there + # those at config time, because dash-proxy would reject the deploy and there # is no sensible winner to pick. # # `client_ca_pem` requires mutual TLS: clients must present a certificate @@ -176,7 +176,7 @@ proxy: # SSL redirect # - # By default, kamal-proxy will redirect all HTTP requests to HTTPS when SSL is enabled. + # By default, dash-proxy will redirect all HTTP requests to HTTPS when SSL is enabled. # If you prefer that HTTP traffic is passed through to your application (along with # HTTPS traffic), you can disable this redirect by setting `ssl_redirect: false`: ssl_redirect: false @@ -244,7 +244,7 @@ proxy: # # If you are behind a trusted proxy, you can set this to `true` to forward the headers. # - # By default, kamal-proxy will not forward the headers if the `ssl` option is set to `true`, and + # By default, dash-proxy will not forward the headers if the `ssl` option is set to `true`, and # will forward them if it is set to `false`. forward_headers: true @@ -278,7 +278,7 @@ proxy: set: Strict-Transport-Security: max-age=31536000 add: - X-Served-By: kamal-proxy + X-Served-By: dash-proxy remove: - Server @@ -329,7 +329,7 @@ proxy: # # Authentication tokens live in the PROXY's environment, not the app's: polls # send `KAMAL_PROXY_REDIRECTS_TOKEN` as a bearer token when set, and - # `POST /.kamal-proxy/redirects/refresh` nudges an immediate re-poll when + # `POST /.dash-proxy/redirects/refresh` nudges an immediate re-poll when # authenticated with `KAMAL_PROXY_REFRESH_TOKEN`. Set both via # `proxy.run.options.env`, next to `KAMAL_PROXY_DOMAINS_TOKEN` — never as # deploy flags, which leak into process listings and audit logs. @@ -397,19 +397,19 @@ proxy: password_secret: WEB_BASIC_AUTH_PASSWORD # # ### Notes - # - Requires a kamal-proxy that supports `--basic-auth`. This is newer than + # - Requires a dash-proxy that supports `--basic-auth`. This is newer than # the current `MINIMUM_VERSION`, so make sure your proxy is up to date # before enabling it — an older proxy fails the deploy on an unknown flag. # - Basic credentials are replayable and are sent on every request. Use this # with `ssl: true`, or terminate TLS in front of the proxy. - # - kamal-proxy removes the `Authorization` header before forwarding, so a + # - dash-proxy removes the `Authorization` header before forwarding, so a # service behind basic auth cannot also pass credentials through to its # target. When load balancing, the credentials are enforced by the load # balancer only. # Dynamic TLS domains # - # kamal-proxy can learn TLS hostnames from your application at runtime + # dash-proxy can learn TLS hostnames from your application at runtime # instead of fixing them at deploy time. It polls `source` — a path # (resolved against a healthy app target) or an absolute http(s) URL — # for the domain list and manages Let's Encrypt certificates for it @@ -434,21 +434,21 @@ proxy: # Who the client is # # Rate limiting and IP allow lists are both only as correct as the address they - # key on, so configure this first if anything sits in front of kamal-proxy. + # key on, so configure this first if anything sits in front of dash-proxy. # # With no `trusted_proxies`, the client is always the address that opened the # connection — nothing a client sends can influence it, which is what makes the # allow list meaningful. # # Once you declare `trusted_proxies`, and only when the connecting address is - # one of them, kamal-proxy reads the forwarded chain instead: it walks the + # one of them, dash-proxy reads the forwarded chain instead: it walks the # chain from the nearest hop backwards past every proxy you declared, and the # first address none of your proxies wrote is the client. **List every hop**, - # not only the one that connects to kamal-proxy — a chain it cannot resolve + # not only the one that connects to dash-proxy — a chain it cannot resolve # denies the request rather than falling back to the connecting address. # # `header` names the header carrying the original client IP (`CF-Connecting-IP` - # behind Cloudflare, `True-Client-IP` behind some others); kamal-proxy reads it + # behind Cloudflare, `True-Client-IP` behind some others); dash-proxy reads it # instead of `X-Forwarded-For`. It is only honoured when `trusted_proxies` is # set, because otherwise it is just something the client wrote — dash rejects # that combination rather than appearing to honour it. @@ -501,7 +501,7 @@ proxy: # # Refuse requests whose full User-Agent matches one of these RE2 patterns, # checked after the IP rules. A missing User-Agent only matches an explicit - # '^$' pattern. Patterns are matched by kamal-proxy (Go RE2), so dash checks + # '^$' pattern. Patterns are matched by dash-proxy (Go RE2), so dash checks # only their shape, not their syntax. deny_user_agents: - 'BadBot/.*' @@ -661,7 +661,7 @@ proxy: # This block is the *policy*, and it is per service. Where the entries live is # proxy-wide and set under `run/cache` below. # - # Only `enabled` is required. Everything else keeps kamal-proxy's own default + # Only `enabled` is required. Everything else keeps dash-proxy's own default # until you set it. # # `max_ttl` caps the lifetime the app asks for, in seconds, so one mistaken @@ -690,7 +690,7 @@ proxy: # ### When it is not caching # # A cache that quietly stores nothing is the usual first surprise. Start with - # `dash proxy cache stats`; kamal-proxy also explains every refusal — check + # `dash proxy cache stats`; dash-proxy also explains every refusal — check # `dash proxy logs` for the reason, and the `cache_refusals_total` metric # (by `reason`) if you run with `metrics_port`. # The common reasons are a missing `Cache-Control: public, max-age=...` on the @@ -739,7 +739,7 @@ proxy: # Read-only targets # - # kamal-proxy can split traffic between the deployed (writer) targets and a + # dash-proxy can split traffic between the deployed (writer) targets and a # set of read-only targets, e.g. app instances backed by database replicas. # Read requests are routed to the read targets; write requests always go to # the writers. @@ -771,7 +771,7 @@ proxy: # re-pinned, so a deploy does not strand anybody. Reads served by a # `read_targets` replica are never pinned. # - # `cookie` renames the pin cookie; kamal-proxy picks a sensible default. + # `cookie` renames the pin cookie; dash-proxy picks a sensible default. session_affinity: enabled: true cookie: _kamal_affinity @@ -827,19 +827,19 @@ proxy: publish: false # Publish ports to the host (default: true) bind_ips: # List of IPs to bind to when publishing ports - 0.0.0.0 - registry: registry:4443 # Extra registry prefix for the kamal-proxy image + registry: registry:4443 # Extra registry prefix for the dash-proxy image # (default: none). If you set this, also override # `repository` to a host-less path (e.g. - # myfork/kamal-proxy) - the default repository + # myfork/dash-proxy) - the default repository # below already embeds its ghcr.io host repository: ghcr.io/zoolutions/dash-proxy # Container repository for the - # kamal-proxy image (this is the default) - version: v1.0.0.7 # Version tag of the kamal-proxy image to use. + # dash-proxy image (this is the default) + version: v1.1.0.0 # Version tag of the dash-proxy image to use. # Defaults to the minimum version this gem # requires - only pin it to roll forward early, # never below the default port_holder: true # Zero-downtime proxy reboots (default: false). - # Runs a minimal long-lived kamal-proxy-net container that + # Runs a minimal long-lived dash-proxy-net container that # owns the published ports; proxy generations join its # network namespace and overlap during a reboot, so config # and version changes apply without dropping requests. @@ -857,7 +857,7 @@ proxy: # DNS-01 on their own. `auto` is an explicit opt-in that picks the provider # from the credentials it can see and logs at boot which one it armed; # `none` says "no DNS-01" explicitly. An unsupported name is rejected here, - # at config time - kamal-proxy would only log a warning and then never + # at config time - dash-proxy would only log a warning and then never # issue a certificate. # # A plain string (`dns_provider: cloudflare`) uses one provider for every @@ -866,7 +866,7 @@ proxy: # spread across registrars. Each provider's API credentials must be present # under `credentials` for its challenges to succeed. # - # kamal-proxy also accepts short aliases for the canonical names - `cf` + # dash-proxy also accepts short aliases for the canonical names - `cf` # (cloudflare), `do` (digitalocean), `gcp`/`google`/`googledns` (gcloud), # `gd` (godaddy), `hz` (hetzner), `nc` (namecheap), `aws`/`r53` (route53) # and `vr` (vultr). Prefer the canonical name; the aliases exist so a @@ -1018,15 +1018,15 @@ proxy: # Defaults to false: reuse_port: true - # Escape hatch for `kamal-proxy run` + # Escape hatch for `dash-proxy run` # - # Anything kamal-proxy accepts that has no key above. Note the difference + # Anything dash-proxy accepts that has no key above. Note the difference # from `options` below, which many people expect to do this: `flags` goes to - # `kamal-proxy run`, `options` goes to `docker run`. + # `dash-proxy run`, `options` goes to `docker run`. # # `true` renders a bare flag; anything else renders `--flag value`. No # translation is applied, so write Go durations and lists the way - # kamal-proxy wants them. + # dash-proxy wants them. # # A key here that a named setting already emits is rejected rather than # passed twice — set one or the other. @@ -1037,7 +1037,7 @@ proxy: # # Path to the container runtime socket, which is what `proxy/sleep` needs in # order to stop and start containers. Setting it does two things: it passes - # the path to kamal-proxy, and it mounts that path into the proxy container, + # the path to dash-proxy, and it mounts that path into the proxy container, # since the flag alone only says where to look. # # **Reaching this socket is root-equivalent on the host.** It is a separate, @@ -1073,11 +1073,11 @@ proxy: store_timeout: 2 memory_size: 134_217_728 # `options` are `docker run` options for the proxy container - resource - # limits, labels, extra mounts - NOT kamal-proxy flags. A kamal-proxy flag + # limits, labels, extra mounts - NOT dash-proxy flags. A dash-proxy flag # the gem has no key for goes in `flags` above instead. options: # Additional options to pass to `docker run` label: - - custom.label=kamal-proxy + - custom.label=dash-proxy memory: 512m cpus: 0.5 diff --git a/lib/dash/configuration/loadbalancer.rb b/lib/dash/configuration/loadbalancer.rb index 1a30f96c..4383e08c 100644 --- a/lib/dash/configuration/loadbalancer.rb +++ b/lib/dash/configuration/loadbalancer.rb @@ -1,6 +1,6 @@ class Dash::Configuration::Loadbalancer < Dash::Configuration::Proxy CONTAINER_NAME = "load-balancer".freeze - SHARED_CONTAINER_NAME = "kamal-proxy".freeze + SHARED_CONTAINER_NAME = "dash-proxy".freeze def self.validation_config_key "proxy" @@ -34,7 +34,7 @@ def directory File.join config.run_directory, "loadbalancer" end - # The load balancer is a kamal-proxy container, so proxy/run applies to it + # The load balancer is a dash-proxy container, so proxy/run applies to it # exactly as it does to the per-host proxies. Without a run block it still # needs the default surface (published ports, log rotation, the apps-config # mount and the run command) to boot from, so fall back to an empty config diff --git a/lib/dash/configuration/proxy.rb b/lib/dash/configuration/proxy.rb index 0b38583b..14c5d6af 100644 --- a/lib/dash/configuration/proxy.rb +++ b/lib/dash/configuration/proxy.rb @@ -2,11 +2,33 @@ class Dash::Configuration::Proxy include Dash::Configuration::Validation DEFAULT_LOG_REQUEST_HEADERS = [ "Cache-Control", "Last-Modified", "User-Agent" ] - CONTAINER_NAME = "kamal-proxy" - LOADBALANCER_CONTAINER_NAME = "kamal-loadbalancer" + CONTAINER_NAME = "dash-proxy" + LOADBALANCER_CONTAINER_NAME = "dash-loadbalancer" CLIENT_CA_FILENAME = "client-ca.pem" - # What `compress: true` offers. kamal-proxy has no "on" state without an + # The image label the prune filters key on, set by dash-proxy's publish + # workflow. + IMAGE_TITLE = "dash-proxy" + LOADBALANCER_IMAGE_TITLE = "dash-loadbalancer" + + NETWORK = "dash" + CONFIG_VOLUME = "dash-proxy-config" + LOADBALANCER_CONFIG_VOLUME = "dash-loadbalancer-config" + + # Pre-rename names, kept only so the stage-3c migration can find what a host + # already has: the container to replace, the volume to copy, the network to + # bridge, and the image label to keep pruning by. Nothing constructs a + # resource with these — stage 3d deletes them. + LEGACY_CONTAINER_NAME = "kamal-proxy" + LEGACY_LOADBALANCER_CONTAINER_NAME = "kamal-loadbalancer" + LEGACY_HOLDER_CONTAINER_NAME = "kamal-proxy-net" + LEGACY_NETWORK = "kamal" + LEGACY_CONFIG_VOLUME = "kamal-proxy-config" + LEGACY_LOADBALANCER_CONFIG_VOLUME = "kamal-loadbalancer-config" + LEGACY_IMAGE_TITLE = "kamal-proxy" + LEGACY_LOADBALANCER_IMAGE_TITLE = "kamal-loadbalancer" + + # What `compress: true` offers. dash-proxy has no "on" state without an # explicit list - --compress *is* the list - so the shorthand has to pick. # Best ratio first, matching the proxy's own default ordering; the client's # Accept-Encoding q-values still outrank this preference. @@ -14,7 +36,7 @@ class Dash::Configuration::Proxy SUPPORTED_COMPRESSION_ENCODINGS = %w[ gzip br zstd ].freeze - # kamal-proxy maps `brotli` onto the `br` token that travels in Content-Encoding. + # dash-proxy maps `brotli` onto the `br` token that travels in Content-Encoding. COMPRESSION_ENCODING_ALIASES = { "brotli" => "br" }.freeze # The layering contract. When the fork's load balancer fronts the per-host @@ -32,7 +54,7 @@ class Dash::Configuration::Proxy # Without load balancing the single proxy is every layer at once and the # whole surface applies to it. DEPLOY_OPTION_DISPOSITIONS = { - # --- Edge: TLS terminates where the handshake happens, and kamal-proxy + # --- Edge: TLS terminates where the handshake happens, and dash-proxy # gates TLSRedirect on TLSEnabled, so the whole family travels together. host: :edge, tls: :edge, @@ -59,7 +81,7 @@ class Dash::Configuration::Proxy "rate-limit-burst": :edge, "rate-limit-exempt": :edge, - # --- Edge: kamal-proxy deletes the Authorization header once a service + # --- Edge: dash-proxy deletes the Authorization header once a service # enforces basic auth, so an inner proxy would 401 the credential-less # request the load balancer forwards. Credentials belong at the edge only. "basic-auth": :edge, @@ -311,7 +333,7 @@ def path_prefixes proxy_config["path_prefixes"] || proxy_config["path_prefix"]&.split(",") || [] end - # Nil when unset: the default lives in kamal-proxy, not here. + # Nil when unset: the default lives in dash-proxy, not here. def healthcheck_path proxy_config.dig("healthcheck", "path") end @@ -370,7 +392,7 @@ def deploy_command_args(target:) optionize ({ target: "#{target}:#{app_port}" }).merge(deploy_options), with: "=" end - # kamal-proxy rollout deploy only accepts the target and the timeouts - the service already + # dash-proxy rollout deploy only accepts the target and the timeouts - the service already # exists, so it keeps the host, TLS, buffering and logging options of the live deploy. def rollout_deploy_options { @@ -426,7 +448,7 @@ def auto_load_balanced_primary_role? primary_role.present? && primary_role.running_proxy? && Array(primary_role.hosts).size > 1 end - # Flags for kamal-proxy's dynamic domain source (runtime TLS hostnames). + # Flags for dash-proxy's dynamic domain source (runtime TLS hostnames). # TLS terminates wherever these flags land — :edge in the layering contract. def ssl_domains_options { @@ -449,7 +471,7 @@ def tls_options # The connection pool between the proxy and this app's containers, and how # hard the proxy tries to place a request on a healthy one. # - # Every value is passed through exactly as written. kamal-proxy resolves its + # Every value is passed through exactly as written. dash-proxy resolves its # own defaults from a zero (target_pool.go), and it has to do that server # side because restored state and older RPC clients never see the CLI — so # substituting a default here would be both redundant and wrong. @@ -517,7 +539,7 @@ def headers_config proxy_config["headers"] || {} end - # kamal-proxy cuts a rule at the first colon, so a value carrying colons of + # dash-proxy cuts a rule at the first colon, so a value carrying colons of # its own arrives intact. def header_rules(direction, verb) (headers_config.dig(direction, verb) || {}).map { |name, value| "#{name}: #{value}" }.presence @@ -574,7 +596,7 @@ def compress_options # The cache policy, which is per service - the store it writes into is # proxy-wide and lives in proxy/run/cache. Only --cache is derived from a - # truthy key; every other default stays in kamal-proxy, so an unset key emits + # truthy key; every other default stays in dash-proxy, so an unset key emits # nothing rather than restating a default the gem would then have to track. def cache_options cache = proxy_config["cache"] || {} @@ -600,7 +622,7 @@ def tls_file_path(directory, filename) File.join([ directory, role_name, filename ].compact) end - # kamal-proxy takes the credential as : and cuts at the + # dash-proxy takes the credential as : and cuts at the # first colon, so a password may contain colons but a username may not (the # validator enforces that). The password is read from .dash/secrets when # password_secret names it, so it need not live in deploy.yml. @@ -628,7 +650,7 @@ def basic_auth_credential Dash::Utils.sensitive("#{basic_auth["username"]}:#{password}") end - # Serves both --path-timeout and --path-request-timeout, which kamal-proxy + # Serves both --path-timeout and --path-request-timeout, which dash-proxy # reads with one parser. A duration may be a Go string ("5m") or plain # seconds; 0 is a value, meaning no limit for that prefix. def path_timeout_args(key) diff --git a/lib/dash/configuration/proxy/acme.rb b/lib/dash/configuration/proxy/acme.rb index 8d149ff7..756b473d 100644 --- a/lib/dash/configuration/proxy/acme.rb +++ b/lib/dash/configuration/proxy/acme.rb @@ -1,7 +1,7 @@ -# ACME configuration for the kamal-proxy container, including the DNS-01 +# ACME configuration for the dash-proxy container, including the DNS-01 # challenge credentials. # -# Everything here except the credentials becomes a `kamal-proxy run` flag, so it +# Everything here except the credentials becomes a `dash-proxy run` flag, so it # lands in the run command and therefore in Proxy::Run#config_digest — changing # the block reboots the proxy on the next deploy. # @@ -9,14 +9,14 @@ # API token can rewrite your zone; `docker run --env TOKEN=...` would put it in # the host's process listing and in kamal's own audit log. class Dash::Configuration::Proxy::Acme - # The canonical provider names kamal-proxy MINIMUM_VERSION advertises. Kept in + # The canonical provider names dash-proxy MINIMUM_VERSION advertises. Kept in # step with the proxy by test/proxy_flag_coverage_test.rb, which compares this # list against the manifest bin/sync-proxy-flags generates from the image. DNS_PROVIDERS = %w[ auto cloudflare digitalocean gcloud godaddy hetzner namecheap none route53 vultr ].freeze - # Short forms kamal-proxy's ParseProviderName accepts but does not advertise, + # Short forms dash-proxy's ParseProviderName accepts but does not advertise, # so they cannot be generated from --help and are not drift-checked. DNS_PROVIDER_ALIASES = %w[ cf do gcp google googledns gd hz nc aws r53 vr ].freeze @@ -70,7 +70,7 @@ def run_command_options private # The hash form pins zones to the DNS host that serves them; `default` - # covers unmatched zones. kamal-proxy takes repeatable --acme-dns-provider + # covers unmatched zones. dash-proxy takes repeatable --acme-dns-provider # entries — zone=provider pairs plus at most one bare default — so the hash # becomes an array and Utils.optionize repeats the flag. The string form # passes through untouched and keeps meaning what it always has. diff --git a/lib/dash/configuration/proxy/boot.rb b/lib/dash/configuration/proxy/boot.rb index 61839657..3c6d9a61 100644 --- a/lib/dash/configuration/proxy/boot.rb +++ b/lib/dash/configuration/proxy/boot.rb @@ -41,10 +41,8 @@ def image_default "#{repository_name}/#{image_name}" end - # Stays kamal-proxy until the server-artifact rename ships a migration - # bridge — every deployed host has a running container by this name. def container_name - "kamal-proxy" + Dash::Configuration::Proxy::CONTAINER_NAME end def host_directory @@ -72,7 +70,7 @@ def apps_directory end def apps_container_directory - "/home/kamal-proxy/.apps-config" + "/home/dash-proxy/.apps-config" end def apps_volume diff --git a/lib/dash/configuration/proxy/run.rb b/lib/dash/configuration/proxy/run.rb index 048c40c7..07e4cc12 100644 --- a/lib/dash/configuration/proxy/run.rb +++ b/lib/dash/configuration/proxy/run.rb @@ -1,5 +1,5 @@ class Dash::Configuration::Proxy::Run - MINIMUM_VERSION = "v1.0.0.7" + MINIMUM_VERSION = "v1.1.0.0" DEFAULT_HTTP_PORT = 80 DEFAULT_HTTPS_PORT = 443 DEFAULT_LOG_MAX_SIZE = "10m" @@ -103,7 +103,7 @@ def image end def container_name - "kamal-proxy" + "dash-proxy" end # Zero-downtime reboots: a minimal long-lived holder container owns the @@ -114,14 +114,14 @@ def port_holder? end def holder_container_name - "kamal-proxy-net" + "dash-proxy-net" end def network_args if port_holder? [ "--network", "container:#{holder_container_name}" ] else - [ "--network", "kamal" ] + [ "--network", "dash" ] end end @@ -136,7 +136,7 @@ def options_args end def run_command - [ "kamal-proxy", "run", *optionize(run_command_options), *acme.run_command_args ].join(" ") + [ "dash-proxy", "run", *optionize(run_command_options), *acme.run_command_args ].join(" ") end def metrics_port @@ -158,7 +158,7 @@ def named_run_command_options .compact.merge(cache_options).merge(server_options) end - # Anything kamal-proxy accepts that has no key of its own yet. Values are + # Anything dash-proxy accepts that has no key of its own yet. Values are # optionized as written - `true` is a bare flag, anything else takes a value - # because the point of an escape hatch is that the gem holds no opinion about # the flag it is forwarding. @@ -189,7 +189,7 @@ def docker_options_args ].compact end - # The flag only tells kamal-proxy where to look inside its own container, so + # The flag only tells dash-proxy where to look inside its own container, so # without this mount the socket is not there and a sleeping service never # wakes - which the operator sees as one hung request, not as a misconfiguration. def docker_socket_args @@ -224,7 +224,7 @@ def apps_directory end def apps_container_directory - "/home/kamal-proxy/.apps-config" + "/home/dash-proxy/.apps-config" end def apps_volume @@ -288,7 +288,7 @@ def server_options end # A passthrough flag that a named key already emits would be optionized - # twice, and kamal-proxy would silently take the last one. Refuse instead. + # twice, and dash-proxy would silently take the last one. Refuse instead. # Only Proxy::Run knows which flags the named keys produce, so the check # cannot live in the validator with the rest. def ensure_no_conflicting_flags @@ -303,7 +303,7 @@ def ensure_no_conflicting_flags # than of any one service - the policy that fills the cache is per service, # in proxy/cache. The store itself is deliberately absent: a store URL may # embed credentials, so it travels as CACHE_STORE in the secrets env file - # (kamal-proxy reads it as the --cache-store default) rather than on a + # (dash-proxy reads it as the --cache-store default) rather than on a # command line that lands in process listings and the audit log. def cache_options cache = run_config["cache"] || {} diff --git a/lib/dash/configuration/role.rb b/lib/dash/configuration/role.rb index 182815f3..97e87d26 100644 --- a/lib/dash/configuration/role.rb +++ b/lib/dash/configuration/role.rb @@ -148,7 +148,7 @@ def readiness_source def readiness_description case readiness_source when :proxy - [ "kamal-proxy health check", proxy.healthcheck_path ].compact.join(" ") + [ "dash-proxy health check", proxy.healthcheck_path ].compact.join(" ") when :healthcheck healthcheck.port ? "healthcheck #{healthcheck.path}:#{healthcheck.port}" : "healthcheck (custom cmd)" when :healthcheck_exec @@ -168,7 +168,7 @@ def readiness_gated? end def stop_args - # When deploying with the proxy, kamal-proxy will drain request before returning so we don't need to wait. + # When deploying with the proxy, dash-proxy will drain request before returning so we don't need to wait. timeout = stop_timeout || (running_proxy? ? nil : config.drain_timeout) [ *argumentize("-t", timeout) ] diff --git a/lib/dash/configuration/validator/proxy.rb b/lib/dash/configuration/validator/proxy.rb index a30c8db5..7adfacab 100644 --- a/lib/dash/configuration/validator/proxy.rb +++ b/lib/dash/configuration/validator/proxy.rb @@ -8,7 +8,7 @@ def validate! # provides the hostnames at runtime. # On-demand TLS joins loadbalancer and ssl_domains as a source of hostnames # that only exist at handshake time - demanding a static host here would - # reject the one shape kamal-proxy requires for it. + # reject the one shape dash-proxy requires for it. if config["host"].blank? && config["hosts"].blank? && config["ssl"] && config["loadbalancer"].blank? && config.dig("ssl_domains", "source").blank? && ssl_config["on_demand_url"].blank? error "Must set a host to enable automatic SSL" @@ -113,7 +113,7 @@ def validate_ssl_domains!(ssl_domains) end end - # Same source shape as ssl_domains. The interval minimum is kamal-proxy's + # Same source shape as ssl_domains. The interval minimum is dash-proxy's # own (MinRedirectsInterval, 10s) - it rejects a smaller one after the SSH # round trip, so catch it here at config time. def validate_redirects_source!(redirects_source) @@ -132,7 +132,7 @@ def validate_redirects_source!(redirects_source) end end - # kamal-proxy only logs a warning for a DNS provider it does not recognise + # dash-proxy only logs a warning for a DNS provider it does not recognise # and then carries on with no provider at all, so the symptom is a # certificate that never issues rather than a failed boot. Catch it here, # before any host is contacted. @@ -185,7 +185,7 @@ def supported_dns_provider?(provider) end # The whole TLS surface lives in the one `ssl` hash: certificate material, - # on-demand issuance and the mTLS client CA. kamal-proxy rejects the + # on-demand issuance and the mTLS client CA. dash-proxy rejects the # on-demand combinations outright rather than picking a winner # (ServiceOptions.Validate), so there is no precedence to document - only # a deploy that would fail after the SSH round-trip. Fail here. @@ -231,13 +231,13 @@ def ssl_config # An RFC 9110 token, which is both a valid header field name and a valid # cookie name. For a header, a space or a colon would also break the - # ': ' encoding kamal-proxy cuts at the first colon. + # ': ' encoding dash-proxy cuts at the first colon. TOKEN = /\A[!#$%&'*+\-.^_`|~0-9A-Za-z]+\z/ POOL_KEYS = %w[ max_conns max_idle_conns idle_conn_timeout dial_timeout try_duration try_interval ].freeze # A zero is meaningful for most of these, so only negatives are refused. - # kamal-proxy clamps them rather than failing when it reads saved state, and + # dash-proxy clamps them rather than failing when it reads saved state, and # rejects them from a client — this is the client. def validate_tuning! target = config["target"] || {} @@ -258,13 +258,13 @@ def validate_tuning! with_context("request_timeout") { error "cannot be negative" } end - # Sibling consistency: kamal-proxy clamps a negative --target-timeout as + # Sibling consistency: dash-proxy clamps a negative --target-timeout as # silently as a negative --request-timeout. if config["response_timeout"].to_f.negative? with_context("response_timeout") { error "cannot be negative" } end - # Both maps reach kamal-proxy's one parsePathTimeouts, which refuses a + # Both maps reach dash-proxy's one parsePathTimeouts, which refuses a # negative duration. %w[ path_response_timeouts path_request_timeouts ].each do |key| with_context(key) do @@ -312,7 +312,7 @@ def validate_lifecycle! end end - # kamal-proxy rejects canonical_host + on-demand TLS after the SSH round + # dash-proxy rejects canonical_host + on-demand TLS after the SSH round # trip (canonical redirection needs a fixed host, on-demand TLS has none), # and a canonical host outside the host list redirects every request to a # hostname this service does not serve. @@ -393,7 +393,7 @@ def validate_header_rule!(direction, name, value) end # Go carries the request host in Request.Host rather than the header map, - # so kamal-proxy refuses the rule instead of silently doing nothing. + # so dash-proxy refuses the rule instead of silently doing nothing. if direction == "request" && name.to_s.downcase == "host" return error "cannot rewrite the Host header" end @@ -408,7 +408,7 @@ def validate_header_rule!(direction, name, value) # The pattern is deliberately not compiled: Go's RE2 and Ruby's Onigmo differ # at the edges (Ruby rejects Go's `(?P...)`), and refusing a pattern - # kamal-proxy would have accepted is worse than finding out at deploy time. + # dash-proxy would have accepted is worse than finding out at deploy time. def validate_path_rules!(key, redirect:) Array(config[key]).each_with_index do |rule, index| with_context(key) do @@ -419,7 +419,7 @@ def validate_path_rules!(key, redirect:) next error "needs both from and to" end - # The wire format is '=' and kamal-proxy cuts at the + # The wire format is '=' and dash-proxy cuts at the # FIRST '=', so an '=' inside the pattern silently builds a rule # for a different path. if rule["from"].to_s.include?("=") @@ -443,7 +443,7 @@ def validate_path_rules!(key, redirect:) end end - # kamal-proxy's --rate-limit is a Float64, so half a request per second is a + # dash-proxy's --rate-limit is a Float64, so half a request per second is a # legal rate. The docs example can only demonstrate one numeric type, and an # Integer there would reject 0.5 — so the shape is checked by hand instead. def validate_key_override!(key, value) @@ -488,7 +488,7 @@ def validate_key_override!(key, value) end # Rate limiting and the IP allow list are only as correct as the address they - # key on, so kamal-proxy ties the three settings together with rules that + # key on, so dash-proxy ties the three settings together with rules that # otherwise surface only once the deploy has reached a host. def validate_access_control! allow_ips = Array(config["allow_ips"]) @@ -531,7 +531,7 @@ def validate_access_control! error "trusted_proxies has no effect without allow_ips, deny_ips or rate_limit" end - # Unconditional: even without allow_ips/rate_limit, kamal-proxy rewrites + # Unconditional: even without allow_ips/rate_limit, dash-proxy rewrites # the client address (and X-Forwarded-For) from this header, so honoring # it from untrusted peers is a client-spoofable identity. if client_ip["header"].present? && trusted_proxies.empty? @@ -549,7 +549,7 @@ def validate_access_control! end end - # kamal-proxy serves the health check path without an address check and + # dash-proxy serves the health check path without an address check and # without a rate limit so deploys keep working, which makes '/' a hole # straight through all three features. if (allow_ips.any? || deny_ips.any? || rate_limited) && config.dig("healthcheck", "path") == "/" @@ -618,7 +618,7 @@ def validate_compress!(compress) Array(compress["content_types"]).each do |content_type| # A main-type wildcard would match everything the proxy cannot see - # inside, so kamal-proxy allows a wildcard only in the subtype. + # inside, so dash-proxy allows a wildcard only in the subtype. unless content_type.to_s.match?(%r{\A[^/*\s]+/[^/\s]+\z}) error "content_types entry '#{content_type}' must be a media type such as text/html or text/*" end @@ -632,7 +632,7 @@ def validate_compress!(compress) REFUSED_TLS_VERSIONS = %w[ 1.0 1.1 ].freeze RUN_TIMEOUTS = %w[ read_header_timeout read_timeout write_timeout idle_timeout shutdown_timeout ].freeze - # kamal-proxy validates these three in preRun, so a typo does not fail the + # dash-proxy validates these three in preRun, so a typo does not fail the # deploy - it stops the proxy container from booting at all. def validate_run_server_options!(run_config) with_context("run") do @@ -656,7 +656,7 @@ def validate_run_server_options!(run_config) end end - # Accepts the spellings kamal-proxy's normalizeTLSVersion reduces - a `tls` + # Accepts the spellings dash-proxy's normalizeTLSVersion reduces - a `tls` # or `tlsv` prefix, and `_` for `.` - so a config written for upstream is not # rejected here and accepted there. def validate_min_tls!(value) @@ -673,7 +673,7 @@ def validate_min_tls!(value) end end - # kamal-proxy reads the cache policy only when --cache is set and ignores it + # dash-proxy reads the cache policy only when --cache is set and ignores it # otherwise, so a tuned block with no `enabled` is a cache that silently # never caches - this issue's own predicted first support question. def validate_cache!(cache) @@ -682,12 +682,12 @@ def validate_cache!(cache) with_context("cache") do if (orphaned = cache.keys - [ "enabled" ]).any? error "#{orphaned.first} has no effect without enabled: true - " \ - "kamal-proxy ignores the cache policy entirely when --cache is absent" + "dash-proxy ignores the cache policy entirely when --cache is absent" end end end - # An unsupported store is rejected in kamal-proxy's preRun, which means the + # An unsupported store is rejected in dash-proxy's preRun, which means the # proxy container exits at boot rather than a deploy failing. Catch it before # the fleet loses its proxy. def validate_cache_store!(cache) @@ -708,7 +708,7 @@ def validate_basic_auth!(basic_auth) if basic_auth["username"].blank? error "Missing username setting (required when basic_auth is set)" elsif basic_auth["username"].to_s.include?(":") - # kamal-proxy cuts : at the first colon, so a + # dash-proxy cuts : at the first colon, so a # colon in the username would silently truncate it. error "Invalid username: cannot contain a colon" end diff --git a/lib/dash/utils.rb b/lib/dash/utils.rb index d579eee9..8ac62bee 100644 --- a/lib/dash/utils.rb +++ b/lib/dash/utils.rb @@ -45,7 +45,7 @@ def optionize(args, with: nil, escape: true) options.flatten.compact end - # kamal-proxy takes durations as Go duration strings; deploy.yml takes plain + # dash-proxy takes durations as Go duration strings; deploy.yml takes plain # seconds. Zero is a real value (it disables the timeout), so only nil drops out. # # A value that already carries a unit is passed through untouched. Appending diff --git a/test/cli/accessory_test.rb b/test/cli/accessory_test.rb index f24add37..1644c15e 100644 --- a/test/cli/accessory_test.rb +++ b/test/cli/accessory_test.rb @@ -15,7 +15,7 @@ class CliAccessoryTest < CliTestCase run_command("boot", "mysql").tap do |output| assert_match "docker login private.registry -u [REDACTED] -p [REDACTED] on 1.1.1.3", output - assert_match "docker run --name app-mysql --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output + assert_match "docker run --name app-mysql --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output end end @@ -32,13 +32,13 @@ class CliAccessoryTest < CliTestCase assert_match "docker login private.registry -u [REDACTED] -p [REDACTED] on 1.1.1.1", output assert_match "docker login private.registry -u [REDACTED] -p [REDACTED] on 1.1.1.2", output assert_match "docker login other.registry -u [REDACTED] -p [REDACTED] on 1.1.1.3", output - assert_match /docker network create kamal.*on 1.1.1.1/, output - assert_match /docker network create kamal.*on 1.1.1.2/, output - assert_match /docker network create kamal.*on 1.1.1.3/, output - assert_match "docker run --name app-mysql --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output - assert_match "docker run --name app-redis --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output - assert_match "docker run --name app-redis --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.2\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.2", output - assert_match "docker run --name custom-box --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env-file .dash/apps/app/env/accessories/busybox.env --label service=\"custom-box\" other.registry/busybox:latest on 1.1.1.3", output + assert_match /docker network create dash.*on 1.1.1.1/, output + assert_match /docker network create dash.*on 1.1.1.2/, output + assert_match /docker network create dash.*on 1.1.1.3/, output + assert_match "docker run --name app-mysql --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output + assert_match "docker run --name app-redis --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output + assert_match "docker run --name app-redis --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.2\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.2", output + assert_match "docker run --name custom-box --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env-file .dash/apps/app/env/accessories/busybox.env --label service=\"custom-box\" other.registry/busybox:latest on 1.1.1.3", output end end @@ -223,7 +223,7 @@ class CliAccessoryTest < CliTestCase run_command("boot", "redis", "--hosts", "1.1.1.1").tap do |output| assert_match "docker login private.registry -u [REDACTED] -p [REDACTED] on 1.1.1.1", output assert_no_match "docker login private.registry -u [REDACTED] -p [REDACTED] on 1.1.1.2", output - assert_match "docker run --name app-redis --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output + assert_match "docker run --name app-redis --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output assert_no_match /docker run --name app-redis .* on 1.1.1.2/, output end end @@ -235,7 +235,7 @@ class CliAccessoryTest < CliTestCase run_command("boot", "redis", "--hosts", "1.1.1.1,1.1.1.3").tap do |output| assert_match "docker login private.registry -u [REDACTED] -p [REDACTED] on 1.1.1.1", output assert_no_match "docker login private.registry -u [REDACTED] -p [REDACTED] on 1.1.1.3", output - assert_match "docker run --name app-redis --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output + assert_match "docker run --name app-redis --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output assert_no_match /docker run --name app-redis .* on 1.1.1.3/, output end end @@ -243,9 +243,9 @@ class CliAccessoryTest < CliTestCase test "upgrade" do run_command("upgrade", "-y", "all").tap do |output| assert_match "Upgrading all accessories on 1.1.1.3,1.1.1.1,1.1.1.2...", output - assert_match "docker network create kamal on 1.1.1.3", output + assert_match "docker network create dash on 1.1.1.3", output assert_match "docker container stop app-mysql on 1.1.1.3", output - assert_match "docker run --name app-mysql --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST="%" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output + assert_match "docker run --name app-mysql --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST="%" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output assert_match "Upgraded all accessories on 1.1.1.3,1.1.1.1,1.1.1.2...", output end end @@ -253,17 +253,17 @@ class CliAccessoryTest < CliTestCase test "upgrade rolling" do run_command("upgrade", "--rolling", "-y", "all").tap do |output| assert_match "Upgrading all accessories on 1.1.1.3...", output - assert_match "docker network create kamal on 1.1.1.3", output + assert_match "docker network create dash on 1.1.1.3", output assert_match "docker container stop app-mysql on 1.1.1.3", output - assert_match "docker run --name app-mysql --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST="%" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output + assert_match "docker run --name app-mysql --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 3306:3306 --env DASH_HOST=\"1.1.1.3\" --env KAMAL_HOST=\"1.1.1.3\" --env MYSQL_ROOT_HOST="%" --env-file .dash/apps/app/env/accessories/mysql.env --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" private.registry/mysql:5.7 on 1.1.1.3", output assert_match "Upgraded all accessories on 1.1.1.3", output end end test "boot with web role filter" do run_command("boot", "redis", "-r", "web").tap do |output| - assert_match "docker run --name app-redis --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output - assert_match "docker run --name app-redis --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.2\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.2", output + assert_match "docker run --name app-redis --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.1\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output + assert_match "docker run --name app-redis --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 6379:6379 --env DASH_HOST=\"1.1.1.2\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/accessories/redis.env --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.2", output end end diff --git a/test/cli/app_test.rb b/test/cli/app_test.rb index 128ac4e3..ee0d2a44 100644 --- a/test/cli/app_test.rb +++ b/test/cli/app_test.rb @@ -5,7 +5,7 @@ class CliAppTest < CliTestCase stub_running run_command("boot").tap do |output| assert_match "docker tag dhh/app:latest dhh/app:latest", output - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} /, output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-[0-9a-f]{12} /, output assert_match "docker container ls --all --filter 'name=^app-web-123$' --quiet | xargs docker stop", output end end @@ -29,7 +29,7 @@ class CliAppTest < CliTestCase run_command("boot").tap do |output| assert_match /Renaming container .* to .* as already deployed on 1.1.1.1/, output # Rename assert_match /docker rename app-web-latest app-web-latest_replaced_[0-9a-f]{16}/, output - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} /, output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-[0-9a-f]{12} /, output assert_match "docker container ls --all --filter 'name=^app-web-123$' --quiet | xargs docker stop", output end ensure @@ -157,7 +157,7 @@ class CliAppTest < CliTestCase assert_match "docker tag dhh/app:latest dhh/app:latest", output assert_match "/usr/bin/env mkdir -p .dash/apps/app/assets/volumes/web-latest ; cp -rnT .dash/apps/app/assets/extracted/web-latest .dash/apps/app/assets/volumes/web-latest ; cp -rnT .dash/apps/app/assets/extracted/web-latest .dash/apps/app/assets/volumes/web-123 || true ; cp -rnT .dash/apps/app/assets/extracted/web-123 .dash/apps/app/assets/volumes/web-latest || true", output assert_match "/usr/bin/env mkdir -p .dash/apps/app/assets/extracted/web-latest && docker container rm app-web-assets 2> /dev/null || true && docker container create --name app-web-assets dhh/app:latest && docker container cp -L app-web-assets:/public/assets/. .dash/apps/app/assets/extracted/web-latest && docker container rm app-web-assets", output - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} /, output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-[0-9a-f]{12} /, output assert_match "docker container ls --all --filter 'name=^app-web-123$' --quiet | xargs docker stop", output assert_match "/usr/bin/env find .dash/apps/app/assets/extracted -maxdepth 1 -name 'web-*' ! -name web-latest -exec rm -rf \"{}\" + ; find .dash/apps/app/assets/volumes -maxdepth 1 -name 'web-*' ! -name web-latest -exec rm -rf \"{}\" +", output end @@ -180,7 +180,7 @@ class CliAppTest < CliTestCase run_command("boot", config: :with_env_tags).tap do |output| assert_match "docker tag dhh/app:latest dhh/app:latest", output - assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} --env KAMAL_CONTAINER_NAME="app-web-latest" --env KAMAL_VERSION="latest" --env KAMAL_HOST="1.1.1.1" --env TEST="root" --env EXPERIMENT="disabled" --env SITE="site1"}, output + assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-[0-9a-f]{12} --env KAMAL_CONTAINER_NAME="app-web-latest" --env KAMAL_VERSION="latest" --env KAMAL_HOST="1.1.1.1" --env TEST="root" --env EXPERIMENT="disabled" --env SITE="site1"}, output assert_match "docker container ls --all --filter 'name=^app-web-123$' --quiet | xargs docker stop", output end end @@ -240,7 +240,7 @@ class CliAppTest < CliTestCase SSHKit::Backend::Abstract.any_instance.stubs(:execute) .with(:docker, :container, :ls, "--all", "--filter", "'name=^app-web-latest$'", "--quiet", "|", :xargs, :docker, :stop, raise_on_non_zero_exit: false) SSHKit::Backend::Abstract.any_instance.expects(:execute) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :deploy, "app-web", "--target=\"123:80\"", "--deploy-timeout=\"1s\"", "--drain-timeout=\"30s\"", "--buffer-requests", "--buffer-responses", "--log-request-header=\"Cache-Control\"", "--log-request-header=\"Last-Modified\"", "--log-request-header=\"User-Agent\"").raises(SSHKit::Command::Failed.new("Failed to deploy")) + .with(:docker, :exec, "dash-proxy", "dash-proxy", :deploy, "app-web", "--target=\"123:80\"", "--deploy-timeout=\"1s\"", "--drain-timeout=\"30s\"", "--buffer-requests", "--buffer-responses", "--log-request-header=\"Cache-Control\"", "--log-request-header=\"Last-Modified\"", "--log-request-header=\"User-Agent\"").raises(SSHKit::Command::Failed.new("Failed to deploy")) stderred do run_command("boot", config: :with_roles, host: nil, allow_execute_error: true).tap do |output| @@ -366,7 +366,7 @@ class CliAppTest < CliTestCase run_command("boot", config: :with_only_workers, host: nil).tap do |output| assert_match /First workers container is healthy on 1.1.1.\d, booting any other roles/, output - assert_no_match "kamal-proxy", output + assert_no_match "dash-proxy", output end end @@ -376,7 +376,7 @@ class CliAppTest < CliTestCase run_command("boot", config: :with_error_pages).tap do |output| assert_match /Uploading .*kamal-error-pages.*\/latest to \.dash\/proxy\/apps-config\/app\/error_pages/, output assert_match "docker tag dhh/app:latest dhh/app:latest", output - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} /, output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-[0-9a-f]{12} /, output assert_match "docker container ls --all --filter 'name=^app-web-123$' --quiet | xargs docker stop", output assert_match "Running /usr/bin/env find .dash/proxy/apps-config/app/error_pages -mindepth 1 -maxdepth 1 ! -name latest -exec rm -rf {} + on 1.1.1.1", output end @@ -393,8 +393,8 @@ class CliAppTest < CliTestCase assert_match "Writing SSL certificates for web on 1.1.1.1", output assert_match "mkdir -p .dash/proxy/apps-config/app/tls", output assert_match "Uploading \"CERTIFICATE CONTENT\" to .dash/proxy/apps-config/app/tls/web/cert.pem", output - assert_match "--tls-certificate-path=\"/home/kamal-proxy/.apps-config/app/tls/web/cert.pem\"", output - assert_match "--tls-private-key-path=\"/home/kamal-proxy/.apps-config/app/tls/web/key.pem\"", output + assert_match "--tls-certificate-path=\"/home/dash-proxy/.apps-config/app/tls/web/cert.pem\"", output + assert_match "--tls-private-key-path=\"/home/dash-proxy/.apps-config/app/tls/web/key.pem\"", output end end @@ -410,7 +410,7 @@ class CliAppTest < CliTestCase assert_match "Writing SSL certificates for web on 1.1.1.1", output assert_match "mkdir -p .dash/proxy/apps-config/app/tls", output assert_match "Uploading \"ca-bundle-content\" to .dash/proxy/apps-config/app/tls/web/client-ca.pem", output - assert_match "--tls-client-ca-path=\"/home/kamal-proxy/.apps-config/app/tls/web/client-ca.pem\"", output + assert_match "--tls-client-ca-path=\"/home/dash-proxy/.apps-config/app/tls/web/client-ca.pem\"", output end end @@ -419,7 +419,7 @@ class CliAppTest < CliTestCase run_command("start").tap do |output| assert_match "docker start app-web-999", output - assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"999:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\"", output + assert_match "docker exec dash-proxy dash-proxy deploy app-web --target=\"999:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\"", output end end @@ -524,7 +524,7 @@ class CliAppTest < CliTestCase test "exec" do run_command("exec", "ruby -v").tap do |output| assert_match "docker login -u [REDACTED] -p [REDACTED]", output - assert_match %r{docker run --rm --name app-web-exec-latest-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v}, output + assert_match %r{docker run --rm --name app-web-exec-latest-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v}, output end end @@ -537,13 +537,13 @@ class CliAppTest < CliTestCase test "exec separate arguments" do run_command("exec", "ruby", " -v").tap do |output| - assert_match %r{docker run --rm --name app-web-exec-latest-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v}, output + assert_match %r{docker run --rm --name app-web-exec-latest-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v}, output end end test "exec detach" do run_command("exec", "--detach", "ruby -v").tap do |output| - assert_match %r{docker run --detach --name app-web-exec-latest-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v}, output + assert_match %r{docker run --detach --name app-web-exec-latest-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v}, output end end @@ -575,7 +575,7 @@ class CliAppTest < CliTestCase test "exec interactive" do Dash::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true) SSHKit::Backend::Abstract.any_instance.expects(:exec) - .with(regexp_matches(%r{ssh -t root@1\.1\.1\.1 -p 22 'docker run -it --rm --name app-web-exec-latest-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v'})) + .with(regexp_matches(%r{ssh -t root@1\.1\.1\.1 -p 22 'docker run -it --rm --name app-web-exec-latest-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:latest ruby -v'})) stub_stdin_tty do run_command("exec", "-i", "ruby -v").tap do |output| @@ -687,7 +687,7 @@ class CliAppTest < CliTestCase hostname = "this-hostname-is-really-unacceptably-long-to-be-honest.example.com" stdouted { Dash::Cli::App.start([ "boot", "-c", "test/fixtures/deploy_with_uncommon_hostnames.yml", "--hosts", hostname ]) }.tap do |output| - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname this-hostname-is-really-unacceptably-long-to-be-hon-[0-9a-f]{12} /, output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname this-hostname-is-really-unacceptably-long-to-be-hon-[0-9a-f]{12} /, output end end @@ -697,7 +697,7 @@ class CliAppTest < CliTestCase hostname = "this-hostname-with-random-part-is-too-long.example.com" stdouted { Dash::Cli::App.start([ "boot", "-c", "test/fixtures/deploy_with_uncommon_hostnames.yml", "--hosts", hostname ]) }.tap do |output| - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname this-hostname-with-random-part-is-too-long.example-[0-9a-f]{12} /, output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname this-hostname-with-random-part-is-too-long.example-[0-9a-f]{12} /, output end end @@ -707,9 +707,9 @@ class CliAppTest < CliTestCase run_command("boot", config: :with_proxy).tap do |output| assert_match /Renaming container .* to .* as already deployed on 1.1.1.1/, output # Rename assert_match /docker rename app-web-latest app-web-latest_replaced_[0-9a-f]{16}/, output - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} --env KAMAL_CONTAINER_NAME="app-web-latest" --env KAMAL_VERSION="latest" --env KAMAL_HOST="1.1.1.1" --env-file .dash\/apps\/app\/env\/roles\/web.env --log-opt max-size="10m" --label service="app" --label role="web" --label destination dhh\/app:latest/, output - assert_match /Deploying web on 1.1.1.1 via kamal-proxy \(waiting up to 6s for it to become healthy\).../, output - assert_match /docker exec kamal-proxy kamal-proxy deploy app-web --target="123:80"/, output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-[0-9a-f]{12} --env KAMAL_CONTAINER_NAME="app-web-latest" --env KAMAL_VERSION="latest" --env KAMAL_HOST="1.1.1.1" --env-file .dash\/apps\/app\/env\/roles\/web.env --log-opt max-size="10m" --label service="app" --label role="web" --label destination dhh\/app:latest/, output + assert_match /Deploying web on 1.1.1.1 via dash-proxy \(waiting up to 6s for it to become healthy\).../, output + assert_match /docker exec dash-proxy dash-proxy deploy app-web --target="123:80"/, output assert_match "docker container ls --all --filter 'name=^app-web-123$' --quiet | xargs docker stop", output end end @@ -718,8 +718,8 @@ class CliAppTest < CliTestCase SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("123") # old version run_command("boot", config: :with_proxy_roles, host: nil).tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"123:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --target-timeout=\"10s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output - assert_match "docker exec kamal-proxy kamal-proxy deploy app-web2 --target=\"123:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --target-timeout=\"15s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output + assert_match "docker exec dash-proxy dash-proxy deploy app-web --target=\"123:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --target-timeout=\"10s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output + assert_match "docker exec dash-proxy dash-proxy deploy app-web2 --target=\"123:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --target-timeout=\"15s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output end end @@ -730,7 +730,7 @@ class CliAppTest < CliTestCase run_command("boot", config: :with_proxy).tap do |output| assert_hook_ran "pre-proxy-deploy", output assert_hook_ran "post-proxy-deploy", output - assert_match /pre-proxy-deploy.*kamal-proxy deploy app-web.*post-proxy-deploy/m, output + assert_match /pre-proxy-deploy.*dash-proxy deploy app-web.*post-proxy-deploy/m, output end end @@ -761,7 +761,7 @@ class CliAppTest < CliTestCase SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("123") # old version run_command("boot", "--skip-hooks", config: :with_proxy).tap do |output| - assert_match /kamal-proxy deploy app-web/, output + assert_match /dash-proxy deploy app-web/, output assert_no_match /hooks\/pre-proxy-deploy/, output assert_no_match /hooks\/post-proxy-deploy/, output end @@ -773,7 +773,7 @@ class CliAppTest < CliTestCase stderred { run_command("boot", config: :with_proxy, allow_execute_error: true) } - assert @executions.none? { |args| args.join(" ").include?("kamal-proxy deploy") } + assert @executions.none? { |args| args.join(" ").include?("dash-proxy deploy") } assert @executions.any? { |args| args.join(" ").include?("app-web-latest") && args.join(" ").include?("docker stop") } end @@ -814,7 +814,7 @@ class CliAppTest < CliTestCase SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("123") # old version run_command("boot", config: :with_proxy).tap do |output| - assert_match /kamal-proxy deploy app-web.*pre-app-stop/m, output + assert_match /dash-proxy deploy app-web.*pre-app-stop/m, output end end @@ -886,25 +886,25 @@ class CliAppTest < CliTestCase SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("999") # old version run_command("start").tap do |output| - assert_match /pre-proxy-deploy.*kamal-proxy deploy app-web.*post-proxy-deploy/m, output + assert_match /pre-proxy-deploy.*dash-proxy deploy app-web.*post-proxy-deploy/m, output end end test "live" do run_command("live").tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy resume app-web on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy resume app-web on 1.1.1.1", output end end test "maintenance" do run_command("maintenance").tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy stop app-web --drain-timeout=\"30s\" on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy stop app-web --drain-timeout=\"30s\" on 1.1.1.1", output end end test "maintenance with options" do run_command("maintenance", "--message", "Hello", "--drain_timeout", "10").tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy stop app-web --drain-timeout=\"10s\" --message=\"Hello\" on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy stop app-web --drain-timeout=\"10s\" --message=\"Hello\" on 1.1.1.1", output end end @@ -913,8 +913,8 @@ class CliAppTest < CliTestCase stub_rollout_target_not_deployed run_command("rollout", "deploy").tap do |output| - assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} /, output - assert_match "docker exec kamal-proxy kamal-proxy rollout deploy app-web --target=\"12345678:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\"", output + assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-[0-9a-f]{12} /, output + assert_match "docker exec dash-proxy dash-proxy rollout deploy app-web --target=\"12345678:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\"", output end end @@ -923,7 +923,7 @@ class CliAppTest < CliTestCase stub_rollout_target_not_deployed run_command("rollout", "deploy").tap do |output| - assert_no_match /kamal-proxy deploy app-web/, output + assert_no_match /dash-proxy deploy app-web/, output assert_no_match /xargs docker stop/, output end end @@ -936,25 +936,25 @@ class CliAppTest < CliTestCase run_command("rollout", "deploy", allow_execute_error: true).tap do |output| assert_match /Version latest is already deployed/, output - assert_no_match /kamal-proxy rollout deploy/, output + assert_no_match /dash-proxy rollout deploy/, output end end test "rollout set with percent" do run_command("rollout", "set", "--percent", "10").tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy rollout set app-web --percent=\"10\" on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy rollout set app-web --percent=\"10\" on 1.1.1.1", output end end test "rollout set with list" do run_command("rollout", "set", "--list", "dhh", "jorge").tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy rollout set app-web --list=\"dhh\" --list=\"jorge\" on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy rollout set app-web --list=\"dhh\" --list=\"jorge\" on 1.1.1.1", output end end test "rollout set with percent zero parks the rollout without tearing it down" do run_command("rollout", "set", "--percent", "0").tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy rollout set app-web --percent=\"0\" on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy rollout set app-web --percent=\"0\" on 1.1.1.1", output end end @@ -964,7 +964,7 @@ class CliAppTest < CliTestCase test "rollout stop" do run_command("rollout", "stop").tap do |output| - assert_match "docker exec kamal-proxy kamal-proxy rollout stop app-web on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy rollout stop app-web on 1.1.1.1", output end end diff --git a/test/cli/doctor_test.rb b/test/cli/doctor_test.rb index 5bedd91e..8f5f7f3d 100644 --- a/test/cli/doctor_test.rb +++ b/test/cli/doctor_test.rb @@ -1,7 +1,7 @@ require_relative "cli_test_case" class CliDoctorTest < CliTestCase - PROXY_VERSION_CAPTURE_ARGS = [ :docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'" ] + PROXY_VERSION_CAPTURE_ARGS = [ :docker, :inspect, "dash-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'" ] setup do Thread.report_on_exception = false @@ -38,7 +38,7 @@ class CliDoctorTest < CliTestCase run_command("doctor").tap do |output| assert_match "OK 1.1.1.1: #{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} (minimum #{Dash::Configuration::Proxy::Run::MINIMUM_VERSION})", output - assert_match "OK 1.1.1.1: ports 80/443 held by the running kamal-proxy", output + assert_match "OK 1.1.1.1: ports 80/443 held by the running dash-proxy", output end end @@ -152,7 +152,7 @@ class CliDoctorTest < CliTestCase # service never wakes. The doctor inspects what is actually mounted. test "doctor reports a mounted docker socket" do stub_proxy_version Dash::Configuration::Proxy::Run::MINIMUM_VERSION - stub_proxy_mounts "/home/kamal-proxy/.config/kamal-proxy\n/var/run/docker.sock" + stub_proxy_mounts "/home/dash-proxy/.config/dash-proxy\n/var/run/docker.sock" stub_domain_resolution to: [ "1.1.1.1" ] stub_served_certificate expiring: Time.now + (90 * 86_400) @@ -163,7 +163,7 @@ class CliDoctorTest < CliTestCase test "doctor fails when sleep is configured but the running proxy lacks the socket mount" do stub_proxy_version Dash::Configuration::Proxy::Run::MINIMUM_VERSION - stub_proxy_mounts "/home/kamal-proxy/.config/kamal-proxy" + stub_proxy_mounts "/home/dash-proxy/.config/dash-proxy" stub_domain_resolution to: [ "1.1.1.1" ] stub_served_certificate expiring: Time.now + (90 * 86_400) @@ -175,12 +175,12 @@ class CliDoctorTest < CliTestCase # Without sleep nothing hangs yet, so a missing mount is drift, not breakage. test "doctor warns when the socket is configured without sleep and not mounted" do stub_proxy_version Dash::Configuration::Proxy::Run::MINIMUM_VERSION - stub_proxy_mounts "/home/kamal-proxy/.config/kamal-proxy" + stub_proxy_mounts "/home/dash-proxy/.config/dash-proxy" stub_domain_resolution to: [ "1.1.1.1" ] stub_served_certificate expiring: Time.now + (90 * 86_400) run_command("doctor", fixture: "deploy_with_doctor_socket_only").tap do |output| - assert_match "WARN 1.1.1.1: the running kamal-proxy has no /var/run/docker.sock mount", output + assert_match "WARN 1.1.1.1: the running dash-proxy has no /var/run/docker.sock mount", output assert_match "ready to deploy", output end end @@ -188,12 +188,12 @@ class CliDoctorTest < CliTestCase # Root-equivalent access the config no longer asks for deserves a flag. test "doctor warns about a mounted socket the config no longer asks for" do stub_proxy_version Dash::Configuration::Proxy::Run::MINIMUM_VERSION - stub_proxy_mounts "/home/kamal-proxy/.config/kamal-proxy\n/var/run/docker.sock" + stub_proxy_mounts "/home/dash-proxy/.config/dash-proxy\n/var/run/docker.sock" stub_domain_resolution to: [ "1.1.1.1" ] stub_served_certificate expiring: Time.now + (90 * 86_400) run_command("doctor").tap do |output| - assert_match "WARN 1.1.1.1: the running kamal-proxy mounts /var/run/docker.sock but the config no longer asks for it", output + assert_match "WARN 1.1.1.1: the running dash-proxy mounts /var/run/docker.sock but the config no longer asks for it", output assert_match "ready to deploy", output end end @@ -213,7 +213,7 @@ class CliDoctorTest < CliTestCase test "doctor stays quiet about sockets when none is configured or mounted" do stub_proxy_version Dash::Configuration::Proxy::Run::MINIMUM_VERSION - stub_proxy_mounts "/home/kamal-proxy/.config/kamal-proxy" + stub_proxy_mounts "/home/dash-proxy/.config/dash-proxy" stub_domain_resolution to: [ "1.1.1.1" ] stub_served_certificate expiring: Time.now + (90 * 86_400) @@ -243,7 +243,7 @@ class CliDoctorTest < CliTestCase test "doctor reports the readiness source of every role" do run_command("doctor", fixture: "deploy_with_readiness_sources").tap do |output| assert_match "Readiness", output - assert_match "OK web: kamal-proxy health check /healthz", output + assert_match "OK web: dash-proxy health check /healthz", output assert_match "OK pulse: docker healthcheck (options: health-cmd)", output assert_match "OK listener: healthcheck /readyz:7434", output assert_match "OK ticker: healthcheck (custom cmd)", output @@ -300,7 +300,7 @@ def stub_proxy_version(version) def stub_proxy_mounts(destinations) SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format", "'{{range .Mounts}}{{println .Destination}}{{end}}'", raise_on_non_zero_exit: false) + .with(:docker, :inspect, "dash-proxy", "--format", "'{{range .Mounts}}{{println .Destination}}{{end}}'", raise_on_non_zero_exit: false) .returns(destinations) end diff --git a/test/cli/main_test.rb b/test/cli/main_test.rb index ad2dd12f..1f4dea11 100644 --- a/test/cli/main_test.rb +++ b/test/cli/main_test.rb @@ -32,7 +32,7 @@ class CliMainTest < CliTestCase # deploy assert_match /Acquiring the deploy lock/, output assert_match /Pull app image/, output - assert_match /Ensure kamal-proxy is running/, output + assert_match /Ensure dash-proxy is running/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output assert_match /Releasing the deploy lock/, output @@ -55,7 +55,7 @@ class CliMainTest < CliTestCase assert_hook_ran "pre-connect", output assert_match /Build and push app image/, output assert_hook_ran "pre-deploy", output - assert_match /Ensure kamal-proxy is running/, output + assert_match /Ensure dash-proxy is running/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output assert_hook_ran "post-deploy", output @@ -79,7 +79,7 @@ class CliMainTest < CliTestCase assert_match /Ensure Docker is installed.../, output # deploy assert_match /Build and push app image/, output - assert_match /Ensure kamal-proxy is running/, output + assert_match /Ensure dash-proxy is running/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output end @@ -101,7 +101,7 @@ class CliMainTest < CliTestCase assert_hook_ran "pre-connect", output assert_match /Build and push app image/, output assert_hook_ran "pre-deploy", output - assert_match /Ensure kamal-proxy is running/, output + assert_match /Ensure dash-proxy is running/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output assert_hook_ran "post-deploy", output @@ -121,7 +121,7 @@ class CliMainTest < CliTestCase run_command("deploy", "--skip_push").tap do |output| assert_match /Acquiring the deploy lock/, output assert_match /Pull app image/, output - assert_match /Ensure kamal-proxy is running/, output + assert_match /Ensure dash-proxy is running/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output assert_match /Releasing the deploy lock/, output @@ -139,7 +139,7 @@ class CliMainTest < CliTestCase run_command("deploy", "--no-cache").tap do |output| assert_match /Build and push app image/, output - assert_match /Ensure kamal-proxy is running/, output + assert_match /Ensure dash-proxy is running/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output end @@ -309,7 +309,7 @@ class CliMainTest < CliTestCase run_command("deploy").tap do |output| assert_no_match /Acquiring the deploy lock/, output assert_match /Build and push app image/, output - assert_match /Ensure kamal-proxy is running/, output + assert_match /Ensure dash-proxy is running/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output assert_no_match /Releasing the deploy lock/, output @@ -828,9 +828,9 @@ class CliMainTest < CliTestCase test "remove with confirmation" do run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output| - assert_match /docker container stop kamal-proxy/, output - assert_match /docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy/, output - assert_match /docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy/, output + assert_match /docker container stop dash-proxy/, output + assert_match /docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy/, output + assert_match /docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy/, output assert_match /docker ps --quiet --filter label=service=app | xargs docker stop/, output assert_match /docker container prune --force --filter label=service=app/, output @@ -1029,7 +1029,7 @@ class CliMainTest < CliTestCase Dash::Cli::Main.any_instance.expects(:invoke).at_least_once run_command("deploy", config_file: "deploy_with_readiness_sources").tap do |output| - assert_match /web: 1 host \(1\.1\.1\.1\) — readiness: kamal-proxy health check \/healthz/, output + assert_match /web: 1 host \(1\.1\.1\.1\) — readiness: dash-proxy health check \/healthz/, output assert_match /workers: 1 host \(1\.1\.1\.3\) — readiness: NONE \(old container stops 7s after boot\)/, output assert_match /pulse: 1 host \(1\.1\.1\.4\) — readiness: docker healthcheck \(options: health-cmd\)/, output assert_match /listener: 1 host \(1\.1\.1\.5\) — readiness: healthcheck \/readyz:7434/, output @@ -1043,7 +1043,7 @@ class CliMainTest < CliTestCase Dash::Cli::Main.any_instance.expects(:invoke).at_least_once run_command("deploy").tap do |output| - assert_match /web: 2 hosts \(1\.1\.1\.1, 1\.1\.1\.2\) — readiness: kamal-proxy health check$/, output + assert_match /web: 2 hosts \(1\.1\.1\.1, 1\.1\.1\.2\) — readiness: dash-proxy health check$/, output end end diff --git a/test/cli/proxy_test.rb b/test/cli/proxy_test.rb index b90d176b..55f54037 100644 --- a/test/cli/proxy_test.rb +++ b/test/cli/proxy_test.rb @@ -5,7 +5,7 @@ class CliProxyTest < CliTestCase run_command("boot").tap do |output| assert_match "docker login", output assert_match "mkdir -p .dash/proxy/apps-config", output - assert_match "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output + assert_match "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy", output end end @@ -39,8 +39,8 @@ class CliProxyTest < CliTestCase run_command("boot", fixture: :with_proxy_run_config).tap do |output| assert_match "docker login", output assert_match "mkdir -p .dash/proxy/apps-config", output - assert_match_with_digest "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9090 --cpus \"1.5\" registry:4443/ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --debug --metrics-port \"9090\" --recheck-targets-on-restore on 1.1.1.1", output - assert_match_with_digest "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9190 ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --metrics-port \"9190\" --recheck-targets-on-restore on 1.1.1.3", output + assert_match_with_digest "docker container start dash-proxy || docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9090 --cpus \"1.5\" registry:4443/ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --debug --metrics-port \"9090\" --recheck-targets-on-restore on 1.1.1.1", output + assert_match_with_digest "docker container start dash-proxy || docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9190 ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --metrics-port \"9190\" --recheck-targets-on-restore on 1.1.1.3", output end end @@ -114,14 +114,14 @@ class CliProxyTest < CliTestCase end end - # kamal-proxy list --json returns {"services": {"": ...}} - exact key + # dash-proxy list --json returns {"services": {"": ...}} - exact key # membership, where the old substring match over the human table could match # a service name inside another's ("app" in "other-app"). test "reboot fails when a re-registered service is missing from the JSON listing" do Object.any_instance.stubs(:sleep) SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :list, "--json") + .with(:docker, :exec, "dash-proxy", "dash-proxy", :list, "--json") .returns({ services: { "other-app" => {} } }.to_json) Dash::Cli::Proxy::Reboot.any_instance.stubs(:re_register_services).returns([ "app-web" ]) @@ -136,12 +136,12 @@ class CliProxyTest < CliTestCase Object.any_instance.stubs(:sleep) SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :list, "--json") + .with(:docker, :exec, "dash-proxy", "dash-proxy", :list, "--json") .returns({ services: { "app-web" => { "target" => "abc:80" } } }.to_json) Dash::Cli::Proxy::Reboot.any_instance.stubs(:re_register_services).returns([ "app-web" ]) run_command("reboot", "-y").tap do |output| - assert_match "Rebooting kamal-proxy on 1.1.1.1", output + assert_match "Rebooting dash-proxy on 1.1.1.1", output end end @@ -150,12 +150,12 @@ class CliProxyTest < CliTestCase stub_proxy_drift run_command("boot").tap do |output| - assert_match "kamal-proxy configuration changed, rebooting on 1.1.1.1", output - assert_match "kamal-proxy configuration changed, rebooting on 1.1.1.2", output + assert_match "dash-proxy configuration changed, rebooting on 1.1.1.1", output + assert_match "dash-proxy configuration changed, rebooting on 1.1.1.2", output %w[ 1.1.1.1 1.1.1.2 ].each do |host| assert_match "docker pull $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") on #{host}", output - assert_match "docker container stop --time 40 kamal-proxy on #{host}", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on #{host}", output + assert_match "docker container stop --time 40 dash-proxy on #{host}", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy && docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on #{host}", output assert_match "--label org.dash.proxy-config-digest=#{Dash::Configuration::Proxy::Run.digest("")}", output end end @@ -166,8 +166,8 @@ class CliProxyTest < CliTestCase run_command("boot", fixture: :with_proxy_reboot_disabled).tap do |output| assert_match "Automatic reboot is disabled (proxy: reboot_on_deploy: false) - run `dash proxy reboot` to apply the new configuration.", output - assert_match "docker container start kamal-proxy ||", output - assert_no_match(/docker container stop --time/, output) + assert_match "docker container start dash-proxy ||", output + assert_no_match(%r{docker container stop --time \d+ dash-proxy}, output) assert_no_match(/rebooting on/, output) end end @@ -177,26 +177,26 @@ class CliProxyTest < CliTestCase stub_proxy_drift # Holder and old generation are running SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :container, :ls, "--filter", "'name=^kamal-proxy-net$'", "--quiet", raise_on_non_zero_exit: false) + .with(:docker, :container, :ls, "--filter", "'name=^dash-proxy-net$'", "--quiet", raise_on_non_zero_exit: false) .returns("holder123") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :container, :ls, "--filter", "'name=^kamal-proxy$'", "--quiet", raise_on_non_zero_exit: false) + .with(:docker, :container, :ls, "--filter", "'name=^dash-proxy$'", "--quiet", raise_on_non_zero_exit: false) .returns("abc123") run_command("boot", fixture: :with_proxy_port_holder).tap do |output| - assert_match "Handing off kamal-proxy on 1.1.1.1 to a new generation (zero downtime)...", output - assert_match_with_digest "docker run --name kamal-proxy-next --network container:kamal-proxy-net --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore --reuse-port on 1.1.1.1", output - assert_match "docker update --restart=no kamal-proxy on 1.1.1.1", output - assert_match "docker exec kamal-proxy kamal-proxy drain --drain-timeout=30s on 1.1.1.1", output - assert_match "docker wait kamal-proxy on 1.1.1.1", output - assert_match "docker container rm kamal-proxy on 1.1.1.1", output - assert_match "docker container rename kamal-proxy-next kamal-proxy on 1.1.1.1", output - assert_no_match(/docker container stop --time/, output) + assert_match "Handing off dash-proxy on 1.1.1.1 to a new generation (zero downtime)...", output + assert_match_with_digest "docker run --name dash-proxy-next --network container:dash-proxy-net --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore --reuse-port on 1.1.1.1", output + assert_match "docker update --restart=no dash-proxy on 1.1.1.1", output + assert_match "docker exec dash-proxy dash-proxy drain --drain-timeout=30s on 1.1.1.1", output + assert_match "docker wait dash-proxy on 1.1.1.1", output + assert_match "docker container rm dash-proxy on 1.1.1.1", output + assert_match "docker container rename dash-proxy-next dash-proxy on 1.1.1.1", output + assert_no_match(%r{docker container stop --time \d+ dash-proxy}, output) # The restart policy must be cancelled BEFORE draining - drain makes the # old proxy exit on its own, which an active restart policy would undo. - assert_operator output.index("docker update --restart=no kamal-proxy on 1.1.1.1"), - :<, output.index("docker exec kamal-proxy kamal-proxy drain") + assert_operator output.index("docker update --restart=no dash-proxy on 1.1.1.1"), + :<, output.index("docker exec dash-proxy dash-proxy drain") end end @@ -204,43 +204,43 @@ class CliProxyTest < CliTestCase Object.any_instance.stubs(:sleep) stub_proxy_drift SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :container, :ls, "--filter", "'name=^kamal-proxy-net$'", "--quiet", raise_on_non_zero_exit: false) + .with(:docker, :container, :ls, "--filter", "'name=^dash-proxy-net$'", "--quiet", raise_on_non_zero_exit: false) .returns("") run_command("boot", fixture: :with_proxy_port_holder).tap do |output| - assert_match "Migrating kamal-proxy on 1.1.1.1 to the port-holder architecture (brief gap)...", output - assert_match "docker container stop --time 40 kamal-proxy on 1.1.1.1", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output - assert_match "docker run --name kamal-proxy-net --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy hold on 1.1.1.1", output - assert_match_with_digest "docker run --name kamal-proxy --network container:kamal-proxy-net --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore --reuse-port on 1.1.1.1", output + assert_match "Migrating dash-proxy on 1.1.1.1 to the port-holder architecture (brief gap)...", output + assert_match "docker container stop --time 40 dash-proxy on 1.1.1.1", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy && docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output + assert_match "docker run --name dash-proxy-net --network dash --detach --restart unless-stopped --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy hold on 1.1.1.1", output + assert_match_with_digest "docker run --name dash-proxy --network container:dash-proxy-net --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --label org.dash.proxy-config-digest=DIGEST --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore --reuse-port on 1.1.1.1", output end end test "boot with port_holder ensures the holder before starting the proxy" do stub_no_proxy_drift SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") + .with(:docker, :inspect, "dash-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns(Dash::Configuration::Proxy::Run::MINIMUM_VERSION) run_command("boot", fixture: :with_proxy_port_holder).tap do |output| - assert_match "docker container start kamal-proxy-net || docker run --name kamal-proxy-net --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy hold on 1.1.1.1", output - assert_match "docker container start kamal-proxy || docker run --name kamal-proxy --network container:kamal-proxy-net", output + assert_match "docker container start dash-proxy-net || docker run --name dash-proxy-net --network dash --detach --restart unless-stopped --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy hold on 1.1.1.1", output + assert_match "docker container start dash-proxy || docker run --name dash-proxy --network container:dash-proxy-net", output end end test "boot with matching digest does not reboot" do SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :container, :ls, "--all", "--filter", "'name=^kamal-proxy$'", "--quiet", raise_on_non_zero_exit: false) + .with(:docker, :container, :ls, "--all", "--filter", "'name=^dash-proxy$'", "--quiet", raise_on_non_zero_exit: false) .returns("abc123") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format", Dash::Commands::Proxy::CONFIG_DIGEST_FORMAT, raise_on_non_zero_exit: false) + .with(:docker, :inspect, "dash-proxy", "--format", Dash::Commands::Proxy::CONFIG_DIGEST_FORMAT, raise_on_non_zero_exit: false) .returns(Dash::Configuration::Proxy::Run.digest("")) run_command("boot").tap do |output| - assert_match "docker container start kamal-proxy ||", output + assert_match "docker container start dash-proxy ||", output assert_no_match(/rebooting on/, output) - assert_no_match(/docker container stop --time/, output) + assert_no_match(%r{docker container stop --time \d+ dash-proxy}, output) end end @@ -254,18 +254,18 @@ class CliProxyTest < CliTestCase Thread.report_on_exception = false stub_no_proxy_drift SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") + .with(:docker, :inspect, "dash-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns("v0.0.1") .at_least_once exception = assert_raises do run_command("boot").tap do |output| assert_match "docker login", output - assert_match "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output + assert_match "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy", output end end - assert_includes exception.message, "kamal-proxy version v0.0.1 is too old, run `dash proxy reboot` in order to update to at least #{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}" + assert_includes exception.message, "dash-proxy version v0.0.1 is too old, run `dash proxy reboot` in order to update to at least #{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}" ensure Thread.report_on_exception = false end @@ -274,13 +274,13 @@ class CliProxyTest < CliTestCase Thread.report_on_exception = false stub_no_proxy_drift SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") + .with(:docker, :inspect, "dash-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns(Dash::Configuration::Proxy::Run::MINIMUM_VERSION) .at_least_once run_command("boot").tap do |output| assert_match "docker login", output - assert_match "docker container start kamal-proxy || echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output + assert_match "docker container start dash-proxy || echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy", output end ensure Thread.report_on_exception = false @@ -290,30 +290,30 @@ class CliProxyTest < CliTestCase run_command("reboot", "-y").tap do |output| %w[ 1.1.1.1 1.1.1.2 ].each do |host| assert_match "docker pull $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") on #{host}", output - assert_match "docker container stop --time 40 kamal-proxy on #{host}", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on #{host}", output + assert_match "docker container stop --time 40 dash-proxy on #{host}", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy && docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on #{host}", output assert_match "mkdir -p .dash/proxy/apps-config on #{host}", output - assert_match "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --label org.dash.proxy-config-digest=#{Dash::Configuration::Proxy::Run.digest("")} --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config on #{host}", output - assert_match "docker exec kamal-proxy kamal-proxy list on #{host}", output + assert_match "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --label org.dash.proxy-config-digest=#{Dash::Configuration::Proxy::Run.digest("")} --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config on #{host}", output + assert_match "docker exec dash-proxy dash-proxy list on #{host}", output end end end test "reboot --rolling" do run_command("reboot", "--rolling", "-y").tap do |output| - assert_match "Running docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output + assert_match "Running docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy && docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output end end test "start" do run_command("start").tap do |output| - assert_match "docker container start kamal-proxy", output + assert_match "docker container start dash-proxy", output end end test "stop" do run_command("stop").tap do |output| - assert_match "docker container stop kamal-proxy", output + assert_match "docker container stop dash-proxy", output end end @@ -326,13 +326,13 @@ class CliProxyTest < CliTestCase test "details" do run_command("details").tap do |output| - assert_match "docker ps --filter 'name=^kamal-proxy$'", output + assert_match "docker ps --filter 'name=^dash-proxy$'", output end end test "logs" do SSHKit::Backend::Abstract.any_instance.stubs(:capture) - .with(:docker, :logs, "kamal-proxy", "--tail 100", "--timestamps", "2>&1") + .with(:docker, :logs, "dash-proxy", "--tail 100", "--timestamps", "2>&1") .returns("Log entry") SSHKit::Backend::Abstract.any_instance.stubs(:capture) @@ -347,16 +347,16 @@ class CliProxyTest < CliTestCase test "logs with follow" do SSHKit::Backend::Abstract.any_instance.stubs(:exec) - .with("ssh -t root@1.1.1.1 -p 22 'docker logs kamal-proxy --timestamps --tail 10 --follow 2>&1'") + .with("ssh -t root@1.1.1.1 -p 22 'docker logs dash-proxy --timestamps --tail 10 --follow 2>&1'") - assert_match "docker logs kamal-proxy --timestamps --tail 10 --follow", run_command("logs", "--follow") + assert_match "docker logs dash-proxy --timestamps --tail 10 --follow", run_command("logs", "--follow") end test "remove" do run_command("remove").tap do |output| assert_match "/usr/bin/env ls .dash/apps | wc -l", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", output - assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy", output + assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy", output end end @@ -386,13 +386,13 @@ class CliProxyTest < CliTestCase test "remove_container" do run_command("remove_container").tap do |output| - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy", output end end test "remove_image" do run_command("remove_image").tap do |output| - assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output + assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy", output end end @@ -403,7 +403,7 @@ class CliProxyTest < CliTestCase stub_no_proxy_drift SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") + .with(:docker, :inspect, "dash-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns(Dash::Configuration::Proxy::Run::MINIMUM_VERSION) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) @@ -414,19 +414,19 @@ class CliProxyTest < CliTestCase assert_match "Upgrading proxy on 1.1.1.1,1.1.1.2,1.1.1.3,1.1.1.4...", output assert_match "docker login -u [REDACTED] -p [REDACTED]", output assert_match "docker container stop traefik ; docker container prune --force --filter label=org.opencontainers.image.title=Traefik && docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik", output - assert_match "docker container stop kamal-proxy", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", output - assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output + assert_match "docker container stop dash-proxy", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy", output + assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy", output assert_match "/usr/bin/env mkdir -p .dash", output - assert_match "docker network create kamal", output + assert_match "docker network create dash", output assert_match "docker login -u [REDACTED] -p [REDACTED]", output - assert_match "docker container start kamal-proxy || echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output + assert_match "docker container start dash-proxy || echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy", output assert_match "/usr/bin/env mkdir -p .dash", output assert_match %r{docker rename app-web-latest app-web-latest_replaced_.*}, output assert_match "/usr/bin/env mkdir -p .dash/apps/app/env/roles", output assert_match "Uploading \"\\n\" to .dash/apps/app/env/roles/web.env", output - assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-.* --env KAMAL_CONTAINER_NAME="app-web-latest" --env KAMAL_VERSION="latest" --env KAMAL_HOST="1.1.1.1" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" --label service="app" --label role="web" --label destination dhh/app:latest}, output - assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"12345678:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output + assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --network dash --hostname 1.1.1.1-.* --env KAMAL_CONTAINER_NAME="app-web-latest" --env KAMAL_VERSION="latest" --env KAMAL_HOST="1.1.1.1" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" --label service="app" --label role="web" --label destination dhh/app:latest}, output + assert_match "docker exec dash-proxy dash-proxy deploy app-web --target=\"12345678:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output assert_match "docker container ls --all --filter 'name=^app-web-12345678$' --quiet | xargs docker stop", output assert_match "docker tag dhh/app:latest dhh/app:latest", output assert_match "/usr/bin/env mkdir -p .dash", output @@ -443,7 +443,7 @@ class CliProxyTest < CliTestCase stub_no_proxy_drift SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") + .with(:docker, :inspect, "dash-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns(Dash::Configuration::Proxy::Run::MINIMUM_VERSION) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) @@ -597,7 +597,7 @@ class CliProxyTest < CliTestCase assert_match "Uploading \"--publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9000\" to .dash/proxy/options on #{host}", output assert_match "Running /usr/bin/env rm .dash/proxy/image on #{host}", output assert_match "Running /usr/bin/env rm .dash/proxy/image_version on #{host}", output - assert_match "Uploading \"kamal-proxy run --debug --metrics-port \\\"9000\\\"\" to .dash/proxy/run_command on #{host}", output + assert_match "Uploading \"dash-proxy run --debug --metrics-port \\\"9000\\\"\" to .dash/proxy/run_command on #{host}", output end end end @@ -608,7 +608,7 @@ class CliProxyTest < CliTestCase assert_match "Uploading \"--publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9000 --label=foo=bar\" to .dash/proxy/options on #{host}", output assert_match "Uploading \"myreg/myrepo/dash-proxy\" to .dash/proxy/image on #{host}", output assert_match "Uploading \"0.9.9\" to .dash/proxy/image_version on #{host}", output - assert_match "Uploading \"kamal-proxy run --debug --metrics-port \\\"9000\\\"\" to .dash/proxy/run_command on #{host}", output + assert_match "Uploading \"dash-proxy run --debug --metrics-port \\\"9000\\\"\" to .dash/proxy/run_command on #{host}", output end end end @@ -636,7 +636,7 @@ class CliProxyTest < CliTestCase # Domains tests test "domains refresh" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", "domains", "refresh") + .with(:docker, :exec, "dash-proxy", "dash-proxy", "domains", "refresh") .returns("Refresh queued") .at_least_once @@ -650,7 +650,7 @@ class CliProxyTest < CliTestCase test "domains stats" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", "domains", "stats") + .with(:docker, :exec, "dash-proxy", "dash-proxy", "domains", "stats") .returns("certs: 3 pending: 1") .at_least_once @@ -663,7 +663,7 @@ class CliProxyTest < CliTestCase # for the operator who already knows the cause is fixed. test "domains retry with a host" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", "domains", "retry", "app.example.com") + .with(:docker, :exec, "dash-proxy", "dash-proxy", "domains", "retry", "app.example.com") .returns("Cleared 1 issuance hold") .at_least_once @@ -674,7 +674,7 @@ class CliProxyTest < CliTestCase test "domains retry --all" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", "domains", "retry", "--all") + .with(:docker, :exec, "dash-proxy", "dash-proxy", "domains", "retry", "--all") .returns("Cleared 3 issuance holds") .at_least_once @@ -694,7 +694,7 @@ class CliProxyTest < CliTestCase # when load balancing (cache policy is edge-only), else the proxy hosts. test "cache stats" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :cache, :stats) + .with(:docker, :exec, "dash-proxy", "dash-proxy", :cache, :stats) .returns("Response cache (per node): 12 entries").twice run_command("cache", "stats").tap do |output| @@ -704,7 +704,7 @@ class CliProxyTest < CliTestCase test "cache stats passes count and json through" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :cache, :stats, "--count", "--json") + .with(:docker, :exec, "dash-proxy", "dash-proxy", :cache, :stats, "--count", "--json") .returns("{}").twice run_command("cache", "stats", "--count", "--json").tap do |output| @@ -716,7 +716,7 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "load-balancer", "kamal-proxy", :cache, :stats) + .with(:docker, :exec, "load-balancer", "dash-proxy", :cache, :stats) .returns("Response cache (shared): 40 entries") run_command("cache", "stats", fixture: :with_loadbalancer).tap do |output| @@ -729,7 +729,7 @@ class CliProxyTest < CliTestCase # purge walks them per host. test "cache purge purges each proxied role service" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :cache, :purge, "app-web") + .with(:docker, :exec, "dash-proxy", "dash-proxy", :cache, :purge, "app-web") .returns("Purged 3 cached responses").twice run_command("cache", "purge").tap do |output| @@ -739,7 +739,7 @@ class CliProxyTest < CliTestCase test "cache purge passes the path prefix through" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :cache, :purge, "app-web", "--path-prefix", "\"/assets\"") + .with(:docker, :exec, "dash-proxy", "dash-proxy", :cache, :purge, "app-web", "--path-prefix", "\"/assets\"") .returns("Purged 1 cached response").twice run_command("cache", "purge", "--path-prefix", "/assets").tap do |output| @@ -751,7 +751,7 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "load-balancer", "kamal-proxy", :cache, :purge, "app") + .with(:docker, :exec, "load-balancer", "dash-proxy", :cache, :purge, "app") .returns("Purged 7 cached responses") run_command("cache", "purge", fixture: :with_loadbalancer).tap do |output| @@ -770,7 +770,7 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "load-balancer", "kamal-proxy", "domains", "list") + .with(:docker, :exec, "load-balancer", "dash-proxy", "domains", "list") .returns("customer1.example.com") run_command("domains", "list", fixture: :with_loadbalancer).tap do |output| @@ -783,7 +783,7 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", "domains", "refresh") + .with(:docker, :exec, "dash-proxy", "dash-proxy", "domains", "refresh") .returns("Refresh queued") run_command("domains", "refresh", fixture: :with_loadbalancer_on_proxy_host).tap do |output| @@ -808,7 +808,7 @@ class CliProxyTest < CliTestCase # Check loadbalancer is started assert_match "Starting loadbalancer on lb.example.com", output assert_match "docker container start load-balancer || docker run --name load-balancer", output - assert_match "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run", output + assert_match "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run", output end end @@ -858,7 +858,7 @@ class CliProxyTest < CliTestCase run_command("boot", fixture: :with_loadbalancer).tap do |output| assert_match "Loadbalancer configuration changed, rebooting on lb.example.com", output assert_match "docker container stop load-balancer on lb.example.com", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer on lb.example.com", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-loadbalancer && docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer on lb.example.com", output assert_match "docker run --name load-balancer", output end end @@ -870,7 +870,7 @@ class CliProxyTest < CliTestCase run_command("boot", fixture: :with_loadbalancer).tap do |output| assert_match "The loadbalancer on lb.example.com is running with a configuration that no longer matches the deploy config", output - assert_no_match(/docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer/, output) + assert_no_match(/docker container prune --force --filter label=org.opencontainers.image.title=dash-loadbalancer/, output) # The old container keeps serving. assert_match "docker container start load-balancer", output end @@ -881,15 +881,15 @@ class CliProxyTest < CliTestCase run_command("reboot", "-y", fixture: :with_loadbalancer).tap do |output| # Check proxy is rebooted on web hosts - assert_match "docker container stop --time 40 kamal-proxy on 1.1.1.1", output - assert_match "docker container stop --time 40 kamal-proxy on 1.1.1.2", output + assert_match "docker container stop --time 40 dash-proxy on 1.1.1.1", output + assert_match "docker container stop --time 40 dash-proxy on 1.1.1.2", output # Check loadbalancer is rebooted assert_match "Stopping and removing load-balancer on lb.example.com, if running", output assert_match "docker container stop load-balancer", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-loadbalancer", output assert_match "docker run --name load-balancer", output - assert_match "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run", output + assert_match "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run", output end end @@ -897,7 +897,7 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) run_command("details", fixture: :with_loadbalancer).tap do |output| - assert_match "docker ps --filter 'name=^kamal-proxy$'", output + assert_match "docker ps --filter 'name=^dash-proxy$'", output assert_match "docker ps --filter 'name=^load-balancer$'", output end end @@ -949,7 +949,7 @@ class CliProxyTest < CliTestCase run_command("loadbalancer", "deploy", fixture: :with_loadbalancer).tap do |output| assert_match "Deploying to loadbalancer on lb.example.com with targets: 1.1.1.1, 1.1.1.2", output - assert_match "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --tls --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output + assert_match "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --tls --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", output end end @@ -963,19 +963,19 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) run_command("remove_container", fixture: :with_loadbalancer).tap do |output| - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-loadbalancer", output end end test "remove_image with loadbalancer" do Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) - # The load balancer runs the kamal-proxy image, so it is pruned by the - # kamal-proxy title label - on its own host as well as on a shared one. + # The load balancer runs the dash-proxy image, so it is pruned by the + # dash-proxy title label - on its own host as well as on a shared one. run_command("remove_image", fixture: :with_loadbalancer).tap do |output| - assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output - assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy on lb.example.com", output + assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy && docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output + assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy && docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy on lb.example.com", output end end @@ -985,13 +985,13 @@ class CliProxyTest < CliTestCase run_command("boot", fixture: :with_loadbalancer_on_proxy_host).tap do |output| # Proxy should only boot on 1.1.1.2 (not 1.1.1.1 which is loadbalancer) - assert_match "docker container start kamal-proxy || echo", output - # Loadbalancer boots on 1.1.1.1 with kamal-proxy name and proxy volume mounts + assert_match "docker container start dash-proxy || echo", output + # Loadbalancer boots on 1.1.1.1 with dash-proxy name and proxy volume mounts assert_match "Starting loadbalancer on 1.1.1.1", output - assert_match "docker container start kamal-proxy || docker run --name kamal-proxy", output + assert_match "docker container start dash-proxy || docker run --name dash-proxy", output # Check that loadbalancer uses proxy-compatible config - assert_match "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output - assert_match ".dash/proxy/apps-config:/home/kamal-proxy/.apps-config", output + assert_match "dash-proxy-config:/home/dash-proxy/.config/dash-proxy", output + assert_match ".dash/proxy/apps-config:/home/dash-proxy/.apps-config", output end end @@ -1000,9 +1000,9 @@ class CliProxyTest < CliTestCase run_command("reboot", "-y", fixture: :with_loadbalancer_on_proxy_host).tap do |output| # Proxy reboots only on 1.1.1.2 - assert_match "docker container stop --time 40 kamal-proxy on 1.1.1.2", output - # Loadbalancer reboots on 1.1.1.1 using kamal-proxy container name - assert_match "Stopping and removing kamal-proxy on 1.1.1.1", output + assert_match "docker container stop --time 40 dash-proxy on 1.1.1.2", output + # Loadbalancer reboots on 1.1.1.1 using dash-proxy container name + assert_match "Stopping and removing dash-proxy on 1.1.1.1", output end end @@ -1010,8 +1010,8 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) run_command("loadbalancer", "info", fixture: :with_loadbalancer_on_proxy_host).tap do |output| - # When on proxy host, loadbalancer uses kamal-proxy container name - assert_match "docker ps --filter 'name=^kamal-proxy$'", output + # When on proxy host, loadbalancer uses dash-proxy container name + assert_match "docker ps --filter 'name=^dash-proxy$'", output end end @@ -1023,7 +1023,7 @@ class CliProxyTest < CliTestCase run_command("loadbalancer", "deploy", fixture: :with_loadbalancer).tap do |output| assert_match "mkdir -p .dash/loadbalancer/services", output - assert_match "docker exec load-balancer kamal-proxy deploy app", output + assert_match "docker exec load-balancer dash-proxy deploy app", output end end @@ -1032,7 +1032,7 @@ class CliProxyTest < CliTestCase stub_loadbalancer_registry(service_owner: loadbalancer_owner_token(:with_loadbalancer)) run_command("loadbalancer", "deploy", fixture: :with_loadbalancer).tap do |output| - assert_match "docker exec load-balancer kamal-proxy deploy app", output + assert_match "docker exec load-balancer dash-proxy deploy app", output assert_no_match(/is already registered on the load balancer/, output) end end @@ -1098,20 +1098,20 @@ class CliProxyTest < CliTestCase end end - # kamal-proxy persists its service state in the kamal-loadbalancer-config + # dash-proxy persists its service state in the dash-loadbalancer-config # named volume, so replacing the container keeps every app's routes. test "reboot preserves other apps services registered on the shared load balancer" do Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) stub_loadbalancer_registry SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :exec, "load-balancer", "kamal-proxy", :list) + .with(:docker, :exec, "load-balancer", "dash-proxy", :list) .returns("app\nother-app") run_command("reboot", "-y", fixture: :with_loadbalancer).tap do |output| # The container is replaced, but the state volume is re-mounted, never - # removed - at the path kamal-proxy actually reads its state from. - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer", output - assert_match "--volume kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy", output + # removed - at the path dash-proxy actually reads its state from. + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-loadbalancer", output + assert_match "--volume dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy", output assert_no_match(/docker volume rm/, output) # And the persisted service list is reported back after the restart. @@ -1128,12 +1128,12 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) stub_loadbalancer_registry(service_owner: loadbalancer_owner_token(:with_loadbalancer)) SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :exec, "load-balancer", "kamal-proxy", :list, "--json") + .with(:docker, :exec, "load-balancer", "dash-proxy", :list, "--json") .returns({ services: { "app" => { "target" => "1.1.1.1:80" } } }.to_json) run_command("reboot", "-y", fixture: :with_loadbalancer).tap do |output| assert_match "Re-registering app with the load balancer on lb.example.com", output - assert_match "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\"", output + assert_match "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\"", output end end @@ -1141,7 +1141,7 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) stub_loadbalancer_registry(service_owner: loadbalancer_owner_token(:with_loadbalancer)) SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :exec, "load-balancer", "kamal-proxy", :list, "--json") + .with(:docker, :exec, "load-balancer", "dash-proxy", :list, "--json") .returns({ services: { "other-app" => {} } }.to_json) error = assert_raises(SSHKit::Runner::ExecuteError) { run_command("reboot", "-y", fixture: :with_loadbalancer) } @@ -1155,7 +1155,7 @@ class CliProxyTest < CliTestCase stub_loadbalancer_registry run_command("reboot", "-y", fixture: :with_loadbalancer).tap do |output| - assert_no_match(/kamal-proxy deploy/, output) + assert_no_match(/dash-proxy deploy/, output) end end @@ -1196,7 +1196,7 @@ class CliProxyTest < CliTestCase run_command("remove", fixture: :with_loadbalancer).tap do |output| assert_match "docker container stop load-balancer on lb.example.com", output - assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=dash-loadbalancer", output end end @@ -1212,9 +1212,9 @@ class CliProxyTest < CliTestCase # Certificate store transfer test "export_certs downloads the archive from the running proxy" do - stub_cert_container_running "kamal-proxy" + stub_cert_container_running "dash-proxy" SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :exec, "kamal-proxy", "kamal-proxy", :export, :certs, "/home/kamal-proxy/.apps-config/certs-export.tar.gz") + .with(:docker, :exec, "dash-proxy", "dash-proxy", :export, :certs, "/home/dash-proxy/.apps-config/certs-export.tar.gz") .returns("Exported 3 certificates (5 domains)") downloads = capture_downloads @@ -1231,7 +1231,7 @@ class CliProxyTest < CliTestCase test "export_certs falls back to a one-off container when the proxy is stopped" do SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with { |*args| args.join(" ").include?("docker run --rm --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy") && args.join(" ").include?("export certs") } + .with { |*args| args.join(" ").include?("docker run --rm --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy") && args.join(" ").include?("export certs") } .returns("Exported 0 certificates (0 domains)") downloads = capture_downloads @@ -1247,7 +1247,7 @@ class CliProxyTest < CliTestCase Dash::Configuration::Proxy.any_instance.unstub(:load_balancing?) stub_cert_container_running "load-balancer" SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :exec, "load-balancer", "kamal-proxy", :export, :certs, "/home/kamal-proxy/.apps-config/certs-export.tar.gz") + .with(:docker, :exec, "load-balancer", "dash-proxy", :export, :certs, "/home/dash-proxy/.apps-config/certs-export.tar.gz") .returns("Exported 3 certificates (5 domains)") downloads = capture_downloads @@ -1262,7 +1262,7 @@ class CliProxyTest < CliTestCase test "import_certs stages the source and runs the one-off importer" do SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with { |*args| args.join(" ").include?("sh -c 'cat > /tmp/kamal-cert-import && kamal-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\"' < .dash/proxy/certs-import") } + .with { |*args| args.join(" ").include?("sh -c 'cat > /tmp/kamal-cert-import && dash-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\"' < .dash/proxy/certs-import") } .returns("Imported: 3") uploads = capture_file_uploads @@ -1277,7 +1277,7 @@ class CliProxyTest < CliTestCase end test "import_certs refuses to run while the proxy is running" do - stub_cert_container_running "kamal-proxy" + stub_cert_container_running "dash-proxy" assert_raises(SSHKit::Runner::ExecuteError) do stdouted { Dash::Cli::Proxy.start([ "import_certs", "--archive", "certs.tar.gz", "-c", "test/fixtures/deploy_with_proxy.yml" ]) } @@ -1285,7 +1285,7 @@ class CliProxyTest < CliTestCase end test "import_certs verify runs against a running proxy" do - stub_cert_container_running "kamal-proxy" + stub_cert_container_running "dash-proxy" SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) .with { |*args| args.join(" ").include?("--archive=\"/tmp/kamal-cert-import\" --verify") } .returns("Verified 3 certificates") @@ -1389,7 +1389,7 @@ def stub_loadbalancer_registry(service_owner: "", run_config: "") # Allow the drift-detection captures without triggering a reboot. def stub_no_proxy_drift SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :container, :ls, "--all", "--filter", "'name=^kamal-proxy$'", "--quiet", raise_on_non_zero_exit: false) + .with(:docker, :container, :ls, "--all", "--filter", "'name=^dash-proxy$'", "--quiet", raise_on_non_zero_exit: false) .returns("") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) .with { |*args| args.first == :echo } @@ -1410,10 +1410,10 @@ def stub_loadbalancer_drift def stub_proxy_drift SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :container, :ls, "--all", "--filter", "'name=^kamal-proxy$'", "--quiet", raise_on_non_zero_exit: false) + .with(:docker, :container, :ls, "--all", "--filter", "'name=^dash-proxy$'", "--quiet", raise_on_non_zero_exit: false) .returns("abc123") SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format", Dash::Commands::Proxy::CONFIG_DIGEST_FORMAT, raise_on_non_zero_exit: false) + .with(:docker, :inspect, "dash-proxy", "--format", Dash::Commands::Proxy::CONFIG_DIGEST_FORMAT, raise_on_non_zero_exit: false) .returns("stale-digest") end diff --git a/test/commands/accessory_test.rb b/test/commands/accessory_test.rb index 674fbcbd..4c4600cb 100644 --- a/test/commands/accessory_test.rb +++ b/test/commands/accessory_test.rb @@ -61,15 +61,15 @@ class CommandsAccessoryTest < ActiveSupport::TestCase test "run" do assert_equal \ - "docker run --name app-mysql --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 3306:3306 --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --label service=\"app-mysql\" --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0", + "docker run --name app-mysql --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 3306:3306 --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --label service=\"app-mysql\" --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0", new_command(:mysql).run.join(" ") assert_equal \ - "docker run --name app-redis --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --publish 6379:6379 --env SOMETHING=\"else\" --env-file .dash/apps/app/env/accessories/redis.env --volume /var/lib/redis:/data --label service=\"app-redis\" --label cache=\"true\" redis:latest", + "docker run --name app-redis --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --publish 6379:6379 --env SOMETHING=\"else\" --env-file .dash/apps/app/env/accessories/redis.env --volume /var/lib/redis:/data --label service=\"app-redis\" --label cache=\"true\" redis:latest", new_command(:redis).run.join(" ") assert_equal \ - "docker run --name custom-busybox --detach --restart unless-stopped --network kamal --log-opt max-size=\"10m\" --env-file .dash/apps/app/env/accessories/busybox.env --label service=\"custom-busybox\" other.registry/busybox:latest", + "docker run --name custom-busybox --detach --restart unless-stopped --network dash --log-opt max-size=\"10m\" --env-file .dash/apps/app/env/accessories/busybox.env --label service=\"custom-busybox\" other.registry/busybox:latest", new_command(:busybox).run.join(" ") end @@ -83,7 +83,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase @config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } } assert_equal \ - "docker run --name custom-busybox --detach --restart unless-stopped --network kamal --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --env-file .dash/apps/app/env/accessories/busybox.env --label service=\"custom-busybox\" other.registry/busybox:latest", + "docker run --name custom-busybox --detach --restart unless-stopped --network dash --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --env-file .dash/apps/app/env/accessories/busybox.env --label service=\"custom-busybox\" other.registry/busybox:latest", new_command(:busybox).run.join(" ") end @@ -91,7 +91,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase @config[:accessories]["mysql"]["options"]["restart"] = "on-failure" assert_equal \ - "docker run --name app-mysql --detach --restart on-failure --network kamal --log-opt max-size=\"10m\" --publish 3306:3306 --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --label service=\"app-mysql\" --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0", + "docker run --name app-mysql --detach --restart on-failure --network dash --log-opt max-size=\"10m\" --publish 3306:3306 --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --label service=\"app-mysql\" --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0", new_command(:mysql).run.join(" ") end @@ -123,7 +123,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase test "execute in new container" do assert_equal \ - "docker run --rm --network kamal --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0 mysql -u root", + "docker run --rm --network dash --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0 mysql -u root", new_command(:mysql).execute_in_new_container("mysql", "-u", "root").join(" ") end @@ -133,7 +133,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase command = new_command(:mysql).execute_in_new_container("mysql", "-u", "root").join(" ") assert_equal \ - "docker run --rm --network kamal --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0 mysql -u root", + "docker run --rm --network dash --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0 mysql -u root", command assert_no_match(/--restart/, command) end @@ -146,7 +146,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase test "execute in new container over ssh" do new_command(:mysql).stub(:run_over_ssh, ->(cmd) { cmd.join(" ") }) do - assert_match %r{docker run -it --rm --network kamal --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0 mysql -u root}, + assert_match %r{docker run -it --rm --network dash --env MYSQL_ROOT_HOST=\"%\" --env-file .dash/apps/app/env/accessories/mysql.env --cpus \"4\" --memory \"2GB\" private.registry/mysql:8.0 mysql -u root}, stub_stdin_tty { new_command(:mysql).execute_in_new_container_over_ssh("mysql", "-u", "root") } end end @@ -213,7 +213,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase test "deploy" do assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy custom-busybox --target=\"172.1.0.2:80\" --host=\"busybox.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy custom-busybox --target=\"172.1.0.2:80\" --host=\"busybox.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command(:busybox).deploy(target: "172.1.0.2").join(" ") end @@ -225,13 +225,13 @@ class CommandsAccessoryTest < ActiveSupport::TestCase @config[:accessories]["busybox"]["proxy"]["ssl"] = true assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy custom-busybox --target=\"172.1.0.2:80\" --host=\"busybox.example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy custom-busybox --target=\"172.1.0.2:80\" --host=\"busybox.example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command(:busybox).deploy(target: "172.1.0.2").join(" ") end test "remove" do assert_equal \ - "docker exec kamal-proxy kamal-proxy remove custom-busybox", + "docker exec dash-proxy dash-proxy remove custom-busybox", new_command(:busybox).remove.join(" ") end diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index d2d20634..1fd146db 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -13,20 +13,20 @@ class CommandsAppTest < ActiveSupport::TestCase test "run" do assert_equal \ - "docker run --detach --restart unless-stopped --name app-web-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", + "docker run --detach --restart unless-stopped --name app-web-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", new_command.run.join(" ") end test "run with destination" do @destination = "staging" assert_equal \ - "docker run --detach --restart unless-stopped --name app-web-staging-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-web-staging-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env KAMAL_DESTINATION=\"staging\" --env-file .dash/apps/app-staging/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination=\"staging\" dhh/app:999", + "docker run --detach --restart unless-stopped --name app-web-staging-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-web-staging-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env KAMAL_DESTINATION=\"staging\" --env-file .dash/apps/app-staging/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination=\"staging\" dhh/app:999", new_command.run.join(" ") end test "run with hostname" do assert_equal \ - "docker run --detach --restart unless-stopped --name app-web-999 --network kamal --hostname myhost --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", + "docker run --detach --restart unless-stopped --name app-web-999 --network dash --hostname myhost --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", new_command.run(hostname: "myhost").join(" ") end @@ -34,7 +34,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "healthcheck" => { "port" => 7434, "path" => "/readyz", "start_period" => 60 } } } assert_equal \ - "docker run --detach --restart unless-stopped --name app-jobs-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-jobs-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/roles/jobs.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"jobs\" --label destination --health-cmd \"curl -f http://localhost:7434/readyz || exit 1\" --health-interval \"1s\" --health-start-period \"60s\" dhh/app:999 bin/jobs", + "docker run --detach --restart unless-stopped --name app-jobs-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-jobs-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/roles/jobs.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"jobs\" --label destination --health-cmd \"curl -f http://localhost:7434/readyz || exit 1\" --health-interval \"1s\" --health-start-period \"60s\" dhh/app:999 bin/jobs", new_command(role: "jobs", host: "1.1.1.2").run.join(" ") end @@ -76,14 +76,14 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:volumes] = [ "/local/path:/container/path" ] assert_equal \ - "docker run --detach --restart unless-stopped --name app-web-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --volume /local/path:/container/path --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", + "docker run --detach --restart unless-stopped --name app-web-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --volume /local/path:/container/path --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", new_command.run.join(" ") end test "run with custom options" do @config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "options" => { "mount" => "somewhere", "cap-add" => true } } } assert_equal \ - "docker run --detach --restart unless-stopped --name app-jobs-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-jobs-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/roles/jobs.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"jobs\" --label destination --mount \"somewhere\" --cap-add dhh/app:999 bin/jobs", + "docker run --detach --restart unless-stopped --name app-jobs-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-jobs-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.2\" --env-file .dash/apps/app/env/roles/jobs.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"jobs\" --label destination --mount \"somewhere\" --cap-add dhh/app:999 bin/jobs", new_command(role: "jobs", host: "1.1.1.2").run.join(" ") end @@ -91,7 +91,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "restart" => "on-failure" } } } assert_equal \ - "docker run --detach --restart on-failure --name app-web-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", + "docker run --detach --restart on-failure --name app-web-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", new_command.run.join(" ") end @@ -99,7 +99,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } } assert_equal \ - "docker run --detach --restart unless-stopped --name app-web-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", + "docker run --detach --restart unless-stopped --name app-web-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", new_command.run.join(" ") end @@ -108,7 +108,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "logging" => { "driver" => "local", "options" => { "max-size" => "100m" } } } } assert_equal \ - "docker run --detach --restart unless-stopped --name app-web-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", + "docker run --detach --restart unless-stopped --name app-web-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env-file .dash/apps/app/env/roles/web.env --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", new_command.run.join(" ") end @@ -117,7 +117,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:env]["tags"] = { "tag1" => { "ENV1" => "value1" } } assert_equal \ - "docker run --detach --restart unless-stopped --name app-web-999 --network kamal --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env ENV1=\"value1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", + "docker run --detach --restart unless-stopped --name app-web-999 --network dash --env KAMAL_CONTAINER_NAME=\"app-web-999\" --env KAMAL_VERSION=\"999\" --env KAMAL_HOST=\"1.1.1.1\" --env ENV1=\"value1\" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination dhh/app:999", new_command.run.join(" ") end @@ -183,7 +183,7 @@ class CommandsAppTest < ActiveSupport::TestCase test "deploy" do assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(target: "172.1.0.2").join(" ") end @@ -191,7 +191,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:proxy] = { "path_response_timeouts" => { "/api/reports" => "5m", "/stream" => 0 } } assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --path-timeout=\"/api/reports=5m\" --path-timeout=\"/stream=0s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --path-timeout=\"/api/reports=5m\" --path-timeout=\"/stream=0s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(target: "172.1.0.2").join(" ") end @@ -202,7 +202,7 @@ class CommandsAppTest < ActiveSupport::TestCase # The executed argv carries the real credential... assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --basic-auth=\"admin:s3cr3t\" --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --basic-auth=\"admin:s3cr3t\" --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", command.join(" ") # ...but anything kamal prints redacts it (registry-login precedent). @@ -214,7 +214,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:proxy] = { "ssl" => true, "host" => "example.com" } assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(target: "172.1.0.2").join(" ") end @@ -222,7 +222,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:proxy] = { "ssl" => true, "hosts" => [ "example.com", "anotherexample.com" ] } assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --host=\"anotherexample.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --host=\"anotherexample.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(target: "172.1.0.2").join(" ") end @@ -230,7 +230,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:proxy] = { "ssl" => false } assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(target: "172.1.0.2").join(" ") end @@ -238,7 +238,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:proxy] = { "healthcheck" => { "interval" => 1, "timeout" => 10, "path" => "/health", "port" => 3001, "host" => "health.example.com" } } assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --health-check-interval=\"1s\" --health-check-timeout=\"10s\" --health-check-path=\"/health\" --health-check-port=\"3001\" --health-check-host=\"health.example.com\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --health-check-interval=\"1s\" --health-check-timeout=\"10s\" --health-check-path=\"/health\" --health-check-port=\"3001\" --health-check-host=\"health.example.com\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(target: "172.1.0.2").join(" ") end @@ -246,19 +246,19 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:proxy] = { "healthcheck" => { "port" => 8080 } } assert_equal \ - "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --health-check-port=\"8080\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec dash-proxy dash-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --health-check-port=\"8080\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(target: "172.1.0.2").join(" ") end test "remove" do assert_equal \ - "docker exec kamal-proxy kamal-proxy remove app-web", + "docker exec dash-proxy dash-proxy remove app-web", new_command.remove.join(" ") end test "rollout_deploy" do assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\"", + "docker exec dash-proxy dash-proxy rollout deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\"", new_command.rollout_deploy(target: "172.1.0.2").join(" ") end @@ -266,7 +266,7 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:proxy] = { "ssl" => true, "host" => "example.com", "response_timeout" => 10 } assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\"", + "docker exec dash-proxy dash-proxy rollout deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\"", new_command.rollout_deploy(target: "172.1.0.2").join(" ") end @@ -275,37 +275,37 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:drain_timeout] = 12 assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"6s\" --drain-timeout=\"12s\"", + "docker exec dash-proxy dash-proxy rollout deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"6s\" --drain-timeout=\"12s\"", new_command.rollout_deploy(target: "172.1.0.2").join(" ") end test "rollout_set with percent" do assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout set app-web --percent=\"10\"", + "docker exec dash-proxy dash-proxy rollout set app-web --percent=\"10\"", new_command.rollout_set(percent: 10).join(" ") end test "rollout_set with percent zero" do assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout set app-web --percent=\"0\"", + "docker exec dash-proxy dash-proxy rollout set app-web --percent=\"0\"", new_command.rollout_set(percent: 0).join(" ") end test "rollout_set with list" do assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout set app-web --list=\"dhh\" --list=\"jorge\"", + "docker exec dash-proxy dash-proxy rollout set app-web --list=\"dhh\" --list=\"jorge\"", new_command.rollout_set(list: [ "dhh", "jorge" ]).join(" ") end test "rollout_set with percent and list" do assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout set app-web --percent=\"10\" --list=\"dhh\"", + "docker exec dash-proxy dash-proxy rollout set app-web --percent=\"10\" --list=\"dhh\"", new_command.rollout_set(percent: 10, list: [ "dhh" ]).join(" ") end test "rollout_stop" do assert_equal \ - "docker exec kamal-proxy kamal-proxy rollout stop app-web", + "docker exec dash-proxy dash-proxy rollout stop app-web", new_command.rollout_stop.join(" ") end @@ -412,7 +412,7 @@ class CommandsAppTest < ActiveSupport::TestCase test "execute in new container" do assert_match \ - %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, + %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ") end @@ -420,19 +420,19 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } } assert_match \ - %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-driver "local" --log-opt max-size="100m" --log-opt max-file="3" dhh/app:999 bin/rails db:setup}, + %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-driver "local" --log-opt max-size="100m" --log-opt max-file="3" dhh/app:999 bin/rails db:setup}, new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ") end test "execute in new container with env" do assert_match \ - %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --env foo="bar" --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, + %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --env foo="bar" --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, new_command.execute_in_new_container("bin/rails", "db:setup", env: { "foo" => "bar" }).join(" ") end test "execute in new detached container" do assert_match \ - %r{docker run --detach --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, + %r{docker run --detach --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, new_command.execute_in_new_container("bin/rails", "db:setup", detach: true, env: {}).join(" ") end @@ -441,14 +441,14 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:env]["tags"] = { "tag1" => { "ENV1" => "value1" } } assert_match \ - %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env ENV1="value1" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, + %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env ENV1="value1" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails db:setup}, new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ") end test "execute in new container with custom options" do @config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } } assert_match \ - %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" --mount "somewhere" --cap-add dhh/app:999 bin/rails db:setup}, + %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" --mount "somewhere" --cap-add dhh/app:999 bin/rails db:setup}, new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ") end @@ -457,7 +457,7 @@ class CommandsAppTest < ActiveSupport::TestCase command = new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ") - assert_match %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" --mount "somewhere" dhh/app:999 bin/rails db:setup}, command + assert_match %r{docker run --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" --mount "somewhere" dhh/app:999 bin/rails db:setup}, command assert_no_match(/--restart/, command) end @@ -474,7 +474,7 @@ class CommandsAppTest < ActiveSupport::TestCase end test "execute in new container over ssh" do - assert_match %r{docker run -it --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails c}, + assert_match %r{docker run -it --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails c}, stub_stdin_tty { new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {}) } end @@ -482,13 +482,13 @@ class CommandsAppTest < ActiveSupport::TestCase @config[:servers] = [ { "1.1.1.1" => "tag1" } ] @config[:env]["tags"] = { "tag1" => { "ENV1" => "value1" } } - assert_match %r{ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env ENV1="value1" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails c'}, + assert_match %r{ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env ENV1="value1" --env-file .dash/apps/app/env/roles/web.env --log-opt max-size="10m" dhh/app:999 bin/rails c'}, stub_stdin_tty { new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {}) } end test "execute in new container with custom options over ssh" do @config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } } - assert_match %r{docker run -it --rm --name app-web-exec-999-[0-9a-f]{6} --network kamal --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --mount \"somewhere\" --cap-add dhh/app:999 bin/rails c}, + assert_match %r{docker run -it --rm --name app-web-exec-999-[0-9a-f]{6} --network dash --env-file .dash/apps/app/env/roles/web.env --log-opt max-size=\"10m\" --mount \"somewhere\" --cap-add dhh/app:999 bin/rails c}, stub_stdin_tty { new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {}) } end @@ -711,19 +711,19 @@ class CommandsAppTest < ActiveSupport::TestCase test "live" do assert_equal \ - "docker exec kamal-proxy kamal-proxy resume app-web", + "docker exec dash-proxy dash-proxy resume app-web", new_command.live.join(" ") end test "maintenance" do assert_equal \ - "docker exec kamal-proxy kamal-proxy stop app-web", + "docker exec dash-proxy dash-proxy stop app-web", new_command.maintenance.join(" ") end test "maintenance with options" do assert_equal \ - "docker exec kamal-proxy kamal-proxy stop app-web --drain-timeout=\"10s\" --message=\"Hi\"", + "docker exec dash-proxy dash-proxy stop app-web --drain-timeout=\"10s\" --message=\"Hi\"", new_command.maintenance(drain_timeout: 10, message: "Hi").join(" ") end diff --git a/test/commands/docker_test.rb b/test/commands/docker_test.rb index daf597ee..aa2d7604 100644 --- a/test/commands/docker_test.rb +++ b/test/commands/docker_test.rb @@ -41,7 +41,32 @@ class CommandsDockerTest < ActiveSupport::TestCase end test "manifest_available?" do - assert_equal "docker manifest inspect basecamp/kamal-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}", - @docker.manifest_available?("basecamp/kamal-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}").join(" ") + assert_equal "docker manifest inspect basecamp/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}", + @docker.manifest_available?("basecamp/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}").join(" ") + end + + test "create_network uses the current network name" do + assert_equal "docker network create dash", @docker.create_network.join(" ") + end + + # Stage 3c: docker cannot rename a network, so `dash` is created alongside + # `kamal` and everything still on the old one is joined to the new one. App + # containers are replaced by the next deploy anyway; accessories are not, + # which is the whole point - without this a renamed proxy cannot reach `db`. + test "connect_legacy_network_containers bridges the old network into the new one" do + command = @docker.connect_legacy_network_containers.join(" ") + + assert_match "docker network inspect kamal > /dev/null 2>&1 &&", command + assert_match "docker network connect dash {}", command + end + + # A host that never had the legacy network must not fail its deploy, and a + # container already on both networks makes `network connect` fail - so each + # connect swallows its own failure and the sweep as a whole exits zero. + test "connect_legacy_network_containers cannot fail a deploy" do + command = @docker.connect_legacy_network_containers.join(" ") + + assert_match "|| true'", command, "a container already attached must not abort the sweep" + assert command.end_with?("|| true"), "a host with no legacy network must still exit zero" end end diff --git a/test/commands/loadbalancer_test.rb b/test/commands/loadbalancer_test.rb index 89c737ae..662938b2 100644 --- a/test/commands/loadbalancer_test.rb +++ b/test/commands/loadbalancer_test.rb @@ -12,33 +12,33 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase } end - # The load balancer is a kamal-proxy container, so it boots with the proxy's - # full run surface: state volume at the path kamal-proxy actually reads, + # The load balancer is a dash-proxy container, so it boots with the proxy's + # full run surface: state volume at the path dash-proxy actually reads, # apps-config mount, and the explicit run command. test "run" do assert_equal \ - "docker run --name load-balancer --network kamal --detach --restart unless-stopped --label org.opencontainers.image.title=kamal-loadbalancer #{digest_label} --volume kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name load-balancer --network dash --detach --restart unless-stopped --label org.opencontainers.image.title=dash-loadbalancer #{digest_label} --volume dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "run honors proxy.run.publish false and options" do @config[:proxy]["run"] = { "publish" => false, "options" => { "label" => [ "traefik.enable=true" ] } } assert_equal \ - "docker run --name load-balancer --network kamal --detach --restart unless-stopped --label org.opencontainers.image.title=kamal-loadbalancer #{digest_label} --volume kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --log-opt max-size=10m --label \"traefik.enable=true\" ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name load-balancer --network dash --detach --restart unless-stopped --label org.opencontainers.image.title=dash-loadbalancer #{digest_label} --volume dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --log-opt max-size=10m --label \"traefik.enable=true\" ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "run honors custom publish ports" do @config[:proxy]["run"] = { "http_port" => 8080, "https_port" => 8443 } assert_equal \ - "docker run --name load-balancer --network kamal --detach --restart unless-stopped --label org.opencontainers.image.title=kamal-loadbalancer #{digest_label} --volume kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 8080:80 --publish 8443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name load-balancer --network dash --detach --restart unless-stopped --label org.opencontainers.image.title=dash-loadbalancer #{digest_label} --volume dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 8080:80 --publish 8443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end # B3 of the layering work: the edge terminates TLS and owns the cache, so it # must be able to issue certificates (acme) and reach the cache store — both # ride in the run command and the env file, which the LB never got before. - test "run carries the kamal-proxy run command surface to the load balancer" do + test "run carries the dash-proxy run command surface to the load balancer" do @config[:proxy]["run"] = { "metrics_port" => 9090, "cache" => { "store" => "redis://cache.example.com:6379/0" }, @@ -49,7 +49,7 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase assert_match "--expose=9090", command assert_match "--env-file .dash/proxy/secrets.env", command - assert_match "kamal-proxy run --metrics-port \"9090\" --recheck-targets-on-restore --acme-email=\"admin@example.com\"", command + assert_match "dash-proxy run --metrics-port \"9090\" --recheck-targets-on-restore --acme-email=\"admin@example.com\"", command # The store reaches the edge through the env file, not the command line. assert_no_match(/cache.example.com/, command) @@ -74,10 +74,10 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase command = new_command.run.join(" ") - assert_match "docker run --name kamal-proxy", command - assert_match "--label org.opencontainers.image.title=kamal-proxy", command - assert_match "--volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", command - assert_match "--volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config", command + assert_match "docker run --name dash-proxy", command + assert_match "--label org.opencontainers.image.title=dash-proxy", command + assert_match "--volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy", command + assert_match "--volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config", command end # The digest must move when anything the container was booted with moves — @@ -105,27 +105,27 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase test "start_or_run" do assert_equal \ - "docker container start load-balancer || docker run --name load-balancer --network kamal --detach --restart unless-stopped --label org.opencontainers.image.title=kamal-loadbalancer #{digest_label} --volume kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker container start load-balancer || docker run --name load-balancer --network dash --detach --restart unless-stopped --label org.opencontainers.image.title=dash-loadbalancer #{digest_label} --volume dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.start_or_run.join(" ") end test "deploy with targets" do assert_equal \ - "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(targets: [ "1.1.1.1", "1.1.1.2" ]).join(" ") end test "deploy with targets and ssl" do @config[:proxy]["ssl"] = true assert_equal \ - "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(targets: [ "1.1.1.1", "1.1.1.2" ]).join(" ") end test "deploy with multiple hosts" do @config[:proxy]["hosts"] = [ "app1.example.com", "app2.example.com" ] assert_equal \ - "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80\" --host=\"app1.example.com\" --host=\"app2.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80\" --host=\"app1.example.com\" --host=\"app2.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(targets: [ "1.1.1.1" ]).join(" ") end @@ -136,7 +136,7 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase test "deploy targets the per-host proxies published http port, not app_port" do @config[:proxy]["app_port"] = 3000 assert_equal \ - "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(targets: [ "1.1.1.1", "1.1.1.2" ]).join(" ") end @@ -151,11 +151,11 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase @config[:proxy]["response_timeout"] = 10 @config[:proxy]["path_prefix"] = "/api" assert_equal \ - "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --health-check-interval=\"2s\" --health-check-timeout=\"5s\" --health-check-path=\"/healthz\" --target-timeout=\"10s\" --buffer-requests --buffer-responses --path-prefix=\"/api\" --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --health-check-interval=\"2s\" --health-check-timeout=\"5s\" --health-check-path=\"/healthz\" --target-timeout=\"10s\" --buffer-requests --buffer-responses --path-prefix=\"/api\" --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", new_command.deploy(targets: [ "1.1.1.1" ]).join(" ") end - # The per-app proxies must NOT also get --basic-auth: kamal-proxy deletes the + # The per-app proxies must NOT also get --basic-auth: dash-proxy deletes the # Authorization header once a service enforces it, so the load balancer would # authenticate the client and then forward a credential-less request. test "deploy propagates basic auth to the load balancer only" do @@ -164,7 +164,7 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase command = new_command.deploy(targets: [ "1.1.1.1", "1.1.1.2" ]) assert_equal \ - "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --basic-auth=\"admin:s3cr3t\" --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", + "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --basic-auth=\"admin:s3cr3t\" --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"", command.join(" ") # Printed output redacts the credential, here as on the per-app deploy. @@ -178,7 +178,7 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase @config[:proxy]["ssl"] = true @config[:proxy]["ssl_domains"] = { "source" => "/api/v1/kamal/domains", "interval" => 300, "batch_size" => 5 } assert_equal \ - "docker exec load-balancer kamal-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" --tls-domains-source=\"/api/v1/kamal/domains\" --tls-domains-interval=\"300s\" --tls-domains-batch-size=\"5\"", + "docker exec load-balancer dash-proxy deploy app --target=\"1.1.1.1:80,1.1.1.2:80\" --host=\"app.example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" --tls-domains-source=\"/api/v1/kamal/domains\" --tls-domains-interval=\"300s\" --tls-domains-batch-size=\"5\"", new_command.deploy(targets: [ "1.1.1.1", "1.1.1.2" ]).join(" ") end @@ -244,19 +244,19 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase # lives on the load balancer - registered under the bare service name. test "cache stats" do assert_equal \ - "docker exec load-balancer kamal-proxy cache stats --count", + "docker exec load-balancer dash-proxy cache stats --count", new_command.cache_stats(count: true).join(" ") end test "cache purge" do assert_equal \ - "docker exec load-balancer kamal-proxy cache purge app", + "docker exec load-balancer dash-proxy cache purge app", new_command.cache_purge("app").join(" ") end test "domains" do assert_equal \ - "docker exec load-balancer kamal-proxy domains list", + "docker exec load-balancer dash-proxy domains list", new_command.domains("list").join(" ") end @@ -314,40 +314,47 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase new_command.follow_logs(host: "lb.example.com", grep: "error") end - test "remove_container" do + # Both the current and the pre-rename title are pruned, or a container + # created before stage 3c survives and the following `docker run` collides on + # the name. Docker ANDs multiple `--filter label=` values, so it is two + # chained commands rather than one filter with two values. + test "remove_container prunes both the current and the legacy title" do assert_equal \ + "docker container prune --force --filter label=org.opencontainers.image.title=dash-loadbalancer && " \ "docker container prune --force --filter label=org.opencontainers.image.title=kamal-loadbalancer", new_command.remove_container.join(" ") end - # On a shared proxy host the container is created with the kamal-proxy title - # label, so pruning by the kamal-loadbalancer label would leave it behind and + # On a shared proxy host the container is created with the dash-proxy title + # label, so pruning by the dash-loadbalancer label would leave it behind and # the following `docker run` would collide on the container name. test "remove_container on a proxy host prunes by the label it was created with" do @config[:proxy]["loadbalancer"] = "1.1.1.1" assert_equal \ + "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy && " \ "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", new_command.remove_container.join(" ") end # Image label filters match labels baked into the image, and the load balancer - # runs the kamal-proxy image - kamal-loadbalancer never matched anything. - test "remove_image prunes the kamal-proxy image" do + # runs the dash-proxy image - dash-loadbalancer never matched anything. + test "remove_image prunes the dash-proxy image, current and legacy title" do assert_equal \ + "docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy && " \ "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", new_command.remove_image.join(" ") end test "list" do assert_equal \ - "docker exec load-balancer kamal-proxy list", + "docker exec load-balancer dash-proxy list", new_command.list.join(" ") end test "list json" do assert_equal \ - "docker exec load-balancer kamal-proxy list --json", + "docker exec load-balancer dash-proxy list --json", new_command.list(json: true).join(" ") end @@ -430,39 +437,39 @@ class CommandsLoadbalancerTest < ActiveSupport::TestCase test "export certs through the running loadbalancer" do assert_equal \ - "docker exec load-balancer kamal-proxy export certs /home/kamal-proxy/.apps-config/certs-export.tar.gz", + "docker exec load-balancer dash-proxy export certs /home/dash-proxy/.apps-config/certs-export.tar.gz", new_command.export_certs.join(" ") end test "export certs offline via a one-off container" do assert_equal \ - "docker run --rm --volume kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy " \ - "--volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config " \ + "docker run --rm --volume dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy " \ + "--volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config " \ "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} " \ - "kamal-proxy export certs /home/kamal-proxy/.apps-config/certs-export.tar.gz", + "dash-proxy export certs /home/dash-proxy/.apps-config/certs-export.tar.gz", new_command.export_certs_offline.join(" ") end - # A loadbalancer sharing a proxy host shares the kamal-proxy container and + # A loadbalancer sharing a proxy host shares the dash-proxy container and # its config volume, so the transfer must target those. test "cert transfer targets the shared volume on a proxy host" do @config[:proxy]["loadbalancer"] = "1.1.1.1" - assert_match "docker exec kamal-proxy kamal-proxy export certs", new_command.export_certs.join(" ") - assert_match "--volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", new_command.export_certs_offline.join(" ") + assert_match "docker exec dash-proxy dash-proxy export certs", new_command.export_certs.join(" ") + assert_match "--volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy", new_command.export_certs_offline.join(" ") end test "import certs from a traefik acme.json" do assert_equal \ - "docker run --rm --interactive --volume kamal-loadbalancer-config:/home/kamal-proxy/.config/kamal-proxy " \ + "docker run --rm --interactive --volume dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy " \ "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} " \ - "sh -c 'cat > /tmp/kamal-cert-import && kamal-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\"' " \ + "sh -c 'cat > /tmp/kamal-cert-import && dash-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\"' " \ "< .dash/proxy/certs-import", new_command.import_certs(traefik_acme: true).join(" ") end test "import certs restores an archive" do - assert_match "kamal-proxy import certs --archive=\"/tmp/kamal-cert-import\"", + assert_match "dash-proxy import certs --archive=\"/tmp/kamal-cert-import\"", new_command.import_certs.join(" ") end diff --git a/test/commands/proxy_test.rb b/test/commands/proxy_test.rb index eed7a4b9..394029ad 100644 --- a/test/commands/proxy_test.rb +++ b/test/commands/proxy_test.rb @@ -15,7 +15,7 @@ class CommandsProxyTest < ActiveSupport::TestCase test "run" do assert_equal \ - "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config", + "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config", new_command.run.join(" ") end @@ -23,85 +23,91 @@ class CommandsProxyTest < ActiveSupport::TestCase @config.delete(:proxy) assert_equal \ - "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config", + "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config", new_command.run.join(" ") end test "proxy start" do assert_equal \ - "docker container start kamal-proxy", + "docker container start dash-proxy", new_command.start.join(" ") end test "proxy stop" do assert_equal \ - "docker container stop kamal-proxy", + "docker container stop dash-proxy", new_command.stop.join(" ") end test "proxy info" do assert_equal \ - "docker ps --filter 'name=^kamal-proxy$'", + "docker ps --filter 'name=^dash-proxy$'", new_command.info.join(" ") end test "proxy logs" do assert_equal \ - "docker logs kamal-proxy --timestamps 2>&1", + "docker logs dash-proxy --timestamps 2>&1", new_command.logs.join(" ") end test "proxy logs since 2h" do assert_equal \ - "docker logs kamal-proxy --since 2h --timestamps 2>&1", + "docker logs dash-proxy --since 2h --timestamps 2>&1", new_command.logs(since: "2h").join(" ") end test "proxy logs last 10 lines" do assert_equal \ - "docker logs kamal-proxy --tail 10 --timestamps 2>&1", + "docker logs dash-proxy --tail 10 --timestamps 2>&1", new_command.logs(lines: 10).join(" ") end test "proxy logs without timestamps" do assert_equal \ - "docker logs kamal-proxy 2>&1", + "docker logs dash-proxy 2>&1", new_command.logs(timestamps: false).join(" ") end test "proxy logs with grep hello!" do assert_equal \ - "docker logs kamal-proxy --timestamps 2>&1 | grep 'hello!'", + "docker logs dash-proxy --timestamps 2>&1 | grep 'hello!'", new_command.logs(grep: "hello!").join(" ") end - test "proxy remove container" do + # Docker ANDs multiple `--filter label=` values, so covering both the current + # and the pre-rename title is two chained commands. Without the legacy pass a + # host that has not been through the stage-3c rename keeps its old container + # and image after `dash proxy remove`. + test "proxy remove container prunes both the current and the legacy title" do assert_equal \ + "docker container prune --force --filter label=org.opencontainers.image.title=dash-proxy && " \ "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", new_command.remove_container.join(" ") end - test "proxy remove image" do + test "proxy remove image prunes both the current and the legacy title" do assert_equal \ + "docker image prune --all --force --filter label=org.opencontainers.image.title=dash-proxy && " \ "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", new_command.remove_image.join(" ") end test "proxy follow logs" do assert_equal \ - "ssh -t root@1.1.1.1 -p 22 'docker logs kamal-proxy --timestamps --tail 10 --follow 2>&1'", + "ssh -t root@1.1.1.1 -p 22 'docker logs dash-proxy --timestamps --tail 10 --follow 2>&1'", new_command.follow_logs(host: @config[:servers].first) end test "proxy follow logs with grep hello!" do assert_equal \ - "ssh -t root@1.1.1.1 -p 22 'docker logs kamal-proxy --timestamps --tail 10 --follow 2>&1 | grep \"hello!\"'", + "ssh -t root@1.1.1.1 -p 22 'docker logs dash-proxy --timestamps --tail 10 --follow 2>&1 | grep \"hello!\"'", new_command.follow_logs(host: @config[:servers].first, grep: "hello!") end test "version" do assert_equal \ - "docker inspect kamal-proxy --format '{{.Config.Image}}' | awk -F: '{print $NF}'", + "docker inspect dash-proxy --format '{{.Config.Image}}' | awk -F: '{print $NF}'", new_command.version.join(" ") end @@ -168,75 +174,75 @@ class CommandsProxyTest < ActiveSupport::TestCase test "registry run config" do @config[:proxy] = { "run" => { "registry" => "registry:4443" } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m registry:4443/ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m registry:4443/ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "repository run config" do @config[:proxy] = { "run" => { "repository" => "custom/repo" } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m custom/repo:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m custom/repo:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "image_version run config" do @config[:proxy] = { "run" => { "version" => "v1.2.3" } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:v1.2.3 kamal-proxy run --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:v1.2.3 dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "bind_ips run config" do @config[:proxy] = { "run" => { "bind_ips" => [ "0.0.0.0", "127.0.0.1" ] } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 0.0.0.0:80:80 --publish 0.0.0.0:443:443 --publish 127.0.0.1:80:80 --publish 127.0.0.1:443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 0.0.0.0:80:80 --publish 0.0.0.0:443:443 --publish 127.0.0.1:80:80 --publish 127.0.0.1:443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "log_max_size run config" do @config[:proxy] = { "run" => { "log_max_size" => "50m" } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=50m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=50m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "domains" do assert_equal \ - "docker exec kamal-proxy kamal-proxy domains refresh", + "docker exec dash-proxy dash-proxy domains refresh", new_command.domains("refresh").join(" ") end test "debug run config" do @config[:proxy] = { "run" => { "debug" => true } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --debug --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --debug --recheck-targets-on-restore", new_command.run.join(" ") end test "metrics_port run config" do @config[:proxy] = { "run" => { "metrics_port" => 9090 } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9090 ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --metrics-port \"9090\" --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m --expose=9090 ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --metrics-port \"9090\" --recheck-targets-on-restore", new_command.run.join(" ") end test "don't publish run config" do @config[:proxy] = { "run" => { "publish" => false } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run.join(" ") end test "run with config digest label" do @config[:proxy] = { "run" => { "log_max_size" => "10m" } } assert_equal \ - "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --label org.dash.proxy-config-digest=abc123 --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore", + "docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --label org.dash.proxy-config-digest=abc123 --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore", new_command.run(digest: "abc123").join(" ") end test "run with config digest label on legacy boot config path" do assert_equal \ - "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --label org.dash.proxy-config-digest=abc123 --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config", + "echo $(cat .dash/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") $(cat .dash/proxy/run_command 2> /dev/null || echo \"\") | xargs docker run --name dash-proxy --network dash --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --label org.dash.proxy-config-digest=abc123 --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config", new_command.run(digest: "abc123").join(" ") end @@ -249,7 +255,7 @@ class CommandsProxyTest < ActiveSupport::TestCase test "stop with timeout" do assert_equal \ - "docker container stop --time 40 kamal-proxy", + "docker container stop --time 40 dash-proxy", new_command.stop(timeout: 40).join(" ") end @@ -268,127 +274,127 @@ class CommandsProxyTest < ActiveSupport::TestCase test "list" do assert_equal \ - "docker exec kamal-proxy kamal-proxy list", + "docker exec dash-proxy dash-proxy list", new_command.list.join(" ") end test "list json" do assert_equal \ - "docker exec kamal-proxy kamal-proxy list --json", + "docker exec dash-proxy dash-proxy list --json", new_command.list(json: true).join(" ") end test "cache stats" do assert_equal \ - "docker exec kamal-proxy kamal-proxy cache stats", + "docker exec dash-proxy dash-proxy cache stats", new_command.cache_stats.join(" ") end test "cache stats with count and json" do assert_equal \ - "docker exec kamal-proxy kamal-proxy cache stats --count --json", + "docker exec dash-proxy dash-proxy cache stats --count --json", new_command.cache_stats(count: true, json: true).join(" ") end test "cache purge" do assert_equal \ - "docker exec kamal-proxy kamal-proxy cache purge app-web", + "docker exec dash-proxy dash-proxy cache purge app-web", new_command.cache_purge("app-web").join(" ") end test "cache purge with path prefix" do assert_equal \ - "docker exec kamal-proxy kamal-proxy cache purge app-web --path-prefix \"/assets\"", + "docker exec dash-proxy dash-proxy cache purge app-web --path-prefix \"/assets\"", new_command.cache_purge("app-web", path_prefix: "/assets").join(" ") end test "mount_destinations" do assert_equal \ - "docker inspect kamal-proxy --format '{{range .Mounts}}{{println .Destination}}{{end}}'", + "docker inspect dash-proxy --format '{{range .Mounts}}{{println .Destination}}{{end}}'", new_command.mount_destinations.join(" ") end test "config_digest reads the new label and falls back to the legacy one" do assert_equal \ - "docker inspect kamal-proxy --format '{{ with index .Config.Labels \"org.dash.proxy-config-digest\" }}{{ . }}{{ else }}{{ index .Config.Labels \"org.kamal.proxy-config-digest\" }}{{ end }}'", + "docker inspect dash-proxy --format '{{ with index .Config.Labels \"org.dash.proxy-config-digest\" }}{{ . }}{{ else }}{{ index .Config.Labels \"org.kamal.proxy-config-digest\" }}{{ end }}'", new_command.config_digest.join(" ") end test "container_id" do assert_equal \ - "docker container ls --all --filter 'name=^kamal-proxy$' --quiet", + "docker container ls --all --filter 'name=^dash-proxy$' --quiet", new_command.container_id.join(" ") end test "run with port_holder joins the holder namespace without publishing" do @config[:proxy] = { "run" => { "port_holder" => true } } assert_equal \ - "docker run --name kamal-proxy --network container:kamal-proxy-net --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy run --recheck-targets-on-restore --reuse-port", + "docker run --name dash-proxy --network container:dash-proxy-net --detach --restart unless-stopped --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy --volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy run --recheck-targets-on-restore --reuse-port", new_command.run.join(" ") end test "run with a custom container name" do @config[:proxy] = { "run" => { "port_holder" => true } } assert_match \ - "docker run --name kamal-proxy-next --network container:kamal-proxy-net", - new_command.run(name: "kamal-proxy-next").join(" ") + "docker run --name dash-proxy-next --network container:dash-proxy-net", + new_command.run(name: "dash-proxy-next").join(" ") end test "run_holder" do @config[:proxy] = { "run" => { "port_holder" => true } } assert_equal \ - "docker run --name kamal-proxy-net --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} kamal-proxy hold", + "docker run --name dash-proxy-net --network dash --detach --restart unless-stopped --publish 80:80 --publish 443:443 --log-opt max-size=10m ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} dash-proxy hold", new_command.run_holder.join(" ") end test "start_holder_or_run" do @config[:proxy] = { "run" => { "port_holder" => true } } assert_match \ - "docker container start kamal-proxy-net || docker run --name kamal-proxy-net", + "docker container start dash-proxy-net || docker run --name dash-proxy-net", new_command.start_holder_or_run.join(" ") end test "holder_container_id" do @config[:proxy] = { "run" => { "port_holder" => true } } assert_equal \ - "docker container ls --filter 'name=^kamal-proxy-net$' --quiet", + "docker container ls --filter 'name=^dash-proxy-net$' --quiet", new_command.holder_container_id.join(" ") end test "disable_restart" do assert_equal \ - "docker update --restart=no kamal-proxy", + "docker update --restart=no dash-proxy", new_command.disable_restart.join(" ") end test "drain" do assert_equal \ - "docker exec kamal-proxy kamal-proxy drain --drain-timeout=30s", + "docker exec dash-proxy dash-proxy drain --drain-timeout=30s", new_command.drain(timeout: 30).join(" ") end test "wait_for_exit" do assert_equal \ - "docker wait kamal-proxy", + "docker wait dash-proxy", new_command.wait_for_exit.join(" ") end test "remove_stopped_container" do assert_equal \ - "docker container rm kamal-proxy-next", - new_command.remove_stopped_container(name: "kamal-proxy-next").join(" ") + "docker container rm dash-proxy-next", + new_command.remove_stopped_container(name: "dash-proxy-next").join(" ") end test "promote_next_container" do assert_equal \ - "docker container rename kamal-proxy-next kamal-proxy", + "docker container rename dash-proxy-next dash-proxy", new_command.promote_next_container.join(" ") end test "list with a custom container name" do assert_equal \ - "docker exec kamal-proxy-next kamal-proxy list", - new_command.list(name: "kamal-proxy-next").join(" ") + "docker exec dash-proxy-next dash-proxy list", + new_command.list(name: "dash-proxy-next").join(" ") end # Certificate store transfer (dash proxy export_certs / import_certs). The @@ -397,7 +403,7 @@ class CommandsProxyTest < ActiveSupport::TestCase test "export certs through the running proxy" do assert_equal \ - "docker exec kamal-proxy kamal-proxy export certs /home/kamal-proxy/.apps-config/certs-export.tar.gz", + "docker exec dash-proxy dash-proxy export certs /home/dash-proxy/.apps-config/certs-export.tar.gz", new_command.export_certs.join(" ") end @@ -405,20 +411,20 @@ class CommandsProxyTest < ActiveSupport::TestCase @config[:proxy] = { "run" => { "log_max_size" => "10m" } } assert_equal \ - "docker run --rm --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy " \ - "--volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config " \ + "docker run --rm --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy " \ + "--volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config " \ "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} " \ - "kamal-proxy export certs /home/kamal-proxy/.apps-config/certs-export.tar.gz", + "dash-proxy export certs /home/dash-proxy/.apps-config/certs-export.tar.gz", new_command.export_certs_offline.join(" ") end test "export certs offline falls back to the boot config image without a run config" do assert_equal \ - "docker run --rm --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy " \ - "--volume $PWD/.dash/proxy/apps-config:/home/kamal-proxy/.apps-config " \ + "docker run --rm --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy " \ + "--volume $PWD/.dash/proxy/apps-config:/home/dash-proxy/.apps-config " \ "$(cat .dash/proxy/image 2> /dev/null || echo \"ghcr.io/zoolutions/dash-proxy\"):" \ "$(cat .dash/proxy/image_version 2> /dev/null || echo \"#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}\") " \ - "kamal-proxy export certs /home/kamal-proxy/.apps-config/certs-export.tar.gz", + "dash-proxy export certs /home/dash-proxy/.apps-config/certs-export.tar.gz", new_command.export_certs_offline.join(" ") end @@ -429,9 +435,9 @@ class CommandsProxyTest < ActiveSupport::TestCase @config[:proxy] = { "run" => { "log_max_size" => "10m" } } assert_equal \ - "docker run --rm --interactive --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy " \ + "docker run --rm --interactive --volume dash-proxy-config:/home/dash-proxy/.config/dash-proxy " \ "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION} " \ - "sh -c 'cat > /tmp/kamal-cert-import && kamal-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\"' " \ + "sh -c 'cat > /tmp/kamal-cert-import && dash-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\"' " \ "< .dash/proxy/certs-import", new_command.import_certs(traefik_acme: true).join(" ") end @@ -439,7 +445,7 @@ class CommandsProxyTest < ActiveSupport::TestCase test "import certs with a resolver" do @config[:proxy] = { "run" => { "log_max_size" => "10m" } } - assert_match "kamal-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\" --resolver=\"letsencrypt\"", + assert_match "dash-proxy import certs --traefik-acme=\"/tmp/kamal-cert-import\" --resolver=\"letsencrypt\"", new_command.import_certs(traefik_acme: true, resolver: "letsencrypt").join(" ") end @@ -457,14 +463,14 @@ class CommandsProxyTest < ActiveSupport::TestCase test "import certs restores an archive with force" do @config[:proxy] = { "run" => { "log_max_size" => "10m" } } - assert_match "kamal-proxy import certs --archive=\"/tmp/kamal-cert-import\" --force", + assert_match "dash-proxy import certs --archive=\"/tmp/kamal-cert-import\" --force", new_command.import_certs(force: true).join(" ") end test "import certs verifies an archive" do @config[:proxy] = { "run" => { "log_max_size" => "10m" } } - assert_match "kamal-proxy import certs --archive=\"/tmp/kamal-cert-import\" --verify", + assert_match "dash-proxy import certs --archive=\"/tmp/kamal-cert-import\" --verify", new_command.import_certs(verify: true).join(" ") end @@ -479,4 +485,49 @@ class CommandsProxyTest < ActiveSupport::TestCase def new_command Dash::Commands::Proxy.new(Dash::Configuration.new(@config, version: "123"), host: "1.1.1.1") end + + # --- Stage 3c migrations ------------------------------------------------- + + # The guard is negated and leads the chain because shell && and || share + # precedence and associate left: written as `exists || legacy && create && + # copy` it parses as `((exists || legacy) && create) && copy`, which re-copies + # the legacy volume over live state on every deploy. + test "copy_legacy_config_volume skips itself once the new volume exists" do + command = new_command.copy_legacy_config_volume.join(" ") + + assert command.start_with?("! docker volume inspect dash-proxy-config"), + "the guard must lead the chain, or the copy runs even when the volume already exists" + assert command.end_with?("|| true"), + "a host with neither volume must not fail its deploy" + end + + test "copy_legacy_config_volume copies the pre-rename volume verbatim" do + command = new_command.copy_legacy_config_volume.join(" ") + + assert_match "docker volume inspect kamal-proxy-config", command + assert_match "docker volume create dash-proxy-config", command + assert_match "--volume kamal-proxy-config:/from", command + assert_match "--volume dash-proxy-config:/to", command + assert_match "cp -a /from/. /to/", command + assert_match "--user root", command, "the image's own user cannot write the destination volume" + end + + # A rename means the old container has to release ports 80/443 before the new + # one can claim them; no port-holder handoff spans two container names. + test "remove_legacy_container stops and removes the pre-rename container" do + command = new_command.remove_legacy_container(timeout: 30).join(" ") + + assert_match "docker container inspect kamal-proxy > /dev/null 2>&1", command + assert_match "docker container stop --time=30 kamal-proxy", command + assert_match "docker container rm kamal-proxy", command + assert command.end_with?("|| true"), "a host with no legacy container must not fail its deploy" + end + + test "remove_legacy_holder_container removes the pre-rename port holder" do + command = new_command.remove_legacy_holder_container.join(" ") + + assert_match "docker container inspect kamal-proxy-net", command + assert_match "docker container rm --force kamal-proxy-net", command + assert command.end_with?("|| true") + end end diff --git a/test/configuration/accessory_test.rb b/test/configuration/accessory_test.rb index 47d89d91..6834f396 100644 --- a/test/configuration/accessory_test.rb +++ b/test/configuration/accessory_test.rb @@ -346,7 +346,7 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase end test "network_args default" do - assert_equal [ "--network", "kamal" ], @config.accessory(:mysql).network_args + assert_equal [ "--network", "dash" ], @config.accessory(:mysql).network_args end test "network_args with configured options" do diff --git a/test/configuration/proxy/access_control_test.rb b/test/configuration/proxy/access_control_test.rb index 2414e208..5b99db06 100644 --- a/test/configuration/proxy/access_control_test.rb +++ b/test/configuration/proxy/access_control_test.rb @@ -111,7 +111,7 @@ class ConfigurationProxyAccessControlTest < ActiveSupport::TestCase "trusting every address means trusting every client to speak for someone else", error.message end - # Dependency rules kamal-proxy enforces after the deploy reaches a host + # Dependency rules dash-proxy enforces after the deploy reaches a host test "trusted_proxies without allow_ips or rate_limit is rejected" do error = assert_raises(Dash::ConfigurationError) do @@ -130,7 +130,7 @@ class ConfigurationProxyAccessControlTest < ActiveSupport::TestCase "or the header would be ignored while appearing to be honored", error.message end - # Unconditionally, not only when allow_ips/rate_limit key on it: kamal-proxy + # Unconditionally, not only when allow_ips/rate_limit key on it: dash-proxy # rewrites the client address (and X-Forwarded-For) from the header for # logging and everything downstream, so honoring it from untrusted peers is # a client-spoofable identity - exactly what the shipped docs say it is not. @@ -165,7 +165,7 @@ class ConfigurationProxyAccessControlTest < ActiveSupport::TestCase assert_raises(Dash::ConfigurationError) { configuration "rate_limit" => { "requests" => 100, "burst" => -1 } }.message end - # kamal-proxy serves the health check path without an address check or a rate + # dash-proxy serves the health check path without an address check or a rate # limit, so leaving it at / would quietly unrestrict the whole service. test "a root healthcheck path is rejected alongside access control" do error = assert_raises(Dash::ConfigurationError) do diff --git a/test/configuration/proxy/acme_test.rb b/test/configuration/proxy/acme_test.rb index de1a7068..b9676ab8 100644 --- a/test/configuration/proxy/acme_test.rb +++ b/test/configuration/proxy/acme_test.rb @@ -7,16 +7,16 @@ class ConfigurationProxyAcmeTest < ActiveSupport::TestCase end test "no acme block leaves the run command untouched" do - assert_equal "kamal-proxy run --recheck-targets-on-restore", run_config({}).run_command + assert_equal "dash-proxy run --recheck-targets-on-restore", run_config({}).run_command end - test "acme settings become kamal-proxy run flags" do + test "acme settings become dash-proxy run flags" do run = run_config \ "email" => "admin@example.com", "dns_provider" => "cloudflare", "directory" => "https://acme-staging-v02.api.letsencrypt.org/directory" - assert_equal "kamal-proxy run --recheck-targets-on-restore " \ + assert_equal "dash-proxy run --recheck-targets-on-restore " \ "--acme-email=\"admin@example.com\" --acme-dns-provider=\"cloudflare\" " \ "--acme-directory=\"https://acme-staging-v02.api.letsencrypt.org/directory\"", run.run_command @@ -103,7 +103,7 @@ class ConfigurationProxyAcmeTest < ActiveSupport::TestCase assert_equal Dash::Configuration::Proxy::Run.digest( "ghcr.io/zoolutions/dash-proxy:#{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}", - "kamal-proxy run --recheck-targets-on-restore", + "dash-proxy run --recheck-targets-on-restore", *Dash::Configuration::Proxy::Run.new(config, run_config: {}).docker_options_args ), Dash::Configuration::Proxy::Run.new(config, run_config: {}).config_digest end @@ -148,7 +148,7 @@ class ConfigurationProxyAcmeTest < ActiveSupport::TestCase "platform.example" => "cloudflare", "legacy.example" => "hetzner", "default" => "route53" } - assert_equal "kamal-proxy run --recheck-targets-on-restore " \ + assert_equal "dash-proxy run --recheck-targets-on-restore " \ "--acme-email=\"admin@example.com\" " \ "--acme-dns-provider=\"platform.example=cloudflare\" " \ "--acme-dns-provider=\"legacy.example=hetzner\" " \ diff --git a/test/configuration/proxy/boot_test.rb b/test/configuration/proxy/boot_test.rb index ec37489c..5f29ae9e 100644 --- a/test/configuration/proxy/boot_test.rb +++ b/test/configuration/proxy/boot_test.rb @@ -20,12 +20,12 @@ class ConfigurationProxyBootTest < ActiveSupport::TestCase test "proxy directories" do assert_equal ".dash/proxy/apps-config", @proxy_boot_config.apps_directory - assert_equal "/home/kamal-proxy/.apps-config", @proxy_boot_config.apps_container_directory + assert_equal "/home/dash-proxy/.apps-config", @proxy_boot_config.apps_container_directory assert_equal ".dash/proxy/apps-config/app", @proxy_boot_config.app_directory - assert_equal "/home/kamal-proxy/.apps-config/app", @proxy_boot_config.app_container_directory + assert_equal "/home/dash-proxy/.apps-config/app", @proxy_boot_config.app_container_directory assert_equal ".dash/proxy/apps-config/app/error_pages", @proxy_boot_config.error_pages_directory - assert_equal "/home/kamal-proxy/.apps-config/app/error_pages", @proxy_boot_config.error_pages_container_directory + assert_equal "/home/dash-proxy/.apps-config/app/error_pages", @proxy_boot_config.error_pages_container_directory assert_equal ".dash/proxy/apps-config/app/tls", @proxy_boot_config.tls_directory - assert_equal "/home/kamal-proxy/.apps-config/app/tls", @proxy_boot_config.tls_container_directory + assert_equal "/home/dash-proxy/.apps-config/app/tls", @proxy_boot_config.tls_container_directory end end diff --git a/test/configuration/proxy/cache_test.rb b/test/configuration/proxy/cache_test.rb index e62cc401..acdd8294 100644 --- a/test/configuration/proxy/cache_test.rb +++ b/test/configuration/proxy/cache_test.rb @@ -22,7 +22,7 @@ class ConfigurationProxyCacheTest < ActiveSupport::TestCase end # Everything but --cache stays out until its key is set: the defaults live in - # kamal-proxy, the same convention healthcheck_path follows. + # dash-proxy, the same convention healthcheck_path follows. test "enabled alone emits only --cache" do options = deploy_options "enabled" => true @@ -60,18 +60,18 @@ class ConfigurationProxyCacheTest < ActiveSupport::TestCase # Store — proxy.run.cache, proxy-wide test "no run cache block leaves the run command unchanged" do - assert_equal "kamal-proxy run --recheck-targets-on-restore", run_config({}).run_command + assert_equal "dash-proxy run --recheck-targets-on-restore", run_config({}).run_command end - test "store tuning becomes kamal-proxy run flags, the store itself never does" do + test "store tuning becomes dash-proxy run flags, the store itself never does" do run = run_config "store" => "redis://cache.example.com:6379/0", "store_timeout" => 2, "memory_size" => 134_217_728 - assert_equal "kamal-proxy run --recheck-targets-on-restore " \ + assert_equal "dash-proxy run --recheck-targets-on-restore " \ "--cache-store-timeout \"2s\" --cache-memory-size \"134217728\"", run.run_command end # A store URL may carry credentials, and the run command lands in host - # process listings and kamal's audit log. kamal-proxy reads CACHE_STORE from + # process listings and kamal's audit log. dash-proxy reads CACHE_STORE from # its environment as the --cache-store default, so the URL travels in the # 0600 proxy secrets env file instead - the acme mechanism made shared. test "the store travels in the proxy secrets env file, never on the command line" do @@ -114,7 +114,7 @@ class ConfigurationProxyCacheTest < ActiveSupport::TestCase error = assert_raises(Dash::ConfigurationError) { configuration "cache" => { "max_ttl" => 300 } } assert_equal "proxy/cache: max_ttl has no effect without enabled: true - " \ - "kamal-proxy ignores the cache policy entirely when --cache is absent", error.message + "dash-proxy ignores the cache policy entirely when --cache is absent", error.message end test "enabled false with policy keys is the same error" do @@ -123,7 +123,7 @@ class ConfigurationProxyCacheTest < ActiveSupport::TestCase end assert_equal "proxy/cache: vary_cookies has no effect without enabled: true - " \ - "kamal-proxy ignores the cache policy entirely when --cache is absent", error.message + "dash-proxy ignores the cache policy entirely when --cache is absent", error.message end test "an unsupported store fails at config time" do diff --git a/test/configuration/proxy/compress_test.rb b/test/configuration/proxy/compress_test.rb index dd04ee39..4e28f53d 100644 --- a/test/configuration/proxy/compress_test.rb +++ b/test/configuration/proxy/compress_test.rb @@ -70,7 +70,7 @@ class ConfigurationProxyCompressTest < ActiveSupport::TestCase assert_empty deploy_options({}).keys.grep(/compress/) end - # Validation — kamal-proxy rejects each of these, after the SSH round-trip + # Validation — dash-proxy rejects each of these, after the SSH round-trip test "min_length without compression is a config error" do error = assert_raises(Dash::ConfigurationError) { configuration "compress" => { "min_length" => 1024 } } diff --git a/test/configuration/proxy/deny_list_test.rb b/test/configuration/proxy/deny_list_test.rb index bdf57a39..1eed27af 100644 --- a/test/configuration/proxy/deny_list_test.rb +++ b/test/configuration/proxy/deny_list_test.rb @@ -1,6 +1,6 @@ require "test_helper" -# proxy/deny_ips and proxy/deny_user_agents: kamal-proxy's --deny-ip and +# proxy/deny_ips and proxy/deny_user_agents: dash-proxy's --deny-ip and # --deny-user-agent. Edge disposition, beside allow_ips and rate_limit — behind # a loadbalancer the per-host proxies only ever see the LB as their peer. class ConfigurationProxyDenyListTest < ActiveSupport::TestCase @@ -70,7 +70,7 @@ class ConfigurationProxyDenyListTest < ActiveSupport::TestCase assert_raises(Dash::ConfigurationError) { configuration "deny_user_agents" => [ 42 ] } end - # kamal-proxy serves the health check path without any of the address checks, + # dash-proxy serves the health check path without any of the address checks, # so a root health path would leave the whole service open to denied clients. test "a root healthcheck path is rejected alongside deny_ips" do assert_raises(Dash::ConfigurationError) do diff --git a/test/configuration/proxy/lifecycle_test.rb b/test/configuration/proxy/lifecycle_test.rb index 2e990403..345207eb 100644 --- a/test/configuration/proxy/lifecycle_test.rb +++ b/test/configuration/proxy/lifecycle_test.rb @@ -122,7 +122,7 @@ class ConfigurationProxyLifecycleTest < ActiveSupport::TestCase test "sleep without a docker socket names the key that is missing" do error = assert_raises(Dash::ConfigurationError) { configuration "sleep" => { "after" => 300 } } - assert_equal "Role(s) web: proxy/sleep requires proxy/run/docker_socket - kamal-proxy can only stop and " \ + assert_equal "Role(s) web: proxy/sleep requires proxy/run/docker_socket - dash-proxy can only stop and " \ "start containers through the container runtime socket, and it is not mounted into the proxy without it", error.message end diff --git a/test/configuration/proxy/redirects_source_test.rb b/test/configuration/proxy/redirects_source_test.rb index 74e2df7f..cc0ccf9b 100644 --- a/test/configuration/proxy/redirects_source_test.rb +++ b/test/configuration/proxy/redirects_source_test.rb @@ -1,6 +1,6 @@ require "test_helper" -# proxy/redirects_source: the dynamic redirect map (kamal-proxy --redirects-source / +# proxy/redirects_source: the dynamic redirect map (dash-proxy --redirects-source / # --redirects-interval). Edge disposition — redirects answer at the loadbalancer, # like ssl_domains and canonical_host. class ConfigurationProxyRedirectsSourceTest < ActiveSupport::TestCase @@ -65,7 +65,7 @@ class ConfigurationProxyRedirectsSourceTest < ActiveSupport::TestCase end end - # kamal-proxy rejects an interval below MinRedirectsInterval (10s) after the + # dash-proxy rejects an interval below MinRedirectsInterval (10s) after the # SSH round trip; catch it at config time instead. test "redirects_source interval must be an integer of at least 10 seconds" do [ 0, -300, "300", 1.5, 9 ].each do |interval| diff --git a/test/configuration/proxy/run_flags_test.rb b/test/configuration/proxy/run_flags_test.rb index 7b454f72..255d3e62 100644 --- a/test/configuration/proxy/run_flags_test.rb +++ b/test/configuration/proxy/run_flags_test.rb @@ -12,7 +12,7 @@ class ConfigurationProxyRunFlagsTest < ActiveSupport::TestCase end test "no new keys leave the run command byte-identical" do - assert_equal "kamal-proxy run --recheck-targets-on-restore", run_config({}).run_command + assert_equal "dash-proxy run --recheck-targets-on-restore", run_config({}).run_command end test "the named run keys become flags" do @@ -48,7 +48,7 @@ class ConfigurationProxyRunFlagsTest < ActiveSupport::TestCase end test "booleans left false emit nothing, matching the proxy defaults" do - assert_equal "kamal-proxy run --recheck-targets-on-restore", + assert_equal "dash-proxy run --recheck-targets-on-restore", run_config("http3" => false, "reuse_port" => false, "proxy_protocol" => false).run_command end @@ -72,7 +72,7 @@ class ConfigurationProxyRunFlagsTest < ActiveSupport::TestCase end end - # The escape hatch — run.flags is kamal-proxy run, run.options is docker run + # The escape hatch — run.flags is dash-proxy run, run.options is docker run test "run.flags are optionized onto the run command" do command = run_config("flags" => { "some-new-flag" => "value", "another-new-flag" => true }).run_command @@ -126,7 +126,7 @@ class ConfigurationProxyRunFlagsTest < ActiveSupport::TestCase assert_no_match(/exclude-metrics-path/, run_config({}).run_command) end - # Validation — kamal-proxy rejects these in preRun, which kills the container + # Validation — dash-proxy rejects these in preRun, which kills the container # at boot rather than failing the deploy. test "an unknown log_format is rejected" do @@ -154,7 +154,7 @@ class ConfigurationProxyRunFlagsTest < ActiveSupport::TestCase proxy_error("min_tls" => "1.0") end - test "min_tls accepts the spellings kamal-proxy normalizes" do + test "min_tls accepts the spellings dash-proxy normalizes" do assert proxy_config("min_tls" => "tls1_2") assert proxy_config("min_tls" => 1.3) end diff --git a/test/configuration/proxy/run_test.rb b/test/configuration/proxy/run_test.rb index d58c6f75..a2358a66 100644 --- a/test/configuration/proxy/run_test.rb +++ b/test/configuration/proxy/run_test.rb @@ -86,7 +86,7 @@ class ConfigurationProxyRunTest < ActiveSupport::TestCase config = Dash::Configuration.new(base_deploy) run = Dash::Configuration::Proxy::Run.new(config, run_config: {}) - assert_equal "kamal-proxy run --recheck-targets-on-restore", run.run_command + assert_equal "dash-proxy run --recheck-targets-on-restore", run.run_command end test "port_holder defaults to false with kamal network and published ports" do @@ -94,7 +94,7 @@ class ConfigurationProxyRunTest < ActiveSupport::TestCase run = Dash::Configuration::Proxy::Run.new(config, run_config: {}) assert_not run.port_holder? - assert_equal [ "--network", "kamal" ], run.network_args + assert_equal [ "--network", "dash" ], run.network_args assert_match "--publish 80:80", run.docker_options_args.join(" ") assert_no_match(/--reuse-port/, run.run_command) end @@ -104,8 +104,8 @@ class ConfigurationProxyRunTest < ActiveSupport::TestCase run = Dash::Configuration::Proxy::Run.new(config, run_config: { "port_holder" => true }) assert run.port_holder? - assert_equal "kamal-proxy-net", run.holder_container_name - assert_equal [ "--network", "container:kamal-proxy-net" ], run.network_args + assert_equal "dash-proxy-net", run.holder_container_name + assert_equal [ "--network", "container:dash-proxy-net" ], run.network_args assert_no_match(/--publish/, run.docker_options_args.join(" ")) assert_match "--publish 80:80 --publish 443:443", run.holder_docker_args.join(" ") assert_match "--reuse-port", run.run_command diff --git a/test/configuration/proxy/tls_test.rb b/test/configuration/proxy/tls_test.rb index 8d11eecc..4e02f996 100644 --- a/test/configuration/proxy/tls_test.rb +++ b/test/configuration/proxy/tls_test.rb @@ -34,8 +34,8 @@ class ConfigurationProxyTlsTest < ActiveSupport::TestCase proxy = configuration("ssl" => { "client_ca_pem" => "CLIENT_CA_PEM" }, "host" => "example.com").proxy assert_equal ".dash/proxy/apps-config/app/tls/client-ca.pem", proxy.host_client_ca - assert_equal "/home/kamal-proxy/.apps-config/app/tls/client-ca.pem", proxy.container_client_ca - assert_equal "/home/kamal-proxy/.apps-config/app/tls/client-ca.pem", proxy.deploy_options[:"tls-client-ca-path"] + assert_equal "/home/dash-proxy/.apps-config/app/tls/client-ca.pem", proxy.container_client_ca + assert_equal "/home/dash-proxy/.apps-config/app/tls/client-ca.pem", proxy.deploy_options[:"tls-client-ca-path"] assert proxy.client_ca? end @@ -46,7 +46,7 @@ class ConfigurationProxyTlsTest < ActiveSupport::TestCase ) assert_equal ".dash/proxy/apps-config/app/tls/web/client-ca.pem", config.role(:web).proxy.host_client_ca - assert_equal "/home/kamal-proxy/.apps-config/app/tls/web/client-ca.pem", config.role(:web).proxy.container_client_ca + assert_equal "/home/dash-proxy/.apps-config/app/tls/web/client-ca.pem", config.role(:web).proxy.container_client_ca end # Resolved at upload time, not config time - `dash app logs` and `rollback` @@ -74,7 +74,7 @@ class ConfigurationProxyTlsTest < ActiveSupport::TestCase assert_not configuration("ssl" => true, "host" => "example.com").proxy.client_ca? end - # kamal-proxy hard-rejects each of these combinations rather than picking a + # dash-proxy hard-rejects each of these combinations rather than picking a # winner, so the gem fails at config time with the same rules. test "on_demand_url cannot be combined with hosts" do error = assert_raises(Dash::ConfigurationError) do @@ -130,7 +130,7 @@ class ConfigurationProxyTlsTest < ActiveSupport::TestCase assert_not config.proxy.deploy_options.key?(:"tls-client-ca-path") loadbalancer = Dash::Configuration::Loadbalancer.new config: config, proxy_config: proxy_config, secrets: config.secrets - assert_equal "/home/kamal-proxy/.apps-config/app/tls/client-ca.pem", loadbalancer.deploy_options[:"tls-client-ca-path"] + assert_equal "/home/dash-proxy/.apps-config/app/tls/client-ca.pem", loadbalancer.deploy_options[:"tls-client-ca-path"] end private diff --git a/test/configuration/proxy/traffic_test.rb b/test/configuration/proxy/traffic_test.rb index 18fcbc4d..0e6b120b 100644 --- a/test/configuration/proxy/traffic_test.rb +++ b/test/configuration/proxy/traffic_test.rb @@ -41,7 +41,7 @@ class ConfigurationProxyTrafficTest < ActiveSupport::TestCase flag = args.find { |arg| arg.start_with?("--set-response-header=") } - # What the shell will hand kamal-proxy, once it has removed the quoting. + # What the shell will hand dash-proxy, once it has removed the quoting. assert_equal "X-Test: #{value}", unshell(flag.delete_prefix("--set-response-header=")) end @@ -62,7 +62,7 @@ class ConfigurationProxyTrafficTest < ActiveSupport::TestCase assert_equal "proxy/headers/request/set: 'X Bad Name' is not a valid header name", error.message end - # Go carries the host in Request.Host, not the header map, so kamal-proxy + # Go carries the host in Request.Host, not the header map, so dash-proxy # refuses the rule rather than letting it silently do nothing. test "a request rule naming Host is rejected" do error = assert_raises(Dash::ConfigurationError) do @@ -145,7 +145,7 @@ class ConfigurationProxyTrafficTest < ActiveSupport::TestCase assert_equal "www.example.com", options[:"canonical-host"] end - # kamal-proxy rejects the pair (canonical redirection needs a fixed host, + # dash-proxy rejects the pair (canonical redirection needs a fixed host, # on-demand TLS has none) - today the deploy fails after the SSH round-trip. test "canonical_host cannot be combined with on_demand_url" do error = assert_raises(Dash::ConfigurationError) do @@ -175,7 +175,7 @@ class ConfigurationProxyTrafficTest < ActiveSupport::TestCase assert configuration("canonical_host" => "www.example.com") end - # The wire format is '=' and kamal-proxy cuts at the FIRST '=', so + # The wire format is '=' and dash-proxy cuts at the FIRST '=', so # an '=' inside the pattern silently builds a rule for the wrong path. test "redirect and rewrite from cannot contain an equals sign" do %w[ redirects rewrites ].each do |key| @@ -216,7 +216,7 @@ class ConfigurationProxyTrafficTest < ActiveSupport::TestCase # The load balancer forwards to the per-host proxies, so applying headers and # rewrites twice would duplicate an added header and rewrite a path twice - # over — they stay per-app. Canonical host goes the other way: kamal-proxy's + # over — they stay per-app. Canonical host goes the other way: dash-proxy's # redirectURLIfNeeded consults r.TLS, so a per-app redirect behind the LB # would emit http:// Locations to HTTPS clients — it moves to the edge. test "traffic shaping stays off the load balancer, canonical host moves to it" do @@ -248,7 +248,7 @@ def deploy_options(proxy_config) end # Round-trips one shell word through the shell, so the assertion is about - # what kamal-proxy actually receives rather than about the quoting style. + # what dash-proxy actually receives rather than about the quoting style. def unshell(word) `printf %s #{word}` end diff --git a/test/configuration/proxy/tuning_test.rb b/test/configuration/proxy/tuning_test.rb index 184142b6..ca6f3cde 100644 --- a/test/configuration/proxy/tuning_test.rb +++ b/test/configuration/proxy/tuning_test.rb @@ -123,7 +123,7 @@ class ConfigurationProxyTuningTest < ActiveSupport::TestCase end # Sibling consistency: request_timeout already refuses negatives, and - # kamal-proxy clamps a negative --target-timeout just as silently. + # dash-proxy clamps a negative --target-timeout just as silently. test "a negative response_timeout is rejected" do error = assert_raises(Dash::ConfigurationError) { configuration "response_timeout" => -1 } @@ -144,7 +144,7 @@ class ConfigurationProxyTuningTest < ActiveSupport::TestCase assert_no_match(/max_idle_conns/, out) end - # kamal-proxy's parsePathTimeouts rejects these; both maps go through it. + # dash-proxy's parsePathTimeouts rejects these; both maps go through it. test "a negative path timeout is rejected in either map" do assert_equal "proxy/path_response_timeouts: '/uploads' cannot be negative", assert_raises(Dash::ConfigurationError) { configuration "path_response_timeouts" => { "/uploads" => -1 } }.message diff --git a/test/configuration/proxy_test.rb b/test/configuration/proxy_test.rb index 86963c47..6df7fd47 100644 --- a/test/configuration/proxy_test.rb +++ b/test/configuration/proxy_test.rb @@ -245,8 +245,8 @@ class ConfigurationProxyTest < ActiveSupport::TestCase proxy = config.proxy assert_equal ".dash/proxy/apps-config/app/tls/cert.pem", proxy.host_tls_cert assert_equal ".dash/proxy/apps-config/app/tls/key.pem", proxy.host_tls_key - assert_equal "/home/kamal-proxy/.apps-config/app/tls/cert.pem", proxy.container_tls_cert - assert_equal "/home/kamal-proxy/.apps-config/app/tls/key.pem", proxy.container_tls_key + assert_equal "/home/dash-proxy/.apps-config/app/tls/cert.pem", proxy.container_tls_cert + assert_equal "/home/dash-proxy/.apps-config/app/tls/key.pem", proxy.container_tls_key end end @@ -263,8 +263,8 @@ class ConfigurationProxyTest < ActiveSupport::TestCase proxy = config.proxy options = proxy.deploy_options assert_equal true, options[:tls] - assert_equal "/home/kamal-proxy/.apps-config/app/tls/cert.pem", options[:"tls-certificate-path"] - assert_equal "/home/kamal-proxy/.apps-config/app/tls/key.pem", options[:"tls-private-key-path"] + assert_equal "/home/dash-proxy/.apps-config/app/tls/cert.pem", options[:"tls-certificate-path"] + assert_equal "/home/dash-proxy/.apps-config/app/tls/key.pem", options[:"tls-private-key-path"] end end @@ -348,7 +348,7 @@ class ConfigurationProxyTest < ActiveSupport::TestCase # Session affinity: both layers used to pin with the same cookie name but # separate HMAC keys, so the inner proxy clobbered the edge pin every other # request — the edge is the only layer whose pin can stick. - # Canonical host and redirects consult r.TLS only (kamal-proxy + # Canonical host and redirects consult r.TLS only (dash-proxy # redirectURLIfNeeded), so behind the LB they emitted http:// Locations to # HTTPS clients. Cache policy and read routing are edge decisions. test "deploy_options strips session affinity, canonical host, redirects, cache and read routing when load balancing" do @@ -386,7 +386,7 @@ class ConfigurationProxyTest < ActiveSupport::TestCase assert_includes options.keys, :compress end - # kamal-proxy gates TLSRedirect on TLSEnabled, and tls is already stripped + # dash-proxy gates TLSRedirect on TLSEnabled, and tls is already stripped # per-app — the whole TLS family terminates at the edge. test "deploy_options strips ssl staging and ssl redirect when load balancing" do @deploy[:proxy] = { @@ -636,7 +636,7 @@ class ConfigurationProxyTest < ActiveSupport::TestCase end end - # Basic auth is an edge concern. kamal-proxy deletes the Authorization header + # Basic auth is an edge concern. dash-proxy deletes the Authorization header # once a service enforces basic auth, so emitting the flag on BOTH the load # balancer and the per-app proxy would have the load balancer authenticate, # strip the header, and the app proxy 401 every forwarded request. diff --git a/test/configuration/role_test.rb b/test/configuration/role_test.rb index 9e6a61a9..c27049c3 100644 --- a/test/configuration/role_test.rb +++ b/test/configuration/role_test.rb @@ -396,7 +396,7 @@ class ConfigurationRoleTest < ActiveSupport::TestCase test "readiness description names the proxy health check path" do @deploy_with_roles[:proxy] = { "healthcheck" => { "path" => "/healthz" } } - assert_equal "kamal-proxy health check /healthz", config_with_roles.role(:web).readiness_description + assert_equal "dash-proxy health check /healthz", config_with_roles.role(:web).readiness_description end test "readiness description names the healthcheck port and path" do diff --git a/test/fixtures/deploy_with_every_proxy_option.yml b/test/fixtures/deploy_with_every_proxy_option.yml index 84e74333..6481b295 100644 --- a/test/fixtures/deploy_with_every_proxy_option.yml +++ b/test/fixtures/deploy_with_every_proxy_option.yml @@ -1,6 +1,6 @@ # Every proxy option the gem can express, in one config. # -# test/proxy_flag_coverage_test.rb generates the kamal-proxy commands from this +# test/proxy_flag_coverage_test.rb generates the dash-proxy commands from this # fixture and treats the flags that come out as the gem's real coverage. So a key # only counts as "mapped" if setting it here actually produces a flag — a config # accessor that exists but is never wired into deploy_options does not pass. @@ -96,7 +96,7 @@ proxy: set: Strict-Transport-Security: max-age=31536000 add: - X-Served-By: kamal-proxy + X-Served-By: dash-proxy remove: - Server redirects: @@ -178,11 +178,11 @@ proxy: write_timeout: 30 idle_timeout: 60 shutdown_timeout: 15 - # Deliberately a name kamal-proxy will never have. run.flags forwards + # Deliberately a name dash-proxy will never have. run.flags forwards # anything, so a real flag here would fake coverage for it — see the note on # R7_BACKLOG in test/proxy_flag_coverage_test.rb. flags: - not-a-real-kamal-proxy-flag: value + not-a-real-dash-proxy-flag: value acme: email: admin@example.com # The hash form (per-zone DNS-01 providers); the string shorthand is diff --git a/test/fixtures/deploy_with_on_demand_tls.yml b/test/fixtures/deploy_with_on_demand_tls.yml index 2cd35787..773c60e4 100644 --- a/test/fixtures/deploy_with_on_demand_tls.yml +++ b/test/fixtures/deploy_with_on_demand_tls.yml @@ -1,5 +1,5 @@ # The second maximal proxy fixture, for options that cannot coexist with the -# first. kamal-proxy rejects on-demand TLS alongside a static host list, a custom +# first. dash-proxy rejects on-demand TLS alongside a static host list, a custom # certificate, or ssl_domains — all three of which # deploy_with_every_proxy_option.yml needs for its own coverage. # diff --git a/test/fixtures/kamal_proxy_flags.yml b/test/fixtures/kamal_proxy_flags.yml index c1bfc732..713e1995 100644 --- a/test/fixtures/kamal_proxy_flags.yml +++ b/test/fixtures/kamal_proxy_flags.yml @@ -2,7 +2,7 @@ # Generated by bin/sync-proxy-flags — do not edit by hand. # Refresh whenever MINIMUM_VERSION moves; test/proxy_flag_coverage_test.rb # fails while proxy_version here disagrees with MINIMUM_VERSION. -proxy_version: v1.0.0.7 +proxy_version: v1.1.0.0 generated_by: bin/sync-proxy-flags acme_dns_providers: - auto diff --git a/test/integration/docker-compose.yml b/test/integration/docker-compose.yml index cb5ace1f..ec7aee7e 100644 --- a/test/integration/docker-compose.yml +++ b/test/integration/docker-compose.yml @@ -45,7 +45,7 @@ services: # Docker Hub pull-through cache. The deployer and vm inner daemons point their # registry-mirrors here (see their boot.sh), so base images (registry:3, nginx, - # busybox, traefik, basecamp/kamal-proxy) are fetched from Docker Hub at most + # busybox, traefik, basecamp/dash-proxy) are fetched from Docker Hub at most # once per run instead of on every test, dodging Hub rate limits. # # The cache fetches from Docker Hub on its own (anonymous by default — separate diff --git a/test/integration/docker/deployer/app/.dash/hooks/post-proxy-reboot b/test/integration/docker/deployer/app/.dash/hooks/post-proxy-reboot index fb47d3cc..c4583a4d 100755 --- a/test/integration/docker/deployer/app/.dash/hooks/post-proxy-reboot +++ b/test/integration/docker/deployer/app/.dash/hooks/post-proxy-reboot @@ -1,3 +1,3 @@ #!/bin/sh -echo "Rebooted kamal-proxy on ${KAMAL_HOSTS}" +echo "Rebooted dash-proxy on ${KAMAL_HOSTS}" mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/post-proxy-reboot diff --git a/test/integration/docker/deployer/app/.dash/hooks/pre-proxy-reboot b/test/integration/docker/deployer/app/.dash/hooks/pre-proxy-reboot index 6413b6ef..ceaf7901 100755 --- a/test/integration/docker/deployer/app/.dash/hooks/pre-proxy-reboot +++ b/test/integration/docker/deployer/app/.dash/hooks/pre-proxy-reboot @@ -1,3 +1,3 @@ #!/bin/sh -echo "Rebooting kamal-proxy on ${KAMAL_HOSTS}..." +echo "Rebooting dash-proxy on ${KAMAL_HOSTS}..." mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-proxy-reboot diff --git a/test/integration/docker/deployer/app_with_roles/.dash/hooks/post-proxy-reboot b/test/integration/docker/deployer/app_with_roles/.dash/hooks/post-proxy-reboot index fb47d3cc..c4583a4d 100755 --- a/test/integration/docker/deployer/app_with_roles/.dash/hooks/post-proxy-reboot +++ b/test/integration/docker/deployer/app_with_roles/.dash/hooks/post-proxy-reboot @@ -1,3 +1,3 @@ #!/bin/sh -echo "Rebooted kamal-proxy on ${KAMAL_HOSTS}" +echo "Rebooted dash-proxy on ${KAMAL_HOSTS}" mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/post-proxy-reboot diff --git a/test/integration/docker/deployer/app_with_roles/.dash/hooks/pre-proxy-reboot b/test/integration/docker/deployer/app_with_roles/.dash/hooks/pre-proxy-reboot index 6413b6ef..ceaf7901 100755 --- a/test/integration/docker/deployer/app_with_roles/.dash/hooks/pre-proxy-reboot +++ b/test/integration/docker/deployer/app_with_roles/.dash/hooks/pre-proxy-reboot @@ -1,3 +1,3 @@ #!/bin/sh -echo "Rebooting kamal-proxy on ${KAMAL_HOSTS}..." +echo "Rebooting dash-proxy on ${KAMAL_HOSTS}..." mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-proxy-reboot diff --git a/test/integration/integration_test.rb b/test/integration/integration_test.rb index 26b070aa..4f8bee14 100644 --- a/test/integration/integration_test.rb +++ b/test/integration/integration_test.rb @@ -328,11 +328,11 @@ def vm_exec(host, command, **options) end def assert_proxy_running - assert_container_running(host: "vm1", name: "kamal-proxy") + assert_container_running(host: "vm1", name: "dash-proxy") end def assert_proxy_not_running - assert_container_not_running(host: "vm1", name: "kamal-proxy") + assert_container_not_running(host: "vm1", name: "dash-proxy") end def app_host(app = @app) diff --git a/test/integration/proxy_test.rb b/test/integration/proxy_test.rb index da9457e9..e79b14f3 100644 --- a/test/integration/proxy_test.rb +++ b/test/integration/proxy_test.rb @@ -12,16 +12,16 @@ class ProxyTest < IntegrationTest output = kamal :proxy, :reboot, "-y", "--verbose", capture: true assert_proxy_running assert_hooks_ran "pre-proxy-reboot", "post-proxy-reboot" - assert_match /Rebooting kamal-proxy on vm1,vm2.../, output - assert_match /Rebooted kamal-proxy on vm1,vm2/, output + assert_match /Rebooting dash-proxy on vm1,vm2.../, output + assert_match /Rebooted dash-proxy on vm1,vm2/, output output = kamal :proxy, :reboot, "--rolling", "-y", "--verbose", capture: true assert_proxy_running assert_hooks_ran "pre-proxy-reboot", "post-proxy-reboot" - assert_match /Rebooting kamal-proxy on vm1.../, output - assert_match /Rebooted kamal-proxy on vm1/, output - assert_match /Rebooting kamal-proxy on vm2.../, output - assert_match /Rebooted kamal-proxy on vm2/, output + assert_match /Rebooting dash-proxy on vm1.../, output + assert_match /Rebooted dash-proxy on vm1/, output + assert_match /Rebooting dash-proxy on vm2.../, output + assert_match /Rebooted dash-proxy on vm2/, output kamal :proxy, :boot assert_proxy_running @@ -43,7 +43,7 @@ class ProxyTest < IntegrationTest kamal :proxy, :restart assert_proxy_running - # Since kamal-proxy v0.9.2.2 state is flushed on every shutdown, so any + # Since dash-proxy v0.9.2.2 state is flushed on every shutdown, so any # boot after the first restores it rather than reporting no previous state. logs = kamal :proxy, :logs, capture: true assert_match /Restored saved state/, logs @@ -68,7 +68,7 @@ class ProxyTest < IntegrationTest kamal :proxy, :boot_config, :set, "--metrics-port", "9099" output = kamal :deploy, "--verbose", capture: true - assert_match /kamal-proxy configuration changed, rebooting on vm1/, output + assert_match /dash-proxy configuration changed, rebooting on vm1/, output assert_hooks_ran "pre-proxy-reboot", "post-proxy-reboot" assert_proxy_running @@ -84,7 +84,7 @@ class ProxyTest < IntegrationTest private def proxy_container_id - docker_compose("exec vm1 docker ps --filter 'name=^kamal-proxy$' --quiet", capture: true).strip + docker_compose("exec vm1 docker ps --filter 'name=^dash-proxy$' --quiet", capture: true).strip end def assert_docker_options_in_file boot_config = kamal :proxy, :boot_config, :get, capture: true @@ -94,6 +94,6 @@ def assert_docker_options_in_file def assert_docker_options_in_container assert_equal \ "{\"net.ipv4.ip_local_port_range\":\"10000 60999\"}", - docker_compose("exec vm1 docker inspect --format '{{ json .HostConfig.Sysctls }}' kamal-proxy", capture: true).strip + docker_compose("exec vm1 docker inspect --format '{{ json .HostConfig.Sysctls }}' dash-proxy", capture: true).strip end end diff --git a/test/namespace_test.rb b/test/namespace_test.rb index e39c63b9..45f8d9d1 100644 --- a/test/namespace_test.rb +++ b/test/namespace_test.rb @@ -2,7 +2,7 @@ # Stage 2 of the rename (issue #117): the gem's Ruby identity is Dash::, and # the old Kamal:: namespace is gone — no compat alias. The remaining server -# artifacts (kamal-proxy container, kamal network, KAMAL_* env) are stage 3c +# artifacts (dash-proxy container, kamal network, KAMAL_* env) are stage 3c # and unaffected; the run directory became .dash/ in 3b. class NamespaceTest < ActiveSupport::TestCase test "the gem loads under the Dash namespace" do diff --git a/test/proxy_flag_coverage_test.rb b/test/proxy_flag_coverage_test.rb index b1caf46d..b78222b6 100644 --- a/test/proxy_flag_coverage_test.rb +++ b/test/proxy_flag_coverage_test.rb @@ -1,11 +1,11 @@ require "test_helper" -# kamal-proxy grows flags faster than deploy.yml grows keys, and nothing noticed: +# dash-proxy grows flags faster than deploy.yml grows keys, and nothing noticed: # 23 `feat` commits landed between v0.9.2.2 and v1.0.0.0 and the gem's config # surface never moved. A flag the gem cannot emit is a feature that ships in the # image and is unreachable from deploy.yml. # -# So: every flag kamal-proxy accepts must either be emitted by the gem, or be +# So: every flag dash-proxy accepts must either be emitted by the gem, or be # waived here with a reason. New flags fail the build at the MINIMUM_VERSION bump # — the moment someone is already thinking about gem/proxy compatibility. # @@ -22,13 +22,13 @@ class ProxyFlagCoverageTest < ActiveSupport::TestCase NEVER_EXPOSED = { "deploy" => { "force" => "CLI-level concern (dash proxy deploy), not operator config", - "tls-acme-cache-path" => "cut for 3.0 (#93 D4) - kamal-proxy's default already persists ACME assets in the kamal-proxy-config volume, so the knob only offered ways to break that", + "tls-acme-cache-path" => "cut for 3.0 (#93 D4) - dash-proxy's default already persists ACME assets in the dash-proxy-config volume, so the knob only offered ways to break that", "scope-cookie-paths" => "cut for 3.0 (#93 D4) - niche cookie-path rewriting under path_prefix; re-expose post-3.0 if someone asks for it" }, "run" => { "http-port" => "the gem publishes host:container ports via docker; the proxy listens on its default inside", "https-port" => "same as --http-port", - "data-dir" => "fixed by the kamal-proxy-config volume mount in Dash::Commands::Proxy#run", + "data-dir" => "fixed by the dash-proxy-config volume mount in Dash::Commands::Proxy#run", "cache-store" => "delivered as CACHE_STORE via the 0600 proxy secrets env file - a store URL may embed credentials that must stay out of process listings and the audit log", "cache-lease-ttl" => "cut for 3.0 (#93 D4) - cross-node coalescing tuning with sane proxy defaults; proxy/run/flags remains the escape hatch", "cache-lease-wait" => "same as --cache-lease-ttl" @@ -41,7 +41,7 @@ class ProxyFlagCoverageTest < ActiveSupport::TestCase # in the generated command or this test fails — which is the point. The waiver # list shrinking to empty is what "R7 is done" means. # - # It is empty. Every flag kamal-proxy accepts is now either emitted from a + # It is empty. Every flag dash-proxy accepts is now either emitted from a # deploy.yml key or waived above with a reason. A new proxy release that adds # one fails this test at the MINIMUM_VERSION bump, which is the only moment # anyone is thinking about gem/proxy compatibility. @@ -65,7 +65,7 @@ class ProxyFlagCoverageTest < ActiveSupport::TestCase test "the flag manifest tracks MINIMUM_VERSION" do assert_equal Dash::Configuration::Proxy::Run::MINIMUM_VERSION, MANIFEST["proxy_version"], <<~MESSAGE - test/fixtures/kamal_proxy_flags.yml was generated for kamal-proxy #{MANIFEST["proxy_version"]}, + test/fixtures/kamal_proxy_flags.yml was generated for dash-proxy #{MANIFEST["proxy_version"]}, but MINIMUM_VERSION is now #{Dash::Configuration::Proxy::Run::MINIMUM_VERSION}. Refresh it: bin/sync-proxy-flags @@ -75,22 +75,22 @@ class ProxyFlagCoverageTest < ActiveSupport::TestCase MESSAGE end - test "every kamal-proxy deploy flag is exposed in deploy.yml or waived" do + test "every dash-proxy deploy flag is exposed in deploy.yml or waived" do assert_covered "deploy", emitted_deploy_flags end - test "every kamal-proxy run flag is exposed in deploy.yml or waived" do + test "every dash-proxy run flag is exposed in deploy.yml or waived" do assert_covered "run", emitted_run_flags end # Unlike a flag the gem cannot emit, a provider the gem does not know is not a # missing feature — it is a rejected deploy. proxy/run/acme/dns_provider is - # validated against Acme::DNS_PROVIDERS, so a provider kamal-proxy grew and the + # validated against Acme::DNS_PROVIDERS, so a provider dash-proxy grew and the # gem did not fails config validation for an operator who is holding it right. - test "the gem's DNS provider allowlist matches what kamal-proxy advertises" do + test "the gem's DNS provider allowlist matches what dash-proxy advertises" do assert_equal MANIFEST.fetch("acme_dns_providers").sort, Dash::Configuration::Proxy::Acme::DNS_PROVIDERS.sort, <<~MESSAGE - kamal-proxy #{MANIFEST["proxy_version"]} and Dash::Configuration::Proxy::Acme::DNS_PROVIDERS + dash-proxy #{MANIFEST["proxy_version"]} and Dash::Configuration::Proxy::Acme::DNS_PROVIDERS disagree about which DNS providers exist. Refresh the manifest (bin/sync-proxy-flags), then bring DNS_PROVIDERS in @@ -98,17 +98,17 @@ class ProxyFlagCoverageTest < ActiveSupport::TestCase configure and the gem would reject; providers it lost are ones the gem still accepts and the proxy will silently ignore. - Short aliases (cf, r53, ...) live in DNS_PROVIDER_ALIASES — kamal-proxy + Short aliases (cf, r53, ...) live in DNS_PROVIDER_ALIASES — dash-proxy accepts them but does not advertise them, so they are not checked here. MESSAGE end - test "no waiver names a flag kamal-proxy no longer accepts" do + test "no waiver names a flag dash-proxy no longer accepts" do WAIVED.each do |subcommand, waivers| stale = waivers.keys - MANIFEST.fetch("flags").fetch(subcommand) assert_empty stale, <<~MESSAGE - These #{subcommand} waivers name flags kamal-proxy #{MANIFEST["proxy_version"]} does not + These #{subcommand} waivers name flags dash-proxy #{MANIFEST["proxy_version"]} does not accept: #{stale.join(", ")}. The flag was renamed or removed upstream. Drop the waiver, and check @@ -123,7 +123,7 @@ def assert_covered(subcommand, emitted) uncovered = flags - emitted - WAIVED.fetch(subcommand).keys assert_empty uncovered, <<~MESSAGE - kamal-proxy #{MANIFEST["proxy_version"]} accepts #{uncovered.size} #{subcommand} flag(s) the gem can + dash-proxy #{MANIFEST["proxy_version"]} accepts #{uncovered.size} #{subcommand} flag(s) the gem can neither emit nor account for: #{uncovered.map { |flag| " --#{flag}" }.join("\n")} @@ -157,7 +157,7 @@ def flag_names(args) Array(args).join(" ").scan(/--([a-z0-9-]+)/).flatten.uniq end - # More than one, because some options are mutually exclusive: kamal-proxy + # More than one, because some options are mutually exclusive: dash-proxy # forbids on-demand TLS alongside a host list, a custom certificate or # ssl_domains, so one fixture cannot hold every key. Coverage is the union. def maximal_configs diff --git a/test/proxy_layering_test.rb b/test/proxy_layering_test.rb index 8a3274a0..f5f2adca 100644 --- a/test/proxy_layering_test.rb +++ b/test/proxy_layering_test.rb @@ -20,7 +20,7 @@ class ProxyLayeringTest < ActiveSupport::TestCase DISPOSITIONS = Dash::Configuration::Proxy::DEPLOY_OPTION_DISPOSITIONS # Same pair as the flag coverage canary: some options are mutually exclusive - # (kamal-proxy forbids on-demand TLS alongside hosts, a custom certificate or + # (dash-proxy forbids on-demand TLS alongside hosts, a custom certificate or # ssl_domains), so one fixture cannot emit every key. Coverage is the union. MAXIMAL_FIXTURES = %w[ deploy_with_every_proxy_option deploy_with_on_demand_tls ].freeze