Merge branch 'basecamp:main' into valid_service_name

This commit is contained in:
Nick Hammond
2024-03-06 09:09:13 -07:00
committed by GitHub
11 changed files with 79 additions and 11 deletions

View File

@@ -20,7 +20,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
on(hosts) do on(hosts) do
execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug
execute *KAMAL.registry.login execute *KAMAL.registry.login
execute *KAMAL.traefik.stop execute *KAMAL.traefik.stop, raise_on_non_zero_exit: false
execute *KAMAL.traefik.remove_container execute *KAMAL.traefik.remove_container
execute *KAMAL.traefik.run execute *KAMAL.traefik.run
end end
@@ -44,7 +44,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
mutating do mutating do
on(KAMAL.traefik_hosts) do on(KAMAL.traefik_hosts) do
execute *KAMAL.auditor.record("Stopped traefik"), verbosity: :debug execute *KAMAL.auditor.record("Stopped traefik"), verbosity: :debug
execute *KAMAL.traefik.stop execute *KAMAL.traefik.stop, raise_on_non_zero_exit: false
end end
end end
end end

View File

@@ -24,7 +24,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
def validate_image def validate_image
pipe \ pipe \
docker(:inspect, "-f", "'{{ .Config.Labels.service }}'", config.absolute_image), docker(:inspect, "-f", "'{{ .Config.Labels.service }}'", config.absolute_image),
[:grep, "-x", config.service, "||", "(echo \"Image #{config.absolute_image} is missing the `service` label\" && exit 1)"] [:grep, "-x", config.service, "||", "(echo \"Image #{config.absolute_image} is missing the 'service' label\" && exit 1)"]
end end

View File

@@ -2,7 +2,10 @@ class Kamal::Commands::Registry < Kamal::Commands::Base
delegate :registry, to: :config delegate :registry, to: :config
def login def login
docker :login, registry["server"], "-u", sensitive(lookup("username")), "-p", sensitive(lookup("password")) docker :login,
registry["server"],
"-u", sensitive(Kamal::Utils.escape_shell_value(lookup("username"))),
"-p", sensitive(Kamal::Utils.escape_shell_value(lookup("password")))
end end
def logout def logout

View File

@@ -8,7 +8,7 @@ class Kamal::Configuration::Boot
limit = @options["limit"] limit = @options["limit"]
if limit.to_s.end_with?("%") if limit.to_s.end_with?("%")
@host_count * limit.to_i / 100 [@host_count * limit.to_i / 100, 1].max
else else
limit limit
end end

View File

@@ -57,7 +57,7 @@ class CliBuildTest < CliTestCase
run_command("pull").tap do |output| run_command("pull").tap do |output|
assert_match /docker image rm --force dhh\/app:999/, output assert_match /docker image rm --force dhh\/app:999/, output
assert_match /docker pull dhh\/app:999/, output assert_match /docker pull dhh\/app:999/, output
assert_match "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:999 | grep -x app || (echo \"Image dhh/app:999 is missing the `service` label\" && exit 1)", output assert_match "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:999 | grep -x app || (echo \"Image dhh/app:999 is missing the 'service' label\" && exit 1)", output
end end
end end

View File

@@ -109,6 +109,12 @@ class CommanderTest < ActiveSupport::TestCase
assert_equal({ in: :groups, limit: 1, wait: 2 }, @kamal.boot_strategy) assert_equal({ in: :groups, limit: 1, wait: 2 }, @kamal.boot_strategy)
end end
test "percentage-based group strategy limit is at least 1" do
configure_with(:deploy_with_low_percentage_boot_strategy)
assert_equal({ in: :groups, limit: 1, wait: 2 }, @kamal.boot_strategy)
end
test "try to match the primary role from a list of specific roles" do test "try to match the primary role from a list of specific roles" do
configure_with(:deploy_primary_web_role_override) configure_with(:deploy_primary_web_role_override)

View File

@@ -120,7 +120,7 @@ class CommandsBuilderTest < ActiveSupport::TestCase
end end
test "validate image" do test "validate image" do
assert_equal "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:123 | grep -x app || (echo \"Image dhh/app:123 is missing the `service` label\" && exit 1)", new_builder_command.validate_image.join(" ") assert_equal "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:123 | grep -x app || (echo \"Image dhh/app:123 is missing the 'service' label\" && exit 1)", new_builder_command.validate_image.join(" ")
end end
private private

View File

@@ -15,7 +15,7 @@ class CommandsRegistryTest < ActiveSupport::TestCase
test "registry login" do test "registry login" do
assert_equal \ assert_equal \
"docker login hub.docker.com -u dhh -p secret", "docker login hub.docker.com -u \"dhh\" -p \"secret\"",
@registry.login.join(" ") @registry.login.join(" ")
end end
@@ -24,7 +24,18 @@ class CommandsRegistryTest < ActiveSupport::TestCase
@config[:registry]["password"] = [ "KAMAL_REGISTRY_PASSWORD" ] @config[:registry]["password"] = [ "KAMAL_REGISTRY_PASSWORD" ]
assert_equal \ assert_equal \
"docker login hub.docker.com -u dhh -p more-secret", "docker login hub.docker.com -u \"dhh\" -p \"more-secret\"",
@registry.login.join(" ")
ensure
ENV.delete("KAMAL_REGISTRY_PASSWORD")
end
test "registry login escape password" do
ENV["KAMAL_REGISTRY_PASSWORD"] = "more-secret'\""
@config[:registry]["password"] = [ "KAMAL_REGISTRY_PASSWORD" ]
assert_equal \
"docker login hub.docker.com -u \"dhh\" -p \"more-secret'\\\"\"",
@registry.login.join(" ") @registry.login.join(" ")
ensure ensure
ENV.delete("KAMAL_REGISTRY_PASSWORD") ENV.delete("KAMAL_REGISTRY_PASSWORD")
@@ -35,7 +46,7 @@ class CommandsRegistryTest < ActiveSupport::TestCase
@config[:registry]["username"] = [ "KAMAL_REGISTRY_USERNAME" ] @config[:registry]["username"] = [ "KAMAL_REGISTRY_USERNAME" ]
assert_equal \ assert_equal \
"docker login hub.docker.com -u also-secret -p secret", "docker login hub.docker.com -u \"also-secret\" -p \"secret\"",
@registry.login.join(" ") @registry.login.join(" ")
ensure ensure
ENV.delete("KAMAL_REGISTRY_USERNAME") ENV.delete("KAMAL_REGISTRY_USERNAME")

View File

@@ -0,0 +1,17 @@
service: app
image: dhh/app
servers:
web:
- "1.1.1.1"
- "1.1.1.2"
workers:
- "1.1.1.3"
- "1.1.1.4"
registry:
username: user
password: pw
boot:
limit: 1%
wait: 2

View File

@@ -13,5 +13,5 @@ registry:
password: pw password: pw
boot: boot:
limit: 25% limit: 1%
wait: 2 wait: 2

View File

@@ -60,6 +60,19 @@ class MainTest < IntegrationTest
assert_equal({ "path" => "/up", "port" => 3000, "max_attempts" => 7, "exposed_port" => 3999, "cord"=>"/tmp/kamal-cord", "log_lines" => 50, "cmd"=>"wget -qO- http://localhost > /dev/null || exit 1" }, config[:healthcheck]) assert_equal({ "path" => "/up", "port" => 3000, "max_attempts" => 7, "exposed_port" => 3999, "cord"=>"/tmp/kamal-cord", "log_lines" => 50, "cmd"=>"wget -qO- http://localhost > /dev/null || exit 1" }, config[:healthcheck])
end end
test "setup and remove" do
# Check remove completes when nothing has been setup yet
kamal :remove, "-y"
assert_no_images_or_containers
kamal :envify
kamal :setup
assert_images_and_containers
kamal :remove, "-y"
assert_no_images_or_containers
end
private private
def assert_local_env_file(contents) def assert_local_env_file(contents)
assert_equal contents, deployer_exec("cat .env", capture: true) assert_equal contents, deployer_exec("cat .env", capture: true)
@@ -84,4 +97,22 @@ class MainTest < IntegrationTest
assert_equal "200", Net::HTTP.get_response(URI.parse("http://localhost:12345/versions/.hidden")).code assert_equal "200", Net::HTTP.get_response(URI.parse("http://localhost:12345/versions/.hidden")).code
end end
def vm1_image_ids
docker_compose("exec vm1 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")
end
def assert_no_images_or_containers
assert vm1_image_ids.empty?
assert vm1_container_ids.empty?
end
def assert_images_and_containers
assert vm1_image_ids.any?
assert vm1_container_ids.any?
end
end end