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:
@@ -7,7 +7,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
say "Start container with version #{version} (or reboot if already running)...", :magenta
|
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
|
# 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::Cli::App::ErrorPages.new(host, self).run
|
||||||
|
|
||||||
KAMAL.roles_on(host).each do |role|
|
KAMAL.roles_on(host).each do |role|
|
||||||
@@ -33,7 +33,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Tag once the app booted on all hosts
|
# 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.auditor.record("Tagging #{KAMAL.config.absolute_image} as the latest image"), verbosity: :debug
|
||||||
execute *KAMAL.app.tag_latest_image
|
execute *KAMAL.app.tag_latest_image
|
||||||
end
|
end
|
||||||
@@ -44,7 +44,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
desc "start", "Start existing app container on servers"
|
desc "start", "Start existing app container on servers"
|
||||||
def start
|
def start
|
||||||
with_lock do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
@@ -67,7 +67,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
desc "stop", "Stop app container on servers"
|
desc "stop", "Stop app container on servers"
|
||||||
def stop
|
def stop
|
||||||
with_lock do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
@@ -91,7 +91,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
# FIXME: Drop in favor of just containers?
|
# FIXME: Drop in favor of just containers?
|
||||||
desc "details", "Show details about app containers"
|
desc "details", "Show details about app containers"
|
||||||
def details
|
def details
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
@@ -135,7 +135,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
using_version(options[:version] || current_running_version) do |version|
|
using_version(options[:version] || current_running_version) do |version|
|
||||||
say "Launching command with version #{version} from existing container...", :magenta
|
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 = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
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]
|
say "Get most recent version available as an image...", :magenta unless options[:version]
|
||||||
using_version(version_or_latest) do |version|
|
using_version(version_or_latest) do |version|
|
||||||
say "Launching command with version #{version} from new container...", :magenta
|
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 = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
@@ -163,7 +163,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "containers", "Show app containers on servers"
|
desc "containers", "Show app containers on servers"
|
||||||
def containers
|
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
|
end
|
||||||
|
|
||||||
desc "stale_containers", "Detect app stale containers"
|
desc "stale_containers", "Detect app stale containers"
|
||||||
@@ -172,7 +172,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
stop = options[:stop]
|
stop = options[:stop]
|
||||||
|
|
||||||
with_lock_if_stopping do
|
with_lock_if_stopping do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
@@ -195,7 +195,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "images", "Show app images on servers"
|
desc "images", "Show app images on servers"
|
||||||
def images
|
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
|
end
|
||||||
|
|
||||||
desc "logs", "Show log lines from app on servers (use --help to show options)"
|
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
|
else
|
||||||
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
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 = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
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
|
desc "remove_container [VERSION]", "Remove app container with given version from servers", hide: true
|
||||||
def remove_container(version)
|
def remove_container(version)
|
||||||
with_lock do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
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
|
desc "remove_containers", "Remove all app containers from servers", hide: true
|
||||||
def remove_containers
|
def remove_containers
|
||||||
with_lock do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
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
|
desc "remove_images", "Remove all app images from servers", hide: true
|
||||||
def remove_images
|
def remove_images
|
||||||
with_lock do
|
with_lock do
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.app_hosts) do
|
||||||
execute *KAMAL.auditor.record("Removed all app images"), verbosity: :debug
|
execute *KAMAL.auditor.record("Removed all app images"), verbosity: :debug
|
||||||
execute *KAMAL.app.remove_images
|
execute *KAMAL.app.remove_images
|
||||||
end
|
end
|
||||||
@@ -326,7 +326,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
desc "remove_app_directories", "Remove the app directories from servers", hide: true
|
desc "remove_app_directories", "Remove the app directories from servers", hide: true
|
||||||
def remove_app_directories
|
def remove_app_directories
|
||||||
with_lock do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
@@ -342,7 +342,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "version", "Show app version currently running on servers"
|
desc "version", "Show app version currently running on servers"
|
||||||
def version
|
def version
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.app_hosts) do |host|
|
||||||
role = KAMAL.roles_on(host).first
|
role = KAMAL.roles_on(host).first
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).current_running_version).strip
|
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).current_running_version).strip
|
||||||
end
|
end
|
||||||
@@ -385,6 +385,6 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def host_boot_groups
|
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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta
|
||||||
pull_on_hosts(first_hosts)
|
pull_on_hosts(first_hosts)
|
||||||
say "Pulling image on remaining hosts...", :magenta
|
say "Pulling image on remaining hosts...", :magenta
|
||||||
pull_on_hosts(KAMAL.hosts - first_hosts)
|
pull_on_hosts(KAMAL.app_hosts - first_hosts)
|
||||||
else
|
else
|
||||||
pull_on_hosts(KAMAL.hosts)
|
pull_on_hosts(KAMAL.app_hosts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -163,9 +163,9 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def mirror_hosts
|
def mirror_hosts
|
||||||
if KAMAL.hosts.many?
|
if KAMAL.app_hosts.many?
|
||||||
mirror_hosts = Concurrent::Hash.new
|
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
|
first_mirror = capture_with_info(*KAMAL.builder.first_mirror).strip.presence
|
||||||
mirror_hosts[first_mirror] ||= host.to_s if first_mirror
|
mirror_hosts[first_mirror] ||= host.to_s if first_mirror
|
||||||
rescue SSHKit::Command::Failed => e
|
rescue SSHKit::Command::Failed => e
|
||||||
@@ -193,7 +193,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def login_to_registry_remotely
|
def login_to_registry_remotely
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.app_hosts) do
|
||||||
execute *KAMAL.registry.login
|
execute *KAMAL.registry.login
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -194,10 +194,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
|
confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
|
||||||
with_lock do
|
with_lock do
|
||||||
if options[:rolling]
|
if options[:rolling]
|
||||||
(KAMAL.hosts | KAMAL.accessory_hosts).each do |host|
|
KAMAL.hosts.each do |host|
|
||||||
KAMAL.with_specific_hosts(host) do
|
KAMAL.with_specific_hosts(host) do
|
||||||
say "Upgrading #{host}...", :magenta
|
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)
|
invoke "kamal:cli:proxy:upgrade", [], options.merge(confirmed: true, rolling: false)
|
||||||
reset_invocation(Kamal::Cli::Proxy)
|
reset_invocation(Kamal::Cli::Proxy)
|
||||||
end
|
end
|
||||||
@@ -253,7 +253,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
private
|
private
|
||||||
def container_available?(version)
|
def container_available?(version)
|
||||||
begin
|
begin
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.app_hosts) do
|
||||||
KAMAL.roles_on(host).each do |role|
|
KAMAL.roles_on(host).each do |role|
|
||||||
container_id = capture_with_info(*KAMAL.app(role: role, host: host).container_id_for_version(version))
|
container_id = capture_with_info(*KAMAL.app(role: role, host: host).container_id_for_version(version))
|
||||||
raise "Container not found" unless container_id.present?
|
raise "Container not found" unless container_id.present?
|
||||||
|
|||||||
@@ -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)"
|
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
||||||
def exec(*cmd)
|
def exec(*cmd)
|
||||||
cmd = Kamal::Utils.join_commands(cmd)
|
cmd = Kamal::Utils.join_commands(cmd)
|
||||||
hosts = KAMAL.hosts | KAMAL.accessory_hosts
|
hosts = KAMAL.hosts
|
||||||
|
|
||||||
case
|
case
|
||||||
when options[:interactive]
|
when options[:interactive]
|
||||||
@@ -27,7 +27,7 @@ class Kamal::Cli::Server < Kamal::Cli::Base
|
|||||||
with_lock do
|
with_lock do
|
||||||
missing = []
|
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)
|
unless execute(*KAMAL.docker.installed?, raise_on_non_zero_exit: false)
|
||||||
if execute(*KAMAL.docker.superuser?, raise_on_non_zero_exit: false)
|
if execute(*KAMAL.docker.superuser?, raise_on_non_zero_exit: false)
|
||||||
info "Missing Docker on #{host}. Installing…"
|
info "Missing Docker on #{host}. Installing…"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ require "active_support/core_ext/object/blank"
|
|||||||
class Kamal::Commander
|
class Kamal::Commander
|
||||||
attr_accessor :verbosity, :holding_lock, :connected
|
attr_accessor :verbosity, :holding_lock, :connected
|
||||||
attr_reader :specific_roles, :specific_hosts
|
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
|
def initialize
|
||||||
reset
|
reset
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ class Kamal::Commander::Specifics
|
|||||||
roles.select { |role| role.hosts.include?(host.to_s) }
|
roles.select { |role| role.hosts.include?(host.to_s) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def app_hosts
|
||||||
|
config.app_hosts & specified_hosts
|
||||||
|
end
|
||||||
|
|
||||||
def proxy_hosts
|
def proxy_hosts
|
||||||
config.proxy_hosts & specified_hosts
|
config.proxy_hosts & specified_hosts
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ class Kamal::Configuration
|
|||||||
(roles + accessories).flat_map(&:hosts).uniq
|
(roles + accessories).flat_map(&:hosts).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def app_hosts
|
||||||
|
roles.flat_map(&:hosts).uniq
|
||||||
|
end
|
||||||
|
|
||||||
def primary_host
|
def primary_host
|
||||||
primary_role&.primary_host
|
primary_role&.primary_host
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -41,3 +41,8 @@ accessories:
|
|||||||
cmd: sh -c 'echo "Starting busybox..."; trap exit term; while true; do sleep 1; done'
|
cmd: sh -c 'echo "Starting busybox..."; trap exit term; while true; do sleep 1; done'
|
||||||
roles:
|
roles:
|
||||||
- web
|
- 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
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class MainTest < IntegrationTest
|
|||||||
version = latest_app_version
|
version = latest_app_version
|
||||||
|
|
||||||
assert_equal [ "web" ], config[:roles]
|
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 "vm1", config[:primary_host]
|
||||||
assert_equal version, config[:version]
|
assert_equal version, config[:version]
|
||||||
assert_equal "registry:4443/app", config[:repository]
|
assert_equal "registry:4443/app", config[:repository]
|
||||||
@@ -88,8 +88,6 @@ class MainTest < IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "setup and remove" do
|
test "setup and remove" do
|
||||||
@app = "app_with_roles"
|
|
||||||
|
|
||||||
kamal :proxy, :boot_config, "set",
|
kamal :proxy, :boot_config, "set",
|
||||||
"--publish=false",
|
"--publish=false",
|
||||||
"--docker-options=label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http",
|
"--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
|
assert_equal "200", Net::HTTP.get_response(URI.parse("http://#{app_host}:12345/versions/.hidden")).code
|
||||||
end
|
end
|
||||||
|
|
||||||
def vm1_image_ids
|
def image_ids(vm:)
|
||||||
docker_compose("exec vm1 docker image ls -q", capture: true).strip.split("\n")
|
docker_compose("exec #{vm} docker image ls -q", capture: true).strip.split("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
def vm1_container_ids
|
def container_ids(vm:)
|
||||||
docker_compose("exec vm1 docker ps -a -q", capture: true).strip.split("\n")
|
docker_compose("exec #{vm} docker ps -a -q", capture: true).strip.split("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_no_images_or_containers
|
def assert_no_images_or_containers
|
||||||
assert vm1_image_ids.empty?
|
[ :vm1, :vm2, :vm3 ].each do |vm|
|
||||||
assert vm1_container_ids.empty?
|
assert image_ids(vm: vm).empty?
|
||||||
|
assert container_ids(vm: vm).empty?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_images_and_containers
|
def assert_images_and_containers
|
||||||
assert vm1_image_ids.any?
|
[ :vm1, :vm2, :vm3 ].each do |vm|
|
||||||
assert vm1_container_ids.any?
|
assert image_ids(vm: vm).any?
|
||||||
|
assert container_ids(vm: vm).any?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user