From 85320dbc518b96d2341c70be76ca5b588b48cf00 Mon Sep 17 00:00:00 2001 From: Donal McBreen Date: Wed, 16 Apr 2025 16:01:34 +0100 Subject: [PATCH] Custom proxy image registry, repo and version Use the --registry, --repository and --image_version options of `kamal proxy boot_config set` to change the kamal-proxy image used. We'll still insist that the image version is at least as high as the minimum. --- lib/kamal/cli/proxy.rb | 35 +++++++- lib/kamal/commands/base.rb | 4 + lib/kamal/commands/proxy.rb | 32 +++++-- lib/kamal/configuration.rb | 20 ++++- test/cli/proxy_test.rb | 84 +++++++++++++++---- test/commands/proxy_test.rb | 34 ++++++-- .../deployer/app/.kamal/hooks/pre-deploy | 3 + .../config/deploy.yml | 2 +- .../app_with_roles/.kamal/hooks/pre-deploy | 3 + .../app_with_traefik/.kamal/hooks/pre-deploy | 5 +- test/integration/docker/deployer/setup.sh | 1 + test/integration/integration_test.rb | 10 +-- test/integration/proxy_test.rb | 4 +- 13 files changed, 197 insertions(+), 40 deletions(-) diff --git a/lib/kamal/cli/proxy.rb b/lib/kamal/cli/proxy.rb index f73177ad..9ce8373e 100644 --- a/lib/kamal/cli/proxy.rb +++ b/lib/kamal/cli/proxy.rb @@ -27,6 +27,9 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base option :http_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTP_PORT, desc: "HTTP port to publish on the host" option :https_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTPS_PORT, desc: "HTTPS port to publish on the host" option :log_max_size, type: :string, default: Kamal::Configuration::PROXY_LOG_MAX_SIZE, desc: "Max size of proxy logs" + option :registry, type: :string, default: nil, desc: "Registry to use for the proxy image" + option :repository, type: :string, default: nil, desc: "Repository for the proxy image" + option :image_version, type: :string, default: nil, desc: "Version of the proxy to run" option :docker_options, type: :array, default: [], desc: "Docker options to pass to the proxy container", banner: "option=value option2=value2" def boot_config(subcommand) case subcommand @@ -37,17 +40,43 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base *options[:docker_options].map { |option| "--#{option}" } ] + default_boot_options = [ + *(KAMAL.config.proxy_publish_args(Kamal::Configuration::PROXY_HTTP_PORT, Kamal::Configuration::PROXY_HTTPS_PORT, nil)), + *(KAMAL.config.proxy_logging_args(Kamal::Configuration::PROXY_LOG_MAX_SIZE)), + ] + + image = [ options[:registry].presence, options[:repository] || KAMAL.config.proxy_repository_name, KAMAL.config.proxy_image_name ].compact.join("/") + image_version = options[:image_version] + on(KAMAL.proxy_hosts) do |host| execute(*KAMAL.proxy.ensure_proxy_directory) - upload! StringIO.new(boot_options.join(" ")), KAMAL.config.proxy_options_file + if boot_options != default_boot_options + upload! StringIO.new(boot_options.join(" ")), KAMAL.config.proxy_options_file + else + execute *KAMAL.proxy.reset_boot_options, raise_on_non_zero_exit: false + end + + if image != KAMAL.config.proxy_image_default + upload! StringIO.new(image), KAMAL.config.proxy_image_file + else + execute *KAMAL.proxy.reset_image, raise_on_non_zero_exit: false + end + + if image_version + upload! StringIO.new(image_version), KAMAL.config.proxy_image_version_file + else + execute *KAMAL.proxy.reset_image_version, raise_on_non_zero_exit: false + end end when "get" on(KAMAL.proxy_hosts) do |host| - puts "Host #{host}: #{capture_with_info(*KAMAL.proxy.get_boot_options)}" + puts "Host #{host}: #{capture_with_info(*KAMAL.proxy.boot_config)}" end when "reset" on(KAMAL.proxy_hosts) do |host| - execute *KAMAL.proxy.reset_boot_options + execute *KAMAL.proxy.reset_boot_options, raise_on_non_zero_exit: false + execute *KAMAL.proxy.reset_image, raise_on_non_zero_exit: false + execute *KAMAL.proxy.reset_image_version, raise_on_non_zero_exit: false end else raise ArgumentError, "Unknown boot_config subcommand #{subcommand}" diff --git a/lib/kamal/commands/base.rb b/lib/kamal/commands/base.rb index 535d17c0..ba3b86ba 100644 --- a/lib/kamal/commands/base.rb +++ b/lib/kamal/commands/base.rb @@ -68,6 +68,10 @@ module Kamal::Commands combine *commands, by: "||" end + def substitute(*commands) + "\$\(#{commands.join(" ")}\)" + end + def xargs(command) [ :xargs, command ].flatten end diff --git a/lib/kamal/commands/proxy.rb b/lib/kamal/commands/proxy.rb index 236ce0c1..25fc1efe 100644 --- a/lib/kamal/commands/proxy.rb +++ b/lib/kamal/commands/proxy.rb @@ -2,7 +2,7 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base delegate :argumentize, :optionize, to: Kamal::Utils def run - pipe echo_boot_config, xargs(docker_run) + pipe boot_config, xargs(docker_run) end def start @@ -24,7 +24,7 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base def version pipe \ docker(:inspect, container_name, "--format '{{.Config.Image}}'"), - [ :cut, "-d:", "-f2" ] + [ :awk, "-F:", "'{print \$NF}'" ] end def logs(timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil) @@ -65,21 +65,41 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base remove_directory config.proxy_directory end - def get_boot_options - combine [ :cat, config.proxy_options_file, "2>", "/dev/null" ], [ :echo, "\"#{config.proxy_options_default.join(" ")}\"" ], by: "||" + def boot_config + [ :echo, "#{substitute(read_boot_options)} #{substitute(read_image)}:#{substitute(read_image_version)}" ] + end + + def read_boot_options + read_file(config.proxy_options_file, default: config.proxy_options_default.join(" ")) + end + + def read_image + read_file(config.proxy_image_file, default: config.proxy_image_default) + end + + def read_image_version + read_file(config.proxy_image_version_file, default: Kamal::Configuration::PROXY_MINIMUM_VERSION) end def reset_boot_options remove_file config.proxy_options_file end + def reset_image + remove_file config.proxy_image_file + end + + def reset_image_version + remove_file config.proxy_image_version_file + end + private def container_name config.proxy_container_name end - def echo_boot_config - [ :echo, "\$\(#{get_boot_options.join(" ")}\) #{config.proxy_image}" ] + def read_file(file, default: nil) + combine [ :cat, file, "2>", "/dev/null" ], [ :echo, "\"#{default}\"" ], by: "||" end def docker_run diff --git a/lib/kamal/configuration.rb b/lib/kamal/configuration.rb index 1c0b79cf..1e9cd667 100644 --- a/lib/kamal/configuration.rb +++ b/lib/kamal/configuration.rb @@ -261,8 +261,16 @@ class Kamal::Configuration [ *proxy_publish_args(PROXY_HTTP_PORT, PROXY_HTTPS_PORT), *proxy_logging_args(PROXY_LOG_MAX_SIZE) ] end - def proxy_image - "basecamp/kamal-proxy:#{PROXY_MINIMUM_VERSION}" + def proxy_repository_name + "basecamp" + end + + def proxy_image_name + "kamal-proxy" + end + + def proxy_image_default + "#{proxy_repository_name}/#{proxy_image_name}" end def proxy_container_name @@ -277,6 +285,14 @@ class Kamal::Configuration File.join proxy_directory, "options" end + def proxy_image_file + File.join proxy_directory, "image" + end + + def proxy_image_version_file + File.join proxy_directory, "image_version" + end + def to_h { roles: role_names, diff --git a/test/cli/proxy_test.rb b/test/cli/proxy_test.rb index 4880a839..cd9cd5b9 100644 --- a/test/cli/proxy_test.rb +++ b/test/cli/proxy_test.rb @@ -4,21 +4,21 @@ class CliProxyTest < CliTestCase test "boot" do run_command("boot").tap do |output| assert_match "docker login", output - assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | 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 .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output end end test "boot old version" do Thread.report_on_exception = false SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :cut, "-d:", "-f2") + .with(:docker, :inspect, "kamal-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 .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | 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 .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output end end @@ -30,13 +30,13 @@ class CliProxyTest < CliTestCase test "boot correct version" do Thread.report_on_exception = false SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :cut, "-d:", "-f2") + .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns(Kamal::Configuration::PROXY_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 .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | 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 kamal-proxy || echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output end ensure Thread.report_on_exception = false @@ -56,12 +56,12 @@ class CliProxyTest < CliTestCase run_command("reboot", "-y").tap do |output| assert_match "docker container stop 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 "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy on 1.1.1.1", output + assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy on 1.1.1.1", output assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef: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\" on 1.1.1.1", output assert_match "docker container stop kamal-proxy on 1.1.1.2", output assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.2", output - assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy on 1.1.1.2", output + assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy on 1.1.1.2", output assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef: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\" on 1.1.1.2", output end end @@ -179,7 +179,7 @@ class CliProxyTest < CliTestCase SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("12345678") SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :cut, "-d:", "-f2") + .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns(Kamal::Configuration::PROXY_MINIMUM_VERSION) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) @@ -196,7 +196,7 @@ class CliProxyTest < CliTestCase assert_match "/usr/bin/env mkdir -p .kamal", output assert_match "docker network create kamal", output assert_match "docker login -u [REDACTED] -p [REDACTED]", output - assert_match "docker container start kamal-proxy || echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | 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 kamal-proxy || echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | 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 "/usr/bin/env mkdir -p .kamal", output assert_match %r{docker rename app-web-latest app-web-latest_replaced_.*}, output assert_match "/usr/bin/env mkdir -p .kamal/apps/app/env/roles", output @@ -218,7 +218,7 @@ class CliProxyTest < CliTestCase SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("12345678") SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :cut, "-d:", "-f2") + .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .returns(Kamal::Configuration::PROXY_MINIMUM_VERSION) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) @@ -238,8 +238,9 @@ class CliProxyTest < CliTestCase run_command("boot_config", "set").tap do |output| %w[ 1.1.1.1 1.1.1.2 ].each do |host| assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output - assert_match "Uploading \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\" to .kamal/proxy/options on #{host}", output - end + assert_match "Running /usr/bin/env rm .kamal/proxy/options on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image_version on #{host}", output end end end @@ -248,6 +249,8 @@ class CliProxyTest < CliTestCase %w[ 1.1.1.1 1.1.1.2 ].each do |host| assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output assert_match "Uploading \"--log-opt max-size=10m\" to .kamal/proxy/options on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image_version on #{host}", output end end end @@ -257,6 +260,8 @@ class CliProxyTest < CliTestCase %w[ 1.1.1.1 1.1.1.2 ].each do |host| assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output assert_match "Uploading \"--publish 80:80 --publish 443:443 --log-opt max-size=100m\" to .kamal/proxy/options on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image_version on #{host}", output end end end @@ -266,6 +271,8 @@ class CliProxyTest < CliTestCase %w[ 1.1.1.1 1.1.1.2 ].each do |host| assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output assert_match "Uploading \"--publish 80:80 --publish 443:443\" to .kamal/proxy/options on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image_version on #{host}", output end end end @@ -310,19 +317,64 @@ class CliProxyTest < CliTestCase %w[ 1.1.1.1 1.1.1.2 ].each do |host| assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output assert_match "Uploading \"--publish 80:80 --publish 443:443 --log-opt max-size=10m --label=foo=bar --add_host=thishost:thathost\" to .kamal/proxy/options on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image_version on #{host}", output + end + end + end + + test "boot_config set registry" do + run_command("boot_config", "set", "--registry", "myreg").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/options on #{host}", output + assert_match "Uploading \"myreg/basecamp/kamal-proxy\" to .kamal/proxy/image on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image_version on #{host}", output + end + end + end + + test "boot_config set repository" do + run_command("boot_config", "set", "--repository", "myrepo").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/options on #{host}", output + assert_match "Uploading \"myrepo/kamal-proxy\" to .kamal/proxy/image on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image_version on #{host}", output + end + end + end + + test "boot_config set image_version" do + run_command("boot_config", "set", "--image_version", "0.9.9").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/options on #{host}", output + assert_match "Running /usr/bin/env rm .kamal/proxy/image on #{host}", output + assert_match "Uploading \"0.9.9\" to .kamal/proxy/image_version on #{host}", output + end + end + end + + test "boot_config set all" do + run_command("boot_config", "set", "--docker_options", "label=foo=bar", "--registry", "myreg", "--repository", "myrepo", "--image_version", "0.9.9").tap do |output| + %w[ 1.1.1.1 1.1.1.2 ].each do |host| + assert_match "Uploading \"--publish 80:80 --publish 443:443 --log-opt max-size=10m --label=foo=bar\" to .kamal/proxy/options on #{host}", output + assert_match "Uploading \"myreg/myrepo/kamal-proxy\" to .kamal/proxy/image on #{host}", output + assert_match "Uploading \"0.9.9\" to .kamal/proxy/image_version on #{host}", output end end end test "boot_config get" do SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:cat, ".kamal/proxy/options", "2>", "/dev/null", "||", :echo, "\"--publish 80:80 --publish 443:443 --log-opt max-size=10m\"") - .returns("--publish 80:80 --publish 8443:443 --label=foo=bar") + .with(:echo, "$(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"v0.8.7\")") + .returns("--publish 80:80 --publish 8443:443 --label=foo=bar basecamp/kamal-proxy:v1.0.0") .twice run_command("boot_config", "get").tap do |output| - assert_match "Host 1.1.1.1: --publish 80:80 --publish 8443:443 --label=foo=bar", output - assert_match "Host 1.1.1.2: --publish 80:80 --publish 8443:443 --label=foo=bar", output + assert_match "Host 1.1.1.1: --publish 80:80 --publish 8443:443 --label=foo=bar basecamp/kamal-proxy:v1.0.0", output + assert_match "Host 1.1.1.2: --publish 80:80 --publish 8443:443 --label=foo=bar basecamp/kamal-proxy:v1.0.0", output end end diff --git a/test/commands/proxy_test.rb b/test/commands/proxy_test.rb index e42415b1..1ebd4009 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 .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", + "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", new_command.run.join(" ") end @@ -23,7 +23,7 @@ class CommandsProxyTest < ActiveSupport::TestCase @config.delete(:proxy) assert_equal \ - "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", + "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", new_command.run.join(" ") end @@ -101,7 +101,7 @@ class CommandsProxyTest < ActiveSupport::TestCase test "version" do assert_equal \ - "docker inspect kamal-proxy --format '{{.Config.Image}}' | cut -d: -f2", + "docker inspect kamal-proxy --format '{{.Config.Image}}' | awk -F: '{print $NF}'", new_command.version.join(" ") end @@ -111,10 +111,22 @@ class CommandsProxyTest < ActiveSupport::TestCase new_command.ensure_proxy_directory.join(" ") end - test "get_boot_options" do + test "read_boot_options" do assert_equal \ "cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\"", - new_command.get_boot_options.join(" ") + new_command.read_boot_options.join(" ") + end + + test "read_image" do + assert_equal \ + "cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"", + new_command.read_image.join(" ") + end + + test "read_image_version" do + assert_equal \ + "cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\"", + new_command.read_image_version.join(" ") end test "reset_boot_options" do @@ -123,6 +135,18 @@ class CommandsProxyTest < ActiveSupport::TestCase new_command.reset_boot_options.join(" ") end + test "reset_image" do + assert_equal \ + "rm .kamal/proxy/image", + new_command.reset_image.join(" ") + end + + test "reset_image_version" do + assert_equal \ + "rm .kamal/proxy/image_version", + new_command.reset_image_version.join(" ") + end + private def new_command Kamal::Commands::Proxy.new(Kamal::Configuration.new(@config, version: "123")) diff --git a/test/integration/docker/deployer/app/.kamal/hooks/pre-deploy b/test/integration/docker/deployer/app/.kamal/hooks/pre-deploy index 32fa04c6..eff40875 100755 --- a/test/integration/docker/deployer/app/.kamal/hooks/pre-deploy +++ b/test/integration/docker/deployer/app/.kamal/hooks/pre-deploy @@ -1,3 +1,6 @@ #!/bin/sh +set -e + +kamal proxy boot_config set --registry registry:4443 echo "Deployed!" mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-deploy diff --git a/test/integration/docker/deployer/app_with_proxied_accessory/config/deploy.yml b/test/integration/docker/deployer/app_with_proxied_accessory/config/deploy.yml index bdb547ae..ae4e217b 100644 --- a/test/integration/docker/deployer/app_with_proxied_accessory/config/deploy.yml +++ b/test/integration/docker/deployer/app_with_proxied_accessory/config/deploy.yml @@ -41,4 +41,4 @@ accessories: interval: 1 timeout: 1 path: "/" - +drain_timeout: 2 diff --git a/test/integration/docker/deployer/app_with_roles/.kamal/hooks/pre-deploy b/test/integration/docker/deployer/app_with_roles/.kamal/hooks/pre-deploy index 32fa04c6..eff40875 100755 --- a/test/integration/docker/deployer/app_with_roles/.kamal/hooks/pre-deploy +++ b/test/integration/docker/deployer/app_with_roles/.kamal/hooks/pre-deploy @@ -1,3 +1,6 @@ #!/bin/sh +set -e + +kamal proxy boot_config set --registry registry:4443 echo "Deployed!" mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-deploy diff --git a/test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy b/test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy index b2d8b112..5d7b7372 100755 --- a/test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy +++ b/test/integration/docker/deployer/app_with_traefik/.kamal/hooks/pre-deploy @@ -1,4 +1,7 @@ -kamal proxy boot_config set --publish false \ +set -e + +kamal proxy boot_config set --registry registry:4443 \ + --publish false \ --docker_options label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http \ label=traefik.http.routers.kamal_proxy.rule=PathPrefix\(\`/\`\) \ sysctl=net.ipv4.ip_local_port_range=\"10000\ 60999\" diff --git a/test/integration/docker/deployer/setup.sh b/test/integration/docker/deployer/setup.sh index 4867519e..24f39d7f 100755 --- a/test/integration/docker/deployer/setup.sh +++ b/test/integration/docker/deployer/setup.sh @@ -20,6 +20,7 @@ push_image_to_registry_4443() { install_kamal push_image_to_registry_4443 nginx 1-alpine-slim push_image_to_registry_4443 busybox 1.36.0 +push_image_to_registry_4443 basecamp/kamal-proxy v0.8.7 # .ssh is on a shared volume that persists between runs. Clean it up as the # churn of temporary vm IPs can eventually create conflicts. diff --git a/test/integration/integration_test.rb b/test/integration/integration_test.rb index 39ef9bc7..88c262c9 100644 --- a/test/integration/integration_test.rb +++ b/test/integration/integration_test.rb @@ -12,11 +12,11 @@ class IntegrationTest < ActiveSupport::TestCase teardown do unless passed? - [ :deployer, :vm1, :vm2, :shared, :load_balancer, :registry ].each do |container| - puts - puts "Logs for #{container}:" - docker_compose :logs, container - end + # [ :deployer, :vm1, :vm2, :shared, :load_balancer, :registry ].each do |container| + # puts + # puts "Logs for #{container}:" + # docker_compose :logs, container + # end end docker_compose "down -t 1" end diff --git a/test/integration/proxy_test.rb b/test/integration/proxy_test.rb index 39cacb94..5a53a08e 100644 --- a/test/integration/proxy_test.rb +++ b/test/integration/proxy_test.rb @@ -6,6 +6,8 @@ class ProxyTest < IntegrationTest end test "boot, reboot, stop, start, restart, logs, remove" do + kamal :proxy, :boot_config, :set, "--registry", "registry:4443" + kamal :proxy, :boot assert_proxy_running @@ -46,7 +48,7 @@ class ProxyTest < IntegrationTest logs = kamal :proxy, :logs, capture: true assert_match /No previous state to restore/, logs - kamal :proxy, :boot_config, :set, "--docker-options='sysctl net.ipv4.ip_local_port_range=\"10000 60999\"'" + kamal :proxy, :boot_config, :set, "--registry", "registry:4443", "--docker-options='sysctl net.ipv4.ip_local_port_range=\"10000 60999\"'" assert_docker_options_in_file kamal :proxy, :reboot, "-y"