Compare commits
18 Commits
v2.0.0.bet
...
v1.9.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21d7d6d79c | ||
|
|
f1b3c4a4fb | ||
|
|
fd9564f0c8 | ||
|
|
d2338251a9 | ||
|
|
b00a4ec3e2 | ||
|
|
4b09375ccd | ||
|
|
3e0302230e | ||
|
|
bce2d35e9f | ||
|
|
46ea88a056 | ||
|
|
fa05270cac | ||
|
|
b058c45973 | ||
|
|
9db1403721 | ||
|
|
bf4add9e72 | ||
|
|
7c7785c1eb | ||
|
|
80bd46cde3 | ||
|
|
b449321a45 | ||
|
|
24a7e94c14 | ||
|
|
d269fc5d36 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -3,6 +3,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 1-9-stable
|
||||||
pull_request:
|
pull_request:
|
||||||
jobs:
|
jobs:
|
||||||
rubocop:
|
rubocop:
|
||||||
@@ -30,6 +31,9 @@ jobs:
|
|||||||
gemfile:
|
gemfile:
|
||||||
- Gemfile
|
- Gemfile
|
||||||
- gemfiles/rails_edge.gemfile
|
- gemfiles/rails_edge.gemfile
|
||||||
|
exclude:
|
||||||
|
- ruby-version: "3.1"
|
||||||
|
gemfile: gemfiles/rails_edge.gemfile
|
||||||
name: ${{ format('Tests (Ruby {0})', matrix.ruby-version) }}
|
name: ${{ format('Tests (Ruby {0})', matrix.ruby-version) }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|||||||
3
.github/workflows/docker-publish.yml
vendored
3
.github/workflows/docker-publish.yml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
tagInput:
|
tagInput:
|
||||||
description: 'Tag'
|
description: 'Tag'
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
tags:
|
tags:
|
||||||
@@ -51,5 +51,4 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
ghcr.io/basecamp/kamal:latest
|
|
||||||
ghcr.io/basecamp/kamal:${{ steps.version-tag.outputs.value }}
|
ghcr.io/basecamp/kamal:${{ steps.version-tag.outputs.value }}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ WORKDIR /workdir
|
|||||||
|
|
||||||
# Tell git it's safe to access /workdir/.git even if
|
# Tell git it's safe to access /workdir/.git even if
|
||||||
# the directory is owned by a different user
|
# the directory is owned by a different user
|
||||||
RUN git config --global --add safe.directory /workdir
|
RUN git config --global --add safe.directory '*'
|
||||||
|
|
||||||
# Set the entrypoint to run the installed binary in /workdir
|
# Set the entrypoint to run the installed binary in /workdir
|
||||||
# Example: docker run -it -v "$PWD:/workdir" kamal init
|
# Example: docker run -it -v "$PWD:/workdir" kamal init
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
kamal (1.8.2)
|
kamal (1.9.2)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
|
|||||||
@@ -222,6 +222,25 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "downgrade", "Downgrade accessories from Kamal 2 to 1.9"
|
||||||
|
option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
|
||||||
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
|
def downgrade(name)
|
||||||
|
confirming "This will restart all accessories" do
|
||||||
|
with_lock do
|
||||||
|
host_groups = options[:rolling] ? KAMAL.accessory_hosts : [ KAMAL.accessory_hosts ]
|
||||||
|
host_groups.each do |hosts|
|
||||||
|
host_list = Array(hosts).join(",")
|
||||||
|
KAMAL.with_specific_hosts(hosts) do
|
||||||
|
say "Downgrading #{name} accessories on #{host_list}...", :magenta
|
||||||
|
reboot name
|
||||||
|
say "Downgraded #{name} accessories on #{host_list}...", :magenta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def with_accessory(name)
|
def with_accessory(name)
|
||||||
if KAMAL.config.accessory(name)
|
if KAMAL.config.accessory(name)
|
||||||
|
|||||||
@@ -206,6 +206,10 @@ module Kamal::Cli
|
|||||||
instance_variable_get("@_invocations").first
|
instance_variable_get("@_invocations").first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset_invocation(cli_class)
|
||||||
|
instance_variable_get("@_invocations")[cli_class].pop
|
||||||
|
end
|
||||||
|
|
||||||
def ensure_run_and_locks_directory
|
def ensure_run_and_locks_directory
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.hosts) do
|
||||||
execute(*KAMAL.server.ensure_run_directory)
|
execute(*KAMAL.server.ensure_run_directory)
|
||||||
|
|||||||
@@ -217,6 +217,37 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "downgrade", "Downgrade from Kamal 2 to 1.9"
|
||||||
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
|
option :rolling, type: :boolean, default: false, desc: "Downgrade one host at a time"
|
||||||
|
def downgrade
|
||||||
|
confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
|
||||||
|
with_lock do
|
||||||
|
if options[:rolling]
|
||||||
|
(KAMAL.hosts | KAMAL.accessory_hosts).each do |host|
|
||||||
|
KAMAL.with_specific_hosts(host) do
|
||||||
|
say "Downgrading #{host}...", :magenta
|
||||||
|
if KAMAL.hosts.include?(host)
|
||||||
|
invoke "kamal:cli:traefik:downgrade", [], options.merge(confirmed: true, rolling: false)
|
||||||
|
reset_invocation(Kamal::Cli::Traefik)
|
||||||
|
end
|
||||||
|
if KAMAL.accessory_hosts.include?(host)
|
||||||
|
invoke "kamal:cli:accessory:downgrade", [ "all" ], options.merge(confirmed: true, rolling: false)
|
||||||
|
reset_invocation(Kamal::Cli::Accessory)
|
||||||
|
end
|
||||||
|
say "Downgraded #{host}", :magenta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
say "Downgrading all hosts...", :magenta
|
||||||
|
invoke "kamal:cli:traefik:downgrade", [], options.merge(confirmed: true)
|
||||||
|
invoke "kamal:cli:accessory:downgrade", [ "all" ], options.merge(confirmed: true)
|
||||||
|
say "Downgraded all hosts", :magenta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc "version", "Show Kamal version"
|
desc "version", "Show Kamal version"
|
||||||
def version
|
def version
|
||||||
puts Kamal::VERSION
|
puts Kamal::VERSION
|
||||||
|
|||||||
@@ -119,4 +119,44 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "downgrade", "Downgrade to Traefik on servers (stop container, remove container, start new container, reboot app)"
|
||||||
|
option :rolling, type: :boolean, default: false, desc: "Reboot proxy on hosts in sequence, rather than in parallel"
|
||||||
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
|
def downgrade
|
||||||
|
invoke_options = { "version" => KAMAL.config.latest_tag }.merge(options)
|
||||||
|
|
||||||
|
confirming "This will cause a brief outage on each host. Are you sure?" do
|
||||||
|
host_groups = options[:rolling] ? KAMAL.hosts : [ KAMAL.hosts ]
|
||||||
|
host_groups.each do |hosts|
|
||||||
|
host_list = Array(hosts).join(",")
|
||||||
|
say "Downgrading to Traefik on #{host_list}...", :magenta
|
||||||
|
run_hook "pre-traefik-reboot", hosts: host_list
|
||||||
|
on(hosts) do |host|
|
||||||
|
execute *KAMAL.auditor.record("Rebooted Traefik"), verbosity: :debug
|
||||||
|
execute *KAMAL.registry.login
|
||||||
|
|
||||||
|
"Stopping and removing kamal-proxy on #{host}, if running..."
|
||||||
|
execute *KAMAL.traefik.cleanup_kamal_proxy
|
||||||
|
|
||||||
|
"Stopping and removing Traefik on #{host}, if running..."
|
||||||
|
execute *KAMAL.traefik.stop, raise_on_non_zero_exit: false
|
||||||
|
execute *KAMAL.traefik.remove_container
|
||||||
|
execute *KAMAL.traefik.remove_image
|
||||||
|
end
|
||||||
|
|
||||||
|
KAMAL.with_specific_hosts(hosts) do
|
||||||
|
invoke "kamal:cli:traefik:boot", [], invoke_options
|
||||||
|
reset_invocation(Kamal::Cli::Traefik)
|
||||||
|
invoke "kamal:cli:app:boot", [], invoke_options
|
||||||
|
reset_invocation(Kamal::Cli::App)
|
||||||
|
invoke "kamal:cli:prune:all", [], invoke_options
|
||||||
|
reset_invocation(Kamal::Cli::Prune)
|
||||||
|
end
|
||||||
|
|
||||||
|
run_hook "post-traefik-reboot", hosts: host_list
|
||||||
|
say "Downgraded to Traefik on #{host_list}", :magenta
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,6 +56,13 @@ class Kamal::Commander
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_specific_hosts(hosts)
|
||||||
|
original_hosts, self.specific_hosts = specific_hosts, hosts
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
self.specific_hosts = original_hosts
|
||||||
|
end
|
||||||
|
|
||||||
def accessory_names
|
def accessory_names
|
||||||
config.accessories&.collect(&:name) || []
|
config.accessories&.collect(&:name) || []
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Kamal::Commander::Specifics
|
|||||||
end
|
end
|
||||||
|
|
||||||
def accessory_hosts
|
def accessory_hosts
|
||||||
specific_hosts || config.accessories.flat_map(&:hosts)
|
config.accessories.flat_map(&:hosts) & specified_hosts
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -58,4 +58,8 @@ class Kamal::Commands::Builder::Multiarch::Remote < Kamal::Commands::Builder::Mu
|
|||||||
def remove_context(arch)
|
def remove_context(arch)
|
||||||
docker :context, :rm, builder_name_with_arch(arch)
|
docker :context, :rm, builder_name_with_arch(arch)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def platform_names
|
||||||
|
"linux/#{local_arch},linux/#{remote_arch}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -62,6 +62,15 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|||||||
[ :rm, "-f", env.secrets_file ]
|
[ :rm, "-f", env.secrets_file ]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cleanup_kamal_proxy
|
||||||
|
chain \
|
||||||
|
docker(:container, :stop, "kamal-proxy"),
|
||||||
|
combine(
|
||||||
|
docker(:container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy"),
|
||||||
|
docker(:image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def publish_args
|
def publish_args
|
||||||
argumentize "--publish", port if publish?
|
argumentize "--publish", port if publish?
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ traefik:
|
|||||||
|
|
||||||
# Image
|
# Image
|
||||||
#
|
#
|
||||||
# The Traefik image to use, defaults to `traefik:v2.10`
|
# The Traefik image to use, defaults to `traefik:v2.11`
|
||||||
image: traefik:v2.9
|
image: traefik:v2.11
|
||||||
|
|
||||||
# Host port
|
# Host port
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
class Kamal::Configuration::Traefik
|
class Kamal::Configuration::Traefik
|
||||||
DEFAULT_IMAGE = "traefik:v2.10"
|
DEFAULT_IMAGE = "traefik:v2.11"
|
||||||
CONTAINER_PORT = 80
|
CONTAINER_PORT = 80
|
||||||
DEFAULT_ARGS = {
|
DEFAULT_ARGS = {
|
||||||
"log.level" => "DEBUG"
|
"log.level" => "DEBUG"
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module Kamal
|
module Kamal
|
||||||
VERSION = "1.8.2"
|
VERSION = "1.9.2"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -209,6 +209,24 @@ class CliAccessoryTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "downgrade" do
|
||||||
|
run_command("downgrade", "-y", "all").tap do |output|
|
||||||
|
assert_match "Downgrading all accessories on 1.1.1.3,1.1.1.1,1.1.1.2...", output
|
||||||
|
assert_match "docker container stop app-mysql on 1.1.1.3", output
|
||||||
|
assert_match "docker run --name app-mysql --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 3306:3306 --env-file .kamal/env/accessories/app-mysql.env --env MYSQL_ROOT_HOST=\"%\" --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" mysql:5.7 on 1.1.1.3", output
|
||||||
|
assert_match "Downgraded all accessories on 1.1.1.3,1.1.1.1,1.1.1.2", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "downgrade rolling" do
|
||||||
|
run_command("downgrade", "--rolling", "-y", "all").tap do |output|
|
||||||
|
assert_match "Downgrading all accessories on 1.1.1.3...", output
|
||||||
|
assert_match "docker container stop app-mysql on 1.1.1.3", output
|
||||||
|
assert_match "docker run --name app-mysql --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 3306:3306 --env-file .kamal/env/accessories/app-mysql.env --env MYSQL_ROOT_HOST=\"%\" --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" mysql:5.7 on 1.1.1.3", output
|
||||||
|
assert_match "Downgraded all accessories on 1.1.1.3", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command)
|
def run_command(*command)
|
||||||
stdouted { Kamal::Cli::Accessory.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
stdouted { Kamal::Cli::Accessory.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
||||||
|
|||||||
@@ -537,6 +537,34 @@ class CliMainTest < CliTestCase
|
|||||||
assert_equal Kamal::VERSION, version
|
assert_equal Kamal::VERSION, version
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "downgrade" do
|
||||||
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_hooks" => false, "confirmed" => true, "rolling" => false }
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:downgrade", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:downgrade", [ "all" ], invoke_options)
|
||||||
|
|
||||||
|
run_command("downgrade", "-y", config_file: "deploy_with_accessories").tap do |output|
|
||||||
|
assert_match "Downgrading all hosts...", output
|
||||||
|
assert_match "Downgraded all hosts", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "downgrade rolling" do
|
||||||
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_hooks" => false, "confirmed" => true, "rolling" => false }
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:downgrade", [], invoke_options).times(4)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:downgrade", [ "all" ], invoke_options).times(3)
|
||||||
|
|
||||||
|
run_command("downgrade", "--rolling", "-y", config_file: "deploy_with_accessories").tap do |output|
|
||||||
|
assert_match "Downgrading 1.1.1.1...", output
|
||||||
|
assert_match "Downgraded 1.1.1.1", output
|
||||||
|
assert_match "Downgrading 1.1.1.2...", output
|
||||||
|
assert_match "Downgraded 1.1.1.2", output
|
||||||
|
assert_match "Downgrading 1.1.1.3...", output
|
||||||
|
assert_match "Downgraded 1.1.1.3", output
|
||||||
|
assert_match "Downgrading 1.1.1.4...", output
|
||||||
|
assert_match "Downgraded 1.1.1.4", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command, config_file: "deploy_simple")
|
def run_command(*command, config_file: "deploy_simple")
|
||||||
stdouted { Kamal::Cli::Main.start([ *command, "-c", "test/fixtures/#{config_file}.yml" ]) }
|
stdouted { Kamal::Cli::Main.start([ *command, "-c", "test/fixtures/#{config_file}.yml" ]) }
|
||||||
|
|||||||
@@ -103,6 +103,90 @@ class CliTraefikTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "downgrade" do
|
||||||
|
Object.any_instance.stubs(:sleep)
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", raise_on_non_zero_exit: false)
|
||||||
|
.returns("12345678")
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", raise_on_non_zero_exit: false)
|
||||||
|
.returns("12345678")
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with { |*args| args[0..1] == [ :sh, "-c" ] }
|
||||||
|
.returns("123") # old version
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
||||||
|
.returns("running") # health check
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(: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
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :inspect, "-f '{{ range .Mounts }}{{printf \"%s %s\\n\" .Source .Destination}}{{ end }}'", "app-web-123", "|", :awk, "'$2 == \"/tmp/kamal-cord\" {print $1}'", raise_on_non_zero_exit: false)
|
||||||
|
.returns("") # old version
|
||||||
|
|
||||||
|
run_command("downgrade", "-y").tap do |output|
|
||||||
|
assert_match "Downgrading to Traefik on 1.1.1.1,1.1.1.2,1.1.1.3,1.1.1.4...", output
|
||||||
|
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
|
||||||
|
assert_match "docker container stop kamal-proxy ; docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy && docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
||||||
|
assert_match "docker container stop traefik", output
|
||||||
|
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=Traefik", output
|
||||||
|
assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik", output
|
||||||
|
assert_match "/usr/bin/env mkdir -p .kamal", output
|
||||||
|
assert_match "docker login -u [REDACTED] -p [REDACTED]", output
|
||||||
|
assert_match "docker container start traefik || docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" traefik:v2.11 --providers.docker --log.level=\"DEBUG\"", 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 run --detach --restart unless-stopped --name app-web-latest --hostname 1.1.1.1-.* -e KAMAL_CONTAINER_NAME="app-web-latest" -e KAMAL_VERSION="latest" --env-file .kamal/env/roles/app-web.env --health-cmd}, output
|
||||||
|
assert_match "docker tag dhh/app:latest dhh/app:latest", output
|
||||||
|
assert_match "/usr/bin/env mkdir -p .kamal", output
|
||||||
|
assert_match "docker ps -q -a --filter label=service=app --filter status=created --filter status=exited --filter status=dead | tail -n +6 | while read container_id; do docker rm $container_id; done", output
|
||||||
|
assert_match "docker image prune --force --filter label=service=app", output
|
||||||
|
assert_match "Downgraded to Traefik on 1.1.1.1,1.1.1.2,1.1.1.3,1.1.1.4", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "downgrade rolling" do
|
||||||
|
Object.any_instance.stubs(:sleep)
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", raise_on_non_zero_exit: false)
|
||||||
|
.returns("12345678")
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", raise_on_non_zero_exit: false)
|
||||||
|
.returns("12345678")
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with { |*args| args[0..1] == [ :sh, "-c" ] }
|
||||||
|
.returns("123") # old version
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
||||||
|
.returns("running") # health check
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(: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
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info)
|
||||||
|
.with(:docker, :inspect, "-f '{{ range .Mounts }}{{printf \"%s %s\\n\" .Source .Destination}}{{ end }}'", "app-web-123", "|", :awk, "'$2 == \"/tmp/kamal-cord\" {print $1}'", raise_on_non_zero_exit: false)
|
||||||
|
.returns("") # old version
|
||||||
|
|
||||||
|
run_command("downgrade", "--rolling", "-y",).tap do |output|
|
||||||
|
%w[1.1.1.1 1.1.1.2 1.1.1.3 1.1.1.4].each do |host|
|
||||||
|
assert_match "Downgrading to Traefik on #{host}...", output
|
||||||
|
assert_match "docker container stop kamal-proxy ; docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy && docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
||||||
|
assert_match "Downgraded to Traefik on #{host}", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command)
|
def run_command(*command)
|
||||||
stdouted { Kamal::Cli::Traefik.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
stdouted { Kamal::Cli::Traefik.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ class CommandsBuilderTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "target multiarch remote when local and remote is set" do
|
test "target multiarch remote when local and remote is set" do
|
||||||
builder = new_builder_command(builder: { "local" => {}, "remote" => {}, "cache" => { "type" => "gha" } })
|
builder = new_builder_command(builder: { "local" => { "arch" => "arm64" }, "remote" => { "arch" => "amd64" }, "cache" => { "type" => "gha" } })
|
||||||
assert_equal "multiarch/remote", builder.name
|
assert_equal "multiarch/remote", builder.name
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker buildx build --push --platform linux/amd64,linux/arm64 --builder kamal-app-multiarch-remote -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
|
"docker buildx build --push --platform linux/arm64,linux/amd64 --builder kamal-app-multiarch-remote -t dhh/app:123 -t dhh/app:latest --cache-to type=gha --cache-from type=gha --label service=\"app\" --file Dockerfile .",
|
||||||
builder.push.join(" ")
|
builder.push.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ traefik:
|
|||||||
args:
|
args:
|
||||||
accesslog: true
|
accesslog: true
|
||||||
accesslog.format: json
|
accesslog.format: json
|
||||||
image: registry:4443/traefik:v2.10
|
image: registry:4443/traefik:v2.11
|
||||||
accessories:
|
accessories:
|
||||||
busybox:
|
busybox:
|
||||||
service: custom-busybox
|
service: custom-busybox
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ traefik:
|
|||||||
args:
|
args:
|
||||||
accesslog: true
|
accesslog: true
|
||||||
accesslog.format: json
|
accesslog.format: json
|
||||||
image: registry:4443/traefik:v2.10
|
image: registry:4443/traefik:v2.11
|
||||||
accessories:
|
accessories:
|
||||||
busybox:
|
busybox:
|
||||||
service: custom-busybox
|
service: custom-busybox
|
||||||
|
|||||||
@@ -19,7 +19,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 traefik v2.10
|
push_image_to_registry_4443 traefik v2.11
|
||||||
push_image_to_registry_4443 busybox 1.36.0
|
push_image_to_registry_4443 busybox 1.36.0
|
||||||
|
|
||||||
# .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
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class MainTest < IntegrationTest
|
|||||||
assert_match /Traefik Host: vm2/, details
|
assert_match /Traefik Host: vm2/, details
|
||||||
assert_match /App Host: vm1/, details
|
assert_match /App Host: vm1/, details
|
||||||
assert_match /App Host: vm2/, details
|
assert_match /App Host: vm2/, details
|
||||||
assert_match /traefik:v2.10/, details
|
assert_match /traefik:v2.11/, details
|
||||||
assert_match /registry:4443\/app:#{first_version}/, details
|
assert_match /registry:4443\/app:#{first_version}/, details
|
||||||
|
|
||||||
audit = kamal :audit, capture: true
|
audit = kamal :audit, capture: true
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ class TraefikTest < IntegrationTest
|
|||||||
|
|
||||||
private
|
private
|
||||||
def assert_traefik_running
|
def assert_traefik_running
|
||||||
assert_match /traefik:v2.10 "\/entrypoint.sh/, traefik_details
|
assert_match /traefik:v2.11 "\/entrypoint.sh/, traefik_details
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_traefik_not_running
|
def assert_traefik_not_running
|
||||||
assert_no_match /traefik:v2.10 "\/entrypoint.sh/, traefik_details
|
assert_no_match /traefik:v2.11 "\/entrypoint.sh/, traefik_details
|
||||||
end
|
end
|
||||||
|
|
||||||
def traefik_details
|
def traefik_details
|
||||||
|
|||||||
Reference in New Issue
Block a user