Merge branch 'basecamp:main' into buildpacks
This commit is contained in:
@@ -115,6 +115,7 @@ class CliAccessoryTest < CliTestCase
|
||||
|
||||
test "exec" do
|
||||
run_command("exec", "mysql", "mysql -v").tap do |output|
|
||||
assert_match "docker login private.registry -u [REDACTED] -p [REDACTED]", output
|
||||
assert_match "Launching command from new container", output
|
||||
assert_match "mysql -v", output
|
||||
end
|
||||
@@ -251,6 +252,19 @@ class CliAccessoryTest < CliTestCase
|
||||
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-file .kamal/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-file .kamal/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
|
||||
|
||||
test "boot with workers role filter" do
|
||||
run_command("boot", "redis", "-r", "workers").tap do |output|
|
||||
assert_no_match "docker run", output
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def run_command(*command)
|
||||
stdouted { Kamal::Cli::Accessory.start([ *command, "-c", "test/fixtures/deploy_with_accessories_with_different_registries.yml" ]) }
|
||||
|
||||
@@ -192,6 +192,34 @@ class CliAppTest < CliTestCase
|
||||
Thread.report_on_exception = true
|
||||
end
|
||||
|
||||
test "boot with only workers" do
|
||||
Object.any_instance.stubs(:sleep)
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("123") # old version
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
||||
.returns("running").at_least_once # workers health check
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
test "boot with error pages" do
|
||||
with_error_pages(directory: "public") do
|
||||
stub_running
|
||||
run_command("boot", config: :with_error_pages).tap do |output|
|
||||
assert_match /Uploading .*kamal-error-pages.*\/latest to \.kamal\/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 container ls --all --filter name=^app-web-123$ --quiet | xargs docker stop", output
|
||||
assert_match "Running /usr/bin/env find .kamal/proxy/apps-config/app/error_pages -mindepth 1 -maxdepth 1 ! -name latest -exec rm -rf {} + on 1.1.1.1", output
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "start" do
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("999") # old version
|
||||
|
||||
@@ -244,9 +272,11 @@ class CliAppTest < CliTestCase
|
||||
|
||||
test "remove" do
|
||||
run_command("remove").tap do |output|
|
||||
assert_match /#{Regexp.escape("sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker stop")}/, output
|
||||
assert_match /#{Regexp.escape("docker container prune --force --filter label=service=app")}/, output
|
||||
assert_match /#{Regexp.escape("docker image prune --all --force --filter label=service=app")}/, output
|
||||
assert_match "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker stop", output
|
||||
assert_match "docker container prune --force --filter label=service=app", output
|
||||
assert_match "docker image prune --all --force --filter label=service=app", output
|
||||
assert_match "rm -r .kamal/apps/app on 1.1.1.1", output
|
||||
assert_match "rm -r .kamal/proxy/apps-config/app on 1.1.1.1", output
|
||||
end
|
||||
end
|
||||
|
||||
@@ -268,8 +298,16 @@ class CliAppTest < CliTestCase
|
||||
end
|
||||
end
|
||||
|
||||
test "remove_app_directories" do
|
||||
run_command("remove_app_directories").tap do |output|
|
||||
assert_match "rm -r .kamal/apps/app on 1.1.1.1", output
|
||||
assert_match "rm -r .kamal/proxy/apps-config/app on 1.1.1.1", output
|
||||
end
|
||||
end
|
||||
|
||||
test "exec" do
|
||||
run_command("exec", "ruby -v").tap do |output|
|
||||
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
|
||||
assert_match "docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size=\"10m\" dhh/app:latest ruby -v", output
|
||||
end
|
||||
end
|
||||
@@ -312,18 +350,25 @@ class CliAppTest < CliTestCase
|
||||
end
|
||||
|
||||
test "exec interactive" do
|
||||
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
||||
.with("ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size=\"10m\" dhh/app:latest ruby -v'")
|
||||
|
||||
run_command("exec", "-i", "ruby -v").tap do |output|
|
||||
assert_hook_ran "pre-connect", output
|
||||
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
|
||||
assert_match "Get most recent version available as an image...", output
|
||||
assert_match "Launching interactive command with version latest via SSH from new container on 1.1.1.1...", output
|
||||
end
|
||||
end
|
||||
|
||||
test "exec interactive with reuse" do
|
||||
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
||||
.with("ssh -t root@1.1.1.1 -p 22 'docker exec -it app-web-999 ruby -v'")
|
||||
|
||||
run_command("exec", "-i", "--reuse", "ruby -v").tap do |output|
|
||||
assert_hook_ran "pre-connect", output
|
||||
assert_match "Get current version of running container...", output
|
||||
assert_match "Running /usr/bin/env sh -c 'docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting' | head -1 | while read line; do echo ${line#app-web-}; done on 1.1.1.1", output
|
||||
assert_match "Launching interactive command with version 999 via SSH from existing container on 1.1.1.1...", output
|
||||
@@ -437,6 +482,24 @@ class CliAppTest < CliTestCase
|
||||
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
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def run_command(*command, config: :with_accessories, host: "1.1.1.1", allow_execute_error: false)
|
||||
stdouted do
|
||||
|
||||
@@ -57,6 +57,7 @@ class CliBuildTest < CliTestCase
|
||||
stub_setup
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "--version", "&&", :docker, :buildx, "version")
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute).with { |*args| args[0..1] == [ :docker, :login ] }
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||
.with(:git, "-C", "#{Dir.tmpdir}/kamal-clones/app-#{pwd_sha}", :clone, Dir.pwd, "--recurse-submodules")
|
||||
@@ -103,6 +104,7 @@ class CliBuildTest < CliTestCase
|
||||
stub_setup
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "--version", "&&", :docker, :buildx, "version")
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute).with { |*args| args[0..1] == [ :docker, :login ] }
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||
.with(:git, "-C", "#{Dir.tmpdir}/kamal-clones/app-#{pwd_sha}", :clone, Dir.pwd, "--recurse-submodules")
|
||||
@@ -139,6 +141,9 @@ class CliBuildTest < CliTestCase
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||
.with(:docker, "--version", "&&", :docker, :buildx, "version")
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||
.with { |*args| args[0..1] == [ :docker, :login ] }
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||
.with(:docker, :buildx, :rm, "kamal-local-docker-container")
|
||||
|
||||
@@ -321,7 +326,7 @@ class CliBuildTest < CliTestCase
|
||||
|
||||
private
|
||||
def run_command(*command, fixture: :with_accessories)
|
||||
stdouted { Kamal::Cli::Build.start([ *command, "-c", "test/fixtures/deploy_#{fixture}.yml" ]) }
|
||||
stdouted { stderred { Kamal::Cli::Build.start([ *command, "-c", "test/fixtures/deploy_#{fixture}.yml" ]) } }
|
||||
end
|
||||
|
||||
def stub_dependency_checks
|
||||
|
||||
@@ -21,7 +21,6 @@ class CliMainTest < CliTestCase
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:server:bootstrap", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:boot", [ "all" ], invoke_options)
|
||||
# deploy
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: true))
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:pull", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||
@@ -32,7 +31,6 @@ class CliMainTest < CliTestCase
|
||||
assert_match /Ensure Docker is installed.../, output
|
||||
# deploy
|
||||
assert_match /Acquiring the deploy lock/, output
|
||||
assert_match /Log into image registry/, output
|
||||
assert_match /Pull app image/, output
|
||||
assert_match /Ensure kamal-proxy is running/, output
|
||||
assert_match /Detect stale containers/, output
|
||||
@@ -45,8 +43,7 @@ class CliMainTest < CliTestCase
|
||||
with_test_secrets("secrets" => "DB_PASSWORD=secret") do
|
||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false, "verbose" => true }
|
||||
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:boot", [], invoke_options)
|
||||
@@ -56,8 +53,7 @@ class CliMainTest < CliTestCase
|
||||
|
||||
run_command("deploy", "--verbose").tap do |output|
|
||||
assert_hook_ran "pre-connect", output
|
||||
assert_match /Log into image registry/, output
|
||||
assert_match /Build and push app image/, 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 /Detect stale containers/, output
|
||||
@@ -70,7 +66,6 @@ class CliMainTest < CliTestCase
|
||||
test "deploy with skip_push" do
|
||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false }
|
||||
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: true))
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:pull", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||
@@ -79,7 +74,6 @@ class CliMainTest < CliTestCase
|
||||
|
||||
run_command("deploy", "--skip_push").tap do |output|
|
||||
assert_match /Acquiring the deploy lock/, output
|
||||
assert_match /Log into image registry/, output
|
||||
assert_match /Pull app image/, output
|
||||
assert_match /Ensure kamal-proxy is running/, output
|
||||
assert_match /Detect stale containers/, output
|
||||
@@ -153,11 +147,11 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
end
|
||||
|
||||
test "deploy errors during outside section leave remove lock" do
|
||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false, :skip_local => false }
|
||||
test "deploy errors during outside section leave remote lock" do
|
||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false }
|
||||
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke)
|
||||
.with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
||||
.with("kamal:cli:build:deliver", [], invoke_options)
|
||||
.raises(RuntimeError)
|
||||
|
||||
assert_not KAMAL.holding_lock?
|
||||
@@ -170,7 +164,6 @@ class CliMainTest < CliTestCase
|
||||
test "deploy with skipped hooks" do
|
||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => true }
|
||||
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||
@@ -185,7 +178,6 @@ class CliMainTest < CliTestCase
|
||||
test "deploy with missing secrets" do
|
||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_secrets.yml", "version" => "999", "skip_hooks" => false }
|
||||
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||
|
||||
@@ -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 --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config 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 --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config 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
|
||||
|
||||
|
||||
@@ -497,6 +497,30 @@ class CommandsAppTest < ActiveSupport::TestCase
|
||||
], new_command(asset_path: "/public/assets").clean_up_assets
|
||||
end
|
||||
|
||||
test "live" do
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy resume app-web",
|
||||
new_command.live.join(" ")
|
||||
end
|
||||
|
||||
test "maintenance" do
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-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\"",
|
||||
new_command.maintenance(drain_timeout: 10, message: "Hi").join(" ")
|
||||
end
|
||||
|
||||
test "remove_proxy_app_directory" do
|
||||
assert_equal \
|
||||
"rm -r .kamal/proxy/apps-config/app",
|
||||
new_command.remove_proxy_app_directory.join(" ")
|
||||
end
|
||||
|
||||
private
|
||||
def new_command(role: "web", host: "1.1.1.1", **additional_config)
|
||||
config = Kamal::Configuration.new(@config.merge(additional_config), destination: @destination, version: "999")
|
||||
|
||||
@@ -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 --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config",
|
||||
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 --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config",
|
||||
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"))
|
||||
|
||||
@@ -187,4 +187,12 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
||||
assert @config.accessory(:monitoring).running_proxy?
|
||||
assert_equal [ "monitoring.example.com" ], @config.accessory(:monitoring).proxy.hosts
|
||||
end
|
||||
|
||||
test "can't set restart in options" do
|
||||
@deploy[:accessories]["mysql"]["options"] = { "restart" => "always" }
|
||||
|
||||
assert_raises Kamal::ConfigurationError, "servers/workers: Cannot set restart policy in docker options, unless-stopped is required" do
|
||||
Kamal::Configuration.new(@deploy)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,6 +38,13 @@ class ConfigurationProxyTest < ActiveSupport::TestCase
|
||||
assert_not config.proxy.ssl?
|
||||
end
|
||||
|
||||
test "false not allowed" do
|
||||
@deploy[:proxy] = false
|
||||
assert_raises(Kamal::ConfigurationError, "proxy: should be a hash") do
|
||||
config.proxy
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def config
|
||||
Kamal::Configuration.new(@deploy)
|
||||
|
||||
@@ -258,6 +258,14 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
||||
assert_equal "18s", config_with_roles.role(:workers).proxy.deploy_options[:"target-timeout"]
|
||||
end
|
||||
|
||||
test "can't set restart in options" do
|
||||
@deploy_with_roles[:servers]["workers"]["options"] = { "restart" => "always" }
|
||||
|
||||
assert_raises Kamal::ConfigurationError, "servers/workers: Cannot set restart policy in docker options, unless-stopped is required" do
|
||||
Kamal::Configuration.new(@deploy_with_roles)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def config
|
||||
Kamal::Configuration.new(@deploy)
|
||||
|
||||
@@ -30,7 +30,7 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
%i[ service image registry ].each do |key|
|
||||
test "#{key} config required" do
|
||||
assert_raise(Kamal::ConfigurationError) do
|
||||
Kamal::Configuration.new @deploy.tap { _1.delete key }
|
||||
Kamal::Configuration.new @deploy.tap { |config| config.delete key }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -38,21 +38,36 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
%w[ username password ].each do |key|
|
||||
test "registry #{key} required" do
|
||||
assert_raise(Kamal::ConfigurationError) do
|
||||
Kamal::Configuration.new @deploy.tap { _1[:registry].delete key }
|
||||
Kamal::Configuration.new @deploy.tap { |config| config[:registry].delete key }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "service name valid" do
|
||||
assert_nothing_raised do
|
||||
Kamal::Configuration.new(@deploy.tap { _1[:service] = "hey-app1_primary" })
|
||||
Kamal::Configuration.new(@deploy.tap { _1[:service] = "MyApp" })
|
||||
Kamal::Configuration.new(@deploy.tap { |config| config[:service] = "hey-app1_primary" })
|
||||
Kamal::Configuration.new(@deploy.tap { |config| config[:service] = "MyApp" })
|
||||
end
|
||||
end
|
||||
|
||||
test "service name invalid" do
|
||||
assert_raise(Kamal::ConfigurationError) do
|
||||
Kamal::Configuration.new @deploy.tap { _1[:service] = "app.com" }
|
||||
Kamal::Configuration.new @deploy.tap { |config| config[:service] = "app.com" }
|
||||
end
|
||||
end
|
||||
|
||||
test "servers required" do
|
||||
assert_raise(Kamal::ConfigurationError) do
|
||||
Kamal::Configuration.new @deploy.tap { |config| config.delete(:servers) }
|
||||
end
|
||||
end
|
||||
|
||||
test "servers not required with accessories" do
|
||||
assert_nothing_raised do
|
||||
@deploy.delete(:servers)
|
||||
@deploy[:accessories] = { "foo" => { "image" => "foo/bar", "host" => "1.1.1.1" } }
|
||||
|
||||
Kamal::Configuration.new(@deploy)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -250,7 +265,7 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
test "destination required" do
|
||||
dest_config_file = Pathname.new(File.expand_path("fixtures/deploy_for_required_dest.yml", __dir__))
|
||||
|
||||
assert_raises(Kamal::ConfigurationError) do
|
||||
assert_raises(ArgumentError, "You must specify a destination") do
|
||||
config = Kamal::Configuration.create_from config_file: dest_config_file
|
||||
end
|
||||
|
||||
@@ -395,4 +410,13 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
|
||||
assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message
|
||||
end
|
||||
|
||||
test "proxy directories" do
|
||||
assert_equal ".kamal/proxy/apps-config", @config.proxy_apps_directory
|
||||
assert_equal "/home/kamal-proxy/.apps-config", @config.proxy_apps_container_directory
|
||||
assert_equal ".kamal/proxy/apps-config/app", @config.proxy_app_directory
|
||||
assert_equal "/home/kamal-proxy/.apps-config/app", @config.proxy_app_container_directory
|
||||
assert_equal ".kamal/proxy/apps-config/app/error_pages", @config.proxy_error_pages_directory
|
||||
assert_equal "/home/kamal-proxy/.apps-config/app/error_pages", @config.proxy_error_pages_container_directory
|
||||
end
|
||||
end
|
||||
|
||||
11
test/fixtures/deploy_with_error_pages.yml
vendored
Normal file
11
test/fixtures/deploy_with_error_pages.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
service: app
|
||||
image: dhh/app
|
||||
servers:
|
||||
- "1.1.1.1"
|
||||
- "1.1.1.2"
|
||||
registry:
|
||||
username: user
|
||||
password: pw
|
||||
builder:
|
||||
arch: amd64
|
||||
error_pages_path: public
|
||||
@@ -17,10 +17,39 @@ class AccessoryTest < IntegrationTest
|
||||
logs = kamal :accessory, :logs, :busybox, capture: true
|
||||
assert_match /Starting busybox.../, logs
|
||||
|
||||
boot = kamal :accessory, :boot, :busybox, capture: true
|
||||
assert_match /Skipping booting `busybox` on vm1, vm2, a container already exists/, boot
|
||||
|
||||
kamal :accessory, :remove, :busybox, "-y"
|
||||
assert_accessory_not_running :busybox
|
||||
end
|
||||
|
||||
test "proxied: boot, stop, start, restart, logs, remove" do
|
||||
@app = "app_with_proxied_accessory"
|
||||
|
||||
kamal :proxy, :boot
|
||||
|
||||
kamal :accessory, :boot, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :stop, :netcat
|
||||
assert_accessory_not_running :netcat
|
||||
assert_netcat_not_found
|
||||
|
||||
kamal :accessory, :start, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :restart, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :remove, :netcat, "-y"
|
||||
assert_accessory_not_running :netcat
|
||||
assert_netcat_not_found
|
||||
end
|
||||
|
||||
private
|
||||
def assert_accessory_running(name)
|
||||
assert_match /registry:4443\/busybox:1.36.0 "sh -c 'echo \\"Start/, accessory_details(name)
|
||||
@@ -33,4 +62,25 @@ class AccessoryTest < IntegrationTest
|
||||
def accessory_details(name)
|
||||
kamal :accessory, :details, name, capture: true
|
||||
end
|
||||
|
||||
def assert_netcat_is_up
|
||||
response = netcat_response
|
||||
debug_response_code(response, "200")
|
||||
assert_equal "200", response.code
|
||||
end
|
||||
|
||||
def assert_netcat_not_found
|
||||
response = netcat_response
|
||||
debug_response_code(response, "404")
|
||||
assert_equal "404", response.code
|
||||
end
|
||||
|
||||
def netcat_response
|
||||
uri = URI.parse("http://127.0.0.1:12345/up")
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request["Host"] = "netcat"
|
||||
|
||||
http.request(request)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,9 +48,36 @@ class AppTest < IntegrationTest
|
||||
assert_match "App Host: vm1", exec_output
|
||||
assert_match /1 root 0:\d\d nginx/, exec_output
|
||||
|
||||
kamal :app, :maintenance
|
||||
assert_app_in_maintenance
|
||||
|
||||
kamal :app, :live
|
||||
assert_app_is_up
|
||||
|
||||
kamal :app, :remove
|
||||
|
||||
assert_app_not_found
|
||||
assert_app_directory_removed
|
||||
end
|
||||
|
||||
test "custom error pages" do
|
||||
@app = "app_with_roles"
|
||||
|
||||
kamal :deploy
|
||||
assert_app_is_up
|
||||
|
||||
kamal :app, :maintenance
|
||||
assert_app_in_maintenance message: "Custom Maintenance Page"
|
||||
|
||||
kamal :app, :live
|
||||
kamal :app, :maintenance, "--message", "\"Testing Maintence Mode\""
|
||||
assert_app_in_maintenance message: "Custom Maintenance Page: Testing Maintence Mode"
|
||||
|
||||
second_version = update_app_rev
|
||||
|
||||
kamal :redeploy
|
||||
|
||||
kamal :app, :maintenance
|
||||
assert_app_in_maintenance message: "Custom Maintenance Page"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -41,3 +41,8 @@ accessories:
|
||||
cmd: sh -c 'echo "Starting busybox..."; trap exit term; while true; do sleep 1; done'
|
||||
roles:
|
||||
- web
|
||||
busybox2:
|
||||
service: custom-busybox
|
||||
image: registry:4443/busybox:1.36.0
|
||||
cmd: sh -c 'echo "Starting busybox..."; trap exit term; while true; do sleep 1; done'
|
||||
host: vm3
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
service: app_with_proxied_accessory
|
||||
image: app_with_proxied_accessory
|
||||
servers:
|
||||
- vm1
|
||||
env:
|
||||
clear:
|
||||
CLEAR_TOKEN: 4321
|
||||
@@ -24,15 +22,13 @@ accessories:
|
||||
service: custom-busybox
|
||||
image: registry:4443/busybox:1.36.0
|
||||
cmd: sh -c 'echo "Starting busybox..."; trap exit term; while true; do sleep 1; done'
|
||||
roles:
|
||||
- web
|
||||
host: vm1
|
||||
netcat:
|
||||
service: netcat
|
||||
image: registry:4443/busybox:1.36.0
|
||||
cmd: >
|
||||
sh -c 'echo "Starting netcat..."; while true; do echo -e "HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHello Ruby" | nc -l -p 80; done'
|
||||
roles:
|
||||
- web
|
||||
host: vm1
|
||||
port: 12345:80
|
||||
proxy:
|
||||
host: netcat
|
||||
@@ -41,4 +37,4 @@ accessories:
|
||||
interval: 1
|
||||
timeout: 1
|
||||
path: "/"
|
||||
|
||||
drain_timeout: 2
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -37,6 +37,7 @@ proxy:
|
||||
- X-Request-Start
|
||||
|
||||
asset_path: /usr/share/nginx/html/versions
|
||||
error_pages_path: error_pages
|
||||
|
||||
registry:
|
||||
server: registry:4443
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>503 Service Interrupted</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Custom Maintenance Page: {{ .Message }}</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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\"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM registry
|
||||
FROM registry:3
|
||||
|
||||
COPY boot.sh .
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
while [ ! -f /certs/domain.crt ]; do sleep 1; done
|
||||
|
||||
exec /entrypoint.sh /etc/docker/registry/config.yml
|
||||
exec /entrypoint.sh /etc/distribution/config.yml
|
||||
|
||||
@@ -11,7 +11,7 @@ class IntegrationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
teardown do
|
||||
unless passed?
|
||||
if !passed? && ENV["DEBUG_CONTAINER_LOGS"]
|
||||
[ :deployer, :vm1, :vm2, :shared, :load_balancer, :registry ].each do |container|
|
||||
puts
|
||||
puts "Logs for #{container}:"
|
||||
@@ -25,8 +25,8 @@ class IntegrationTest < ActiveSupport::TestCase
|
||||
def docker_compose(*commands, capture: false, raise_on_error: true)
|
||||
command = "TEST_ID=#{ENV["TEST_ID"]} docker compose #{commands.join(" ")}"
|
||||
succeeded = false
|
||||
if capture
|
||||
result = stdouted { succeeded = system("cd test/integration && #{command}") }
|
||||
if capture || !ENV["DEBUG"]
|
||||
result = stdouted { stderred { succeeded = system("cd test/integration && #{command}") } }
|
||||
else
|
||||
succeeded = system("cd test/integration && #{command}")
|
||||
end
|
||||
@@ -45,15 +45,22 @@ class IntegrationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
def assert_app_is_down
|
||||
response = app_response
|
||||
debug_response_code(response, "502")
|
||||
assert_equal "502", response.code
|
||||
assert_app_error_code("502")
|
||||
end
|
||||
|
||||
def assert_app_in_maintenance(message: nil)
|
||||
assert_app_error_code("503", message: message)
|
||||
end
|
||||
|
||||
def assert_app_not_found
|
||||
assert_app_error_code("404")
|
||||
end
|
||||
|
||||
def assert_app_error_code(code, message: nil)
|
||||
response = app_response
|
||||
debug_response_code(response, "404")
|
||||
assert_equal "404", response.code
|
||||
debug_response_code(response, code)
|
||||
assert_equal code, response.code
|
||||
assert_match message, response.body.strip if message
|
||||
end
|
||||
|
||||
def assert_app_is_up(version: nil, app: @app)
|
||||
|
||||
@@ -60,7 +60,7 @@ class MainTest < IntegrationTest
|
||||
version = latest_app_version
|
||||
|
||||
assert_equal [ "web" ], config[:roles]
|
||||
assert_equal [ "vm1", "vm2" ], config[:hosts]
|
||||
assert_equal [ "vm1", "vm2", "vm3" ], config[:hosts]
|
||||
assert_equal "vm1", config[:primary_host]
|
||||
assert_equal version, config[:version]
|
||||
assert_equal "registry:4443/app", config[:repository]
|
||||
@@ -88,8 +88,6 @@ class MainTest < IntegrationTest
|
||||
end
|
||||
|
||||
test "setup and remove" do
|
||||
@app = "app_with_roles"
|
||||
|
||||
kamal :proxy, :boot_config, "set",
|
||||
"--publish=false",
|
||||
"--docker-options=label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http",
|
||||
@@ -172,21 +170,25 @@ class MainTest < IntegrationTest
|
||||
assert_equal "200", Net::HTTP.get_response(URI.parse("http://#{app_host}:12345/versions/.hidden")).code
|
||||
end
|
||||
|
||||
def vm1_image_ids
|
||||
docker_compose("exec vm1 docker image ls -q", capture: true).strip.split("\n")
|
||||
def image_ids(vm:)
|
||||
docker_compose("exec #{vm} docker image ls -q", capture: true).strip.split("\n")
|
||||
end
|
||||
|
||||
def vm1_container_ids
|
||||
docker_compose("exec vm1 docker ps -a -q", capture: true).strip.split("\n")
|
||||
def container_ids(vm:)
|
||||
docker_compose("exec #{vm} docker ps -a -q", capture: true).strip.split("\n")
|
||||
end
|
||||
|
||||
def assert_no_images_or_containers
|
||||
assert vm1_image_ids.empty?
|
||||
assert vm1_container_ids.empty?
|
||||
[ :vm1, :vm2, :vm3 ].each do |vm|
|
||||
assert image_ids(vm: vm).empty?
|
||||
assert container_ids(vm: vm).empty?
|
||||
end
|
||||
end
|
||||
|
||||
def assert_images_and_containers
|
||||
assert vm1_image_ids.any?
|
||||
assert vm1_container_ids.any?
|
||||
[ :vm1, :vm2, :vm3 ].each do |vm|
|
||||
assert image_ids(vm: vm).any?
|
||||
assert container_ids(vm: vm).any?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
require_relative "integration_test"
|
||||
|
||||
class ProxiedAccessoryTest < IntegrationTest
|
||||
test "boot, stop, start, restart, logs, remove" do
|
||||
@app = "app_with_proxied_accessory"
|
||||
|
||||
kamal :deploy
|
||||
|
||||
kamal :accessory, :boot, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :stop, :netcat
|
||||
assert_accessory_not_running :netcat
|
||||
assert_netcat_not_found
|
||||
|
||||
kamal :accessory, :start, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :restart, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :remove, :netcat, "-y"
|
||||
assert_accessory_not_running :netcat
|
||||
assert_netcat_not_found
|
||||
end
|
||||
|
||||
private
|
||||
def assert_accessory_running(name)
|
||||
assert_match /registry:4443\/busybox:1.36.0 "sh -c 'echo \\"Start/, accessory_details(name)
|
||||
end
|
||||
|
||||
def assert_accessory_not_running(name)
|
||||
assert_no_match /registry:4443\/busybox:1.36.0 "sh -c 'echo \\"Start/, accessory_details(name)
|
||||
end
|
||||
|
||||
def accessory_details(name)
|
||||
kamal :accessory, :details, name, capture: true
|
||||
end
|
||||
|
||||
def assert_netcat_is_up
|
||||
response = netcat_response
|
||||
debug_response_code(response, "200")
|
||||
assert_equal "200", response.code
|
||||
end
|
||||
|
||||
def assert_netcat_not_found
|
||||
response = netcat_response
|
||||
debug_response_code(response, "404")
|
||||
assert_equal "404", response.code
|
||||
end
|
||||
|
||||
def netcat_response
|
||||
uri = URI.parse("http://127.0.0.1:12345/up")
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request["Host"] = "netcat"
|
||||
|
||||
http.request(request)
|
||||
end
|
||||
end
|
||||
@@ -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"
|
||||
|
||||
@@ -4,7 +4,7 @@ class AwsSecretsManagerAdapterTest < SecretAdapterTestCase
|
||||
test "fails when errors are present" do
|
||||
stub_ticks.with("aws --version 2> /dev/null")
|
||||
stub_ticks
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list unknown1 unknown2 --profile default")
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list unknown1 unknown2 --profile default --output json")
|
||||
.returns(<<~JSON)
|
||||
{
|
||||
"SecretValues": [],
|
||||
@@ -33,7 +33,7 @@ class AwsSecretsManagerAdapterTest < SecretAdapterTestCase
|
||||
test "fetch" do
|
||||
stub_ticks.with("aws --version 2> /dev/null")
|
||||
stub_ticks
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret/KEY1 secret/KEY2 secret2/KEY3 --profile default")
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret/KEY1 secret/KEY2 secret2/KEY3 --profile default --output json")
|
||||
.returns(<<~JSON)
|
||||
{
|
||||
"SecretValues": [
|
||||
@@ -76,7 +76,7 @@ class AwsSecretsManagerAdapterTest < SecretAdapterTestCase
|
||||
test "fetch with string value" do
|
||||
stub_ticks.with("aws --version 2> /dev/null")
|
||||
stub_ticks
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret secret2/KEY1 --profile default")
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret secret2/KEY1 --profile default --output json")
|
||||
.returns(<<~JSON)
|
||||
{
|
||||
"SecretValues": [
|
||||
@@ -118,7 +118,7 @@ class AwsSecretsManagerAdapterTest < SecretAdapterTestCase
|
||||
test "fetch with secret names" do
|
||||
stub_ticks.with("aws --version 2> /dev/null")
|
||||
stub_ticks
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret/KEY1 secret/KEY2 --profile default")
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret/KEY1 secret/KEY2 --profile default --output json")
|
||||
.returns(<<~JSON)
|
||||
{
|
||||
"SecretValues": [
|
||||
@@ -159,7 +159,7 @@ class AwsSecretsManagerAdapterTest < SecretAdapterTestCase
|
||||
test "fetch without account option omits --profile" do
|
||||
stub_ticks.with("aws --version 2> /dev/null")
|
||||
stub_ticks
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret/KEY1 secret/KEY2")
|
||||
.with("aws secretsmanager batch-get-secret-value --secret-id-list secret/KEY1 secret/KEY2 --output json")
|
||||
.returns(<<~JSON)
|
||||
{
|
||||
"SecretValues": [
|
||||
|
||||
@@ -58,9 +58,7 @@ class ActiveSupport::TestCase
|
||||
def setup_test_secrets(**files)
|
||||
@original_pwd = Dir.pwd
|
||||
@secrets_tmpdir = Dir.mktmpdir
|
||||
fixtures_dup = File.join(@secrets_tmpdir, "test")
|
||||
FileUtils.mkdir_p(fixtures_dup)
|
||||
FileUtils.cp_r("test/fixtures/", fixtures_dup)
|
||||
copy_fixtures(@secrets_tmpdir)
|
||||
|
||||
Dir.chdir(@secrets_tmpdir)
|
||||
FileUtils.mkdir_p(".kamal")
|
||||
@@ -75,6 +73,30 @@ class ActiveSupport::TestCase
|
||||
Dir.chdir(@original_pwd)
|
||||
FileUtils.rm_rf(@secrets_tmpdir)
|
||||
end
|
||||
|
||||
def with_error_pages(directory:)
|
||||
error_pages_tmpdir = Dir.mktmpdir
|
||||
|
||||
Dir.mktmpdir do |tmpdir|
|
||||
copy_fixtures(tmpdir)
|
||||
|
||||
Dir.chdir(tmpdir) do
|
||||
FileUtils.mkdir_p(directory)
|
||||
Dir.chdir(directory) do
|
||||
File.write("404.html", "404 page")
|
||||
File.write("503.html", "503 page")
|
||||
end
|
||||
|
||||
yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def copy_fixtures(to_dir)
|
||||
new_test_dir = File.join(to_dir, "test")
|
||||
FileUtils.mkdir_p(new_test_dir)
|
||||
FileUtils.cp_r("test/fixtures/", new_test_dir)
|
||||
end
|
||||
end
|
||||
|
||||
class SecretAdapterTestCase < ActiveSupport::TestCase
|
||||
|
||||
Reference in New Issue
Block a user