diff --git a/lib/kamal/cli/app.rb b/lib/kamal/cli/app.rb index d2f9c3f9..54d8a164 100644 --- a/lib/kamal/cli/app.rb +++ b/lib/kamal/cli/app.rb @@ -7,7 +7,7 @@ class Kamal::Cli::App < Kamal::Cli::Base say "Start container with version #{version} (or reboot if already running)...", :magenta # Assets are prepared in a separate step to ensure they are on all hosts before booting - on(KAMAL.hosts) do + on(KAMAL.app_hosts) do Kamal::Cli::App::ErrorPages.new(host, self).run KAMAL.roles_on(host).each do |role| @@ -33,7 +33,7 @@ class Kamal::Cli::App < Kamal::Cli::Base end # Tag once the app booted on all hosts - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| execute *KAMAL.auditor.record("Tagging #{KAMAL.config.absolute_image} as the latest image"), verbosity: :debug execute *KAMAL.app.tag_latest_image end @@ -44,7 +44,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "start", "Start existing app container on servers" def start with_lock do - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -67,7 +67,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "stop", "Stop app container on servers" def stop with_lock do - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -91,7 +91,7 @@ class Kamal::Cli::App < Kamal::Cli::Base # FIXME: Drop in favor of just containers? desc "details", "Show details about app containers" def details - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -135,7 +135,7 @@ class Kamal::Cli::App < Kamal::Cli::Base using_version(options[:version] || current_running_version) do |version| say "Launching command with version #{version} from existing container...", :magenta - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -149,7 +149,7 @@ class Kamal::Cli::App < Kamal::Cli::Base say "Get most recent version available as an image...", :magenta unless options[:version] using_version(version_or_latest) do |version| say "Launching command with version #{version} from new container...", :magenta - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -163,7 +163,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "containers", "Show app containers on servers" def containers - on(KAMAL.hosts) { |host| puts_by_host host, capture_with_info(*KAMAL.app.list_containers) } + on(KAMAL.app_hosts) { |host| puts_by_host host, capture_with_info(*KAMAL.app.list_containers) } end desc "stale_containers", "Detect app stale containers" @@ -172,7 +172,7 @@ class Kamal::Cli::App < Kamal::Cli::Base stop = options[:stop] with_lock_if_stopping do - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -195,7 +195,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "images", "Show app images on servers" def images - on(KAMAL.hosts) { |host| puts_by_host host, capture_with_info(*KAMAL.app.list_images) } + on(KAMAL.app_hosts) { |host| puts_by_host host, capture_with_info(*KAMAL.app.list_images) } end desc "logs", "Show log lines from app on servers (use --help to show options)" @@ -231,7 +231,7 @@ class Kamal::Cli::App < Kamal::Cli::Base else lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -288,7 +288,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "remove_container [VERSION]", "Remove app container with given version from servers", hide: true def remove_container(version) with_lock do - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -302,7 +302,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "remove_containers", "Remove all app containers from servers", hide: true def remove_containers with_lock do - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -316,7 +316,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "remove_images", "Remove all app images from servers", hide: true def remove_images with_lock do - on(KAMAL.hosts) do + on(KAMAL.app_hosts) do execute *KAMAL.auditor.record("Removed all app images"), verbosity: :debug execute *KAMAL.app.remove_images end @@ -326,7 +326,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "remove_app_directories", "Remove the app directories from servers", hide: true def remove_app_directories with_lock do - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| @@ -342,7 +342,7 @@ class Kamal::Cli::App < Kamal::Cli::Base desc "version", "Show app version currently running on servers" def version - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| role = KAMAL.roles_on(host).first puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).current_running_version).strip end @@ -385,6 +385,6 @@ class Kamal::Cli::App < Kamal::Cli::Base end def host_boot_groups - KAMAL.config.boot.limit ? KAMAL.hosts.each_slice(KAMAL.config.boot.limit).to_a : [ KAMAL.hosts ] + KAMAL.config.boot.limit ? KAMAL.app_hosts.each_slice(KAMAL.config.boot.limit).to_a : [ KAMAL.app_hosts ] end end diff --git a/lib/kamal/cli/build.rb b/lib/kamal/cli/build.rb index 310c2689..b9b6a5d5 100644 --- a/lib/kamal/cli/build.rb +++ b/lib/kamal/cli/build.rb @@ -70,9 +70,9 @@ class Kamal::Cli::Build < Kamal::Cli::Base say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta pull_on_hosts(first_hosts) say "Pulling image on remaining hosts...", :magenta - pull_on_hosts(KAMAL.hosts - first_hosts) + pull_on_hosts(KAMAL.app_hosts - first_hosts) else - pull_on_hosts(KAMAL.hosts) + pull_on_hosts(KAMAL.app_hosts) end end @@ -163,9 +163,9 @@ class Kamal::Cli::Build < Kamal::Cli::Base end def mirror_hosts - if KAMAL.hosts.many? + if KAMAL.app_hosts.many? mirror_hosts = Concurrent::Hash.new - on(KAMAL.hosts) do |host| + on(KAMAL.app_hosts) do |host| first_mirror = capture_with_info(*KAMAL.builder.first_mirror).strip.presence mirror_hosts[first_mirror] ||= host.to_s if first_mirror rescue SSHKit::Command::Failed => e @@ -193,7 +193,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base end def login_to_registry_remotely - on(KAMAL.hosts) do + on(KAMAL.app_hosts) do execute *KAMAL.registry.login end end diff --git a/lib/kamal/cli/main.rb b/lib/kamal/cli/main.rb index cd28ab35..4af6d878 100644 --- a/lib/kamal/cli/main.rb +++ b/lib/kamal/cli/main.rb @@ -194,10 +194,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base 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.hosts.each do |host| KAMAL.with_specific_hosts(host) do say "Upgrading #{host}...", :magenta - if KAMAL.hosts.include?(host) + if KAMAL.app_hosts.include?(host) invoke "kamal:cli:proxy:upgrade", [], options.merge(confirmed: true, rolling: false) reset_invocation(Kamal::Cli::Proxy) end @@ -253,7 +253,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base private def container_available?(version) begin - on(KAMAL.hosts) do + on(KAMAL.app_hosts) do KAMAL.roles_on(host).each do |role| container_id = capture_with_info(*KAMAL.app(role: role, host: host).container_id_for_version(version)) raise "Container not found" unless container_id.present? diff --git a/lib/kamal/cli/server.rb b/lib/kamal/cli/server.rb index 452ab089..db464e7b 100644 --- a/lib/kamal/cli/server.rb +++ b/lib/kamal/cli/server.rb @@ -3,7 +3,7 @@ class Kamal::Cli::Server < Kamal::Cli::Base option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)" def exec(*cmd) cmd = Kamal::Utils.join_commands(cmd) - hosts = KAMAL.hosts | KAMAL.accessory_hosts + hosts = KAMAL.hosts case when options[:interactive] @@ -27,7 +27,7 @@ class Kamal::Cli::Server < Kamal::Cli::Base with_lock do missing = [] - on(KAMAL.hosts | KAMAL.accessory_hosts) do |host| + on(KAMAL.hosts) do |host| unless execute(*KAMAL.docker.installed?, raise_on_non_zero_exit: false) if execute(*KAMAL.docker.superuser?, raise_on_non_zero_exit: false) info "Missing Docker on #{host}. Installing…" diff --git a/lib/kamal/commander.rb b/lib/kamal/commander.rb index b0e8f0ba..8a4356ed 100644 --- a/lib/kamal/commander.rb +++ b/lib/kamal/commander.rb @@ -5,7 +5,7 @@ require "active_support/core_ext/object/blank" class Kamal::Commander attr_accessor :verbosity, :holding_lock, :connected attr_reader :specific_roles, :specific_hosts - delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :proxy_hosts, :accessory_hosts, to: :specifics + delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :app_hosts, :proxy_hosts, :accessory_hosts, to: :specifics def initialize reset diff --git a/lib/kamal/commander/specifics.rb b/lib/kamal/commander/specifics.rb index 238cc012..e609baba 100644 --- a/lib/kamal/commander/specifics.rb +++ b/lib/kamal/commander/specifics.rb @@ -18,6 +18,10 @@ class Kamal::Commander::Specifics roles.select { |role| role.hosts.include?(host.to_s) } end + def app_hosts + config.app_hosts & specified_hosts + end + def proxy_hosts config.proxy_hosts & specified_hosts end diff --git a/lib/kamal/configuration.rb b/lib/kamal/configuration.rb index b291dfde..5f0abde8 100644 --- a/lib/kamal/configuration.rb +++ b/lib/kamal/configuration.rb @@ -125,6 +125,10 @@ class Kamal::Configuration (roles + accessories).flat_map(&:hosts).uniq end + def app_hosts + roles.flat_map(&:hosts).uniq + end + def primary_host primary_role&.primary_host end diff --git a/test/integration/docker/deployer/app/config/deploy.yml b/test/integration/docker/deployer/app/config/deploy.yml index 242d893a..c0a576a4 100644 --- a/test/integration/docker/deployer/app/config/deploy.yml +++ b/test/integration/docker/deployer/app/config/deploy.yml @@ -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 diff --git a/test/integration/main_test.rb b/test/integration/main_test.rb index 04040c38..0a918a78 100644 --- a/test/integration/main_test.rb +++ b/test/integration/main_test.rb @@ -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