Add KAMAL.app_hosts

KAMAL.hosts includes accessory and apps hosts. Add KAMAL.app_hosts which
does not include accessory only hosts and use it for app specific
commands.

Fixes:
- https://github.com/basecamp/kamal/issues/1059
- https://github.com/basecamp/kamal/issues/1148
This commit is contained in:
Donal McBreen
2025-04-18 11:52:55 +01:00
parent 5c71f2ba5a
commit e4e39c31e3
9 changed files with 54 additions and 39 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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?

View File

@@ -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…"

View File

@@ -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

View File

@@ -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

View File

@@ -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