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.
This commit is contained in:
Donal McBreen
2025-04-16 16:01:34 +01:00
parent c9a755bde6
commit 85320dbc51
13 changed files with 197 additions and 40 deletions

View File

@@ -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 :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 :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 :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" option :docker_options, type: :array, default: [], desc: "Docker options to pass to the proxy container", banner: "option=value option2=value2"
def boot_config(subcommand) def boot_config(subcommand)
case subcommand case subcommand
@@ -37,17 +40,43 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
*options[:docker_options].map { |option| "--#{option}" } *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| on(KAMAL.proxy_hosts) do |host|
execute(*KAMAL.proxy.ensure_proxy_directory) 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 end
when "get" when "get"
on(KAMAL.proxy_hosts) do |host| 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 end
when "reset" when "reset"
on(KAMAL.proxy_hosts) do |host| 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 end
else else
raise ArgumentError, "Unknown boot_config subcommand #{subcommand}" raise ArgumentError, "Unknown boot_config subcommand #{subcommand}"

View File

@@ -68,6 +68,10 @@ module Kamal::Commands
combine *commands, by: "||" combine *commands, by: "||"
end end
def substitute(*commands)
"\$\(#{commands.join(" ")}\)"
end
def xargs(command) def xargs(command)
[ :xargs, command ].flatten [ :xargs, command ].flatten
end end

View File

@@ -2,7 +2,7 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
delegate :argumentize, :optionize, to: Kamal::Utils delegate :argumentize, :optionize, to: Kamal::Utils
def run def run
pipe echo_boot_config, xargs(docker_run) pipe boot_config, xargs(docker_run)
end end
def start def start
@@ -24,7 +24,7 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
def version def version
pipe \ pipe \
docker(:inspect, container_name, "--format '{{.Config.Image}}'"), docker(:inspect, container_name, "--format '{{.Config.Image}}'"),
[ :cut, "-d:", "-f2" ] [ :awk, "-F:", "'{print \$NF}'" ]
end end
def logs(timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil) 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 remove_directory config.proxy_directory
end end
def get_boot_options def boot_config
combine [ :cat, config.proxy_options_file, "2>", "/dev/null" ], [ :echo, "\"#{config.proxy_options_default.join(" ")}\"" ], by: "||" [ :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 end
def reset_boot_options def reset_boot_options
remove_file config.proxy_options_file remove_file config.proxy_options_file
end end
def reset_image
remove_file config.proxy_image_file
end
def reset_image_version
remove_file config.proxy_image_version_file
end
private private
def container_name def container_name
config.proxy_container_name config.proxy_container_name
end end
def echo_boot_config def read_file(file, default: nil)
[ :echo, "\$\(#{get_boot_options.join(" ")}\) #{config.proxy_image}" ] combine [ :cat, file, "2>", "/dev/null" ], [ :echo, "\"#{default}\"" ], by: "||"
end end
def docker_run def docker_run

View File

@@ -261,8 +261,16 @@ class Kamal::Configuration
[ *proxy_publish_args(PROXY_HTTP_PORT, PROXY_HTTPS_PORT), *proxy_logging_args(PROXY_LOG_MAX_SIZE) ] [ *proxy_publish_args(PROXY_HTTP_PORT, PROXY_HTTPS_PORT), *proxy_logging_args(PROXY_LOG_MAX_SIZE) ]
end end
def proxy_image def proxy_repository_name
"basecamp/kamal-proxy:#{PROXY_MINIMUM_VERSION}" "basecamp"
end
def proxy_image_name
"kamal-proxy"
end
def proxy_image_default
"#{proxy_repository_name}/#{proxy_image_name}"
end end
def proxy_container_name def proxy_container_name
@@ -277,6 +285,14 @@ class Kamal::Configuration
File.join proxy_directory, "options" File.join proxy_directory, "options"
end 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 def to_h
{ {
roles: role_names, roles: role_names,

View File

@@ -4,21 +4,21 @@ class CliProxyTest < CliTestCase
test "boot" do test "boot" do
run_command("boot").tap do |output| run_command("boot").tap do |output|
assert_match "docker login", 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
end end
test "boot old version" do test "boot old version" do
Thread.report_on_exception = false Thread.report_on_exception = false
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) 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") .returns("v0.0.1")
.at_least_once .at_least_once
exception = assert_raises do exception = assert_raises do
run_command("boot").tap do |output| run_command("boot").tap do |output|
assert_match "docker login", 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
end end
@@ -30,13 +30,13 @@ class CliProxyTest < CliTestCase
test "boot correct version" do test "boot correct version" do
Thread.report_on_exception = false Thread.report_on_exception = false
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) 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) .returns(Kamal::Configuration::PROXY_MINIMUM_VERSION)
.at_least_once .at_least_once
run_command("boot").tap do |output| run_command("boot").tap do |output|
assert_match "docker login", 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 end
ensure ensure
Thread.report_on_exception = false Thread.report_on_exception = false
@@ -56,12 +56,12 @@ class CliProxyTest < CliTestCase
run_command("reboot", "-y").tap do |output| run_command("reboot", "-y").tap do |output|
assert_match "docker container stop kamal-proxy on 1.1.1.1", 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 "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 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 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 "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 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
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.stubs(:capture_with_info).returns("12345678")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) 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) .returns(Kamal::Configuration::PROXY_MINIMUM_VERSION)
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) 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 "/usr/bin/env mkdir -p .kamal", output
assert_match "docker network create kamal", output assert_match "docker network create kamal", output
assert_match "docker login -u [REDACTED] -p [REDACTED]", 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 "/usr/bin/env mkdir -p .kamal", output
assert_match %r{docker rename app-web-latest app-web-latest_replaced_.*}, 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 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.stubs(:capture_with_info).returns("12345678")
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) 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) .returns(Kamal::Configuration::PROXY_MINIMUM_VERSION)
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
@@ -238,8 +238,9 @@ class CliProxyTest < CliTestCase
run_command("boot_config", "set").tap do |output| run_command("boot_config", "set").tap do |output|
%w[ 1.1.1.1 1.1.1.2 ].each do |host| %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 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 assert_match "Running /usr/bin/env rm .kamal/proxy/options on #{host}", output
end 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
end end
@@ -248,6 +249,8 @@ class CliProxyTest < CliTestCase
%w[ 1.1.1.1 1.1.1.2 ].each do |host| %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 mkdir -p .kamal/proxy on #{host}", output
assert_match "Uploading \"--log-opt max-size=10m\" to .kamal/proxy/options 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 end
end end
@@ -257,6 +260,8 @@ class CliProxyTest < CliTestCase
%w[ 1.1.1.1 1.1.1.2 ].each do |host| %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 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 "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 end
end end
@@ -266,6 +271,8 @@ class CliProxyTest < CliTestCase
%w[ 1.1.1.1 1.1.1.2 ].each do |host| %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 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 "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 end
end end
@@ -310,19 +317,64 @@ class CliProxyTest < CliTestCase
%w[ 1.1.1.1 1.1.1.2 ].each do |host| %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 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 "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 end
end end
test "boot_config get" do test "boot_config get" do
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) 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\"") .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") .returns("--publish 80:80 --publish 8443:443 --label=foo=bar basecamp/kamal-proxy:v1.0.0")
.twice .twice
run_command("boot_config", "get").tap do |output| 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.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", 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
end end

View File

@@ -15,7 +15,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
test "run" do test "run" do
assert_equal \ 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(" ") new_command.run.join(" ")
end end
@@ -23,7 +23,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
@config.delete(:proxy) @config.delete(:proxy)
assert_equal \ 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(" ") new_command.run.join(" ")
end end
@@ -101,7 +101,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
test "version" do test "version" do
assert_equal \ 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(" ") new_command.version.join(" ")
end end
@@ -111,10 +111,22 @@ class CommandsProxyTest < ActiveSupport::TestCase
new_command.ensure_proxy_directory.join(" ") new_command.ensure_proxy_directory.join(" ")
end end
test "get_boot_options" do test "read_boot_options" do
assert_equal \ assert_equal \
"cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\"", "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 end
test "reset_boot_options" do test "reset_boot_options" do
@@ -123,6 +135,18 @@ class CommandsProxyTest < ActiveSupport::TestCase
new_command.reset_boot_options.join(" ") new_command.reset_boot_options.join(" ")
end 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 private
def new_command def new_command
Kamal::Commands::Proxy.new(Kamal::Configuration.new(@config, version: "123")) Kamal::Commands::Proxy.new(Kamal::Configuration.new(@config, version: "123"))

View File

@@ -1,3 +1,6 @@
#!/bin/sh #!/bin/sh
set -e
kamal proxy boot_config set --registry registry:4443
echo "Deployed!" echo "Deployed!"
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-deploy mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-deploy

View File

@@ -41,4 +41,4 @@ accessories:
interval: 1 interval: 1
timeout: 1 timeout: 1
path: "/" path: "/"
drain_timeout: 2

View File

@@ -1,3 +1,6 @@
#!/bin/sh #!/bin/sh
set -e
kamal proxy boot_config set --registry registry:4443
echo "Deployed!" echo "Deployed!"
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-deploy mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-deploy

View File

@@ -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 \ --docker_options label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http \
label=traefik.http.routers.kamal_proxy.rule=PathPrefix\(\`/\`\) \ label=traefik.http.routers.kamal_proxy.rule=PathPrefix\(\`/\`\) \
sysctl=net.ipv4.ip_local_port_range=\"10000\ 60999\" sysctl=net.ipv4.ip_local_port_range=\"10000\ 60999\"

View File

@@ -20,6 +20,7 @@ push_image_to_registry_4443() {
install_kamal install_kamal
push_image_to_registry_4443 nginx 1-alpine-slim push_image_to_registry_4443 nginx 1-alpine-slim
push_image_to_registry_4443 busybox 1.36.0 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 # .ssh is on a shared volume that persists between runs. Clean it up as the
# churn of temporary vm IPs can eventually create conflicts. # churn of temporary vm IPs can eventually create conflicts.

View File

@@ -12,11 +12,11 @@ class IntegrationTest < ActiveSupport::TestCase
teardown do teardown do
unless passed? unless passed?
[ :deployer, :vm1, :vm2, :shared, :load_balancer, :registry ].each do |container| # [ :deployer, :vm1, :vm2, :shared, :load_balancer, :registry ].each do |container|
puts # puts
puts "Logs for #{container}:" # puts "Logs for #{container}:"
docker_compose :logs, container # docker_compose :logs, container
end # end
end end
docker_compose "down -t 1" docker_compose "down -t 1"
end end

View File

@@ -6,6 +6,8 @@ class ProxyTest < IntegrationTest
end end
test "boot, reboot, stop, start, restart, logs, remove" do test "boot, reboot, stop, start, restart, logs, remove" do
kamal :proxy, :boot_config, :set, "--registry", "registry:4443"
kamal :proxy, :boot kamal :proxy, :boot
assert_proxy_running assert_proxy_running
@@ -46,7 +48,7 @@ class ProxyTest < IntegrationTest
logs = kamal :proxy, :logs, capture: true logs = kamal :proxy, :logs, capture: true
assert_match /No previous state to restore/, logs 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 assert_docker_options_in_file
kamal :proxy, :reboot, "-y" kamal :proxy, :reboot, "-y"