Split lock and connection setup
Allow run the pre-connect hook before the first SSH command is executed, but only run the locking in `with_lock` blocks.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
class Kamal::Cli::Accessory < Kamal::Cli::Base
|
class Kamal::Cli::Accessory < Kamal::Cli::Base
|
||||||
desc "boot [NAME]", "Boot new accessory service on host (use NAME=all to boot all accessories)"
|
desc "boot [NAME]", "Boot new accessory service on host (use NAME=all to boot all accessories)"
|
||||||
def boot(name, login: true)
|
def boot(name, login: true)
|
||||||
mutating do
|
with_lock do
|
||||||
if name == "all"
|
if name == "all"
|
||||||
KAMAL.accessory_names.each { |accessory_name| boot(accessory_name) }
|
KAMAL.accessory_names.each { |accessory_name| boot(accessory_name) }
|
||||||
else
|
else
|
||||||
@@ -21,7 +21,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "upload [NAME]", "Upload accessory files to host", hide: true
|
desc "upload [NAME]", "Upload accessory files to host", hide: true
|
||||||
def upload(name)
|
def upload(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
accessory.files.each do |(local, remote)|
|
accessory.files.each do |(local, remote)|
|
||||||
@@ -38,7 +38,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "directories [NAME]", "Create accessory directories on host", hide: true
|
desc "directories [NAME]", "Create accessory directories on host", hide: true
|
||||||
def directories(name)
|
def directories(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
accessory.directories.keys.each do |host_path|
|
accessory.directories.keys.each do |host_path|
|
||||||
@@ -51,7 +51,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container; use NAME=all to boot all accessories)"
|
desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container; use NAME=all to boot all accessories)"
|
||||||
def reboot(name)
|
def reboot(name)
|
||||||
mutating do
|
with_lock do
|
||||||
if name == "all"
|
if name == "all"
|
||||||
KAMAL.accessory_names.each { |accessory_name| reboot(accessory_name) }
|
KAMAL.accessory_names.each { |accessory_name| reboot(accessory_name) }
|
||||||
else
|
else
|
||||||
@@ -70,7 +70,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "start [NAME]", "Start existing accessory container on host"
|
desc "start [NAME]", "Start existing accessory container on host"
|
||||||
def start(name)
|
def start(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
execute *KAMAL.auditor.record("Started #{name} accessory"), verbosity: :debug
|
execute *KAMAL.auditor.record("Started #{name} accessory"), verbosity: :debug
|
||||||
@@ -82,7 +82,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "stop [NAME]", "Stop existing accessory container on host"
|
desc "stop [NAME]", "Stop existing accessory container on host"
|
||||||
def stop(name)
|
def stop(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
execute *KAMAL.auditor.record("Stopped #{name} accessory"), verbosity: :debug
|
execute *KAMAL.auditor.record("Stopped #{name} accessory"), verbosity: :debug
|
||||||
@@ -94,7 +94,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "restart [NAME]", "Restart existing accessory container on host"
|
desc "restart [NAME]", "Restart existing accessory container on host"
|
||||||
def restart(name)
|
def restart(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do
|
with_accessory(name) do
|
||||||
stop(name)
|
stop(name)
|
||||||
start(name)
|
start(name)
|
||||||
@@ -175,7 +175,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
def remove(name)
|
def remove(name)
|
||||||
confirming "This will remove all containers, images and data directories for #{name}. Are you sure?" do
|
confirming "This will remove all containers, images and data directories for #{name}. Are you sure?" do
|
||||||
mutating do
|
with_lock do
|
||||||
if name == "all"
|
if name == "all"
|
||||||
KAMAL.accessory_names.each { |accessory_name| remove_accessory(accessory_name) }
|
KAMAL.accessory_names.each { |accessory_name| remove_accessory(accessory_name) }
|
||||||
else
|
else
|
||||||
@@ -187,7 +187,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "remove_container [NAME]", "Remove accessory container from host", hide: true
|
desc "remove_container [NAME]", "Remove accessory container from host", hide: true
|
||||||
def remove_container(name)
|
def remove_container(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
execute *KAMAL.auditor.record("Remove #{name} accessory container"), verbosity: :debug
|
execute *KAMAL.auditor.record("Remove #{name} accessory container"), verbosity: :debug
|
||||||
@@ -199,7 +199,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "remove_image [NAME]", "Remove accessory image from host", hide: true
|
desc "remove_image [NAME]", "Remove accessory image from host", hide: true
|
||||||
def remove_image(name)
|
def remove_image(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
execute *KAMAL.auditor.record("Removed #{name} accessory image"), verbosity: :debug
|
execute *KAMAL.auditor.record("Removed #{name} accessory image"), verbosity: :debug
|
||||||
@@ -211,7 +211,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true
|
desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true
|
||||||
def remove_service_directory(name)
|
def remove_service_directory(name)
|
||||||
mutating do
|
with_lock do
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
execute *accessory.remove_service_directory
|
execute *accessory.remove_service_directory
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Kamal::Cli::App < Kamal::Cli::Base
|
class Kamal::Cli::App < Kamal::Cli::Base
|
||||||
desc "boot", "Boot app on servers (or reboot app if already running)"
|
desc "boot", "Boot app on servers (or reboot app if already running)"
|
||||||
def boot
|
def boot
|
||||||
mutating do
|
with_lock do
|
||||||
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 "Start container with version #{version} using a #{KAMAL.config.readiness_delay}s readiness delay (or reboot if already running)...", :magenta
|
say "Start container with version #{version} using a #{KAMAL.config.readiness_delay}s readiness delay (or reboot if already running)...", :magenta
|
||||||
@@ -33,7 +33,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
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
@@ -47,7 +47,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
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
def stale_containers
|
def stale_containers
|
||||||
stop = options[:stop]
|
stop = options[:stop]
|
||||||
|
|
||||||
mutating(mutates: stop) do
|
with_lock_if_stopping do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "remove", "Remove app containers and images from servers"
|
desc "remove", "Remove app containers and images from servers"
|
||||||
def remove
|
def remove
|
||||||
mutating do
|
with_lock do
|
||||||
stop
|
stop
|
||||||
remove_containers
|
remove_containers
|
||||||
remove_images
|
remove_images
|
||||||
@@ -213,7 +213,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)
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
@@ -227,7 +227,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
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
@@ -241,7 +241,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
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.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
|
||||||
@@ -284,4 +284,12 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
def version_or_latest
|
def version_or_latest
|
||||||
options[:version] || KAMAL.config.latest_tag
|
options[:version] || KAMAL.config.latest_tag
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_lock_if_stopping
|
||||||
|
if options[:stop]
|
||||||
|
with_lock { yield }
|
||||||
|
else
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -79,27 +79,27 @@ module Kamal::Cli
|
|||||||
puts " Finished all in #{sprintf("%.1f seconds", runtime)}"
|
puts " Finished all in #{sprintf("%.1f seconds", runtime)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def mutating(mutates: true)
|
def with_lock
|
||||||
return yield if KAMAL.holding_lock? || !mutates
|
if KAMAL.holding_lock?
|
||||||
|
|
||||||
run_hook "pre-connect"
|
|
||||||
|
|
||||||
ensure_run_and_locks_directory
|
|
||||||
|
|
||||||
acquire_lock
|
|
||||||
|
|
||||||
begin
|
|
||||||
yield
|
yield
|
||||||
rescue
|
else
|
||||||
begin
|
ensure_run_and_locks_directory
|
||||||
release_lock
|
|
||||||
rescue => e
|
|
||||||
say "Error releasing the deploy lock: #{e.message}", :red
|
|
||||||
end
|
|
||||||
raise
|
|
||||||
end
|
|
||||||
|
|
||||||
release_lock
|
acquire_lock
|
||||||
|
|
||||||
|
begin
|
||||||
|
yield
|
||||||
|
rescue
|
||||||
|
begin
|
||||||
|
release_lock
|
||||||
|
rescue => e
|
||||||
|
say "Error releasing the deploy lock: #{e.message}", :red
|
||||||
|
end
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
release_lock
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def confirming(question)
|
def confirming(question)
|
||||||
@@ -153,6 +153,15 @@ module Kamal::Cli
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def on(*args, &block)
|
||||||
|
if !KAMAL.connected?
|
||||||
|
run_hook "pre-connect"
|
||||||
|
KAMAL.connected = true
|
||||||
|
end
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
def command
|
def command
|
||||||
@kamal_command ||= begin
|
@kamal_command ||= begin
|
||||||
invocation_class, invocation_commands = *first_invocation
|
invocation_class, invocation_commands = *first_invocation
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require "tempfile"
|
|||||||
class Kamal::Cli::Env < Kamal::Cli::Base
|
class Kamal::Cli::Env < Kamal::Cli::Base
|
||||||
desc "push", "Push the env file to the remote hosts"
|
desc "push", "Push the env file to the remote hosts"
|
||||||
def push
|
def push
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.hosts) do
|
||||||
execute *KAMAL.auditor.record("Pushed env files"), verbosity: :debug
|
execute *KAMAL.auditor.record("Pushed env files"), verbosity: :debug
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class Kamal::Cli::Env < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "delete", "Delete the env file from the remote hosts"
|
desc "delete", "Delete the env file from the remote hosts"
|
||||||
def delete
|
def delete
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.hosts) do
|
||||||
execute *KAMAL.auditor.record("Deleted env files"), verbosity: :debug
|
execute *KAMAL.auditor.record("Deleted env files"), verbosity: :debug
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
||||||
def setup
|
def setup
|
||||||
print_runtime do
|
print_runtime do
|
||||||
mutating do
|
with_lock do
|
||||||
invoke_options = deploy_options
|
invoke_options = deploy_options
|
||||||
|
|
||||||
say "Ensure Docker is installed...", :magenta
|
say "Ensure Docker is installed...", :magenta
|
||||||
@@ -22,22 +22,22 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
||||||
def deploy
|
def deploy
|
||||||
runtime = print_runtime do
|
runtime = print_runtime do
|
||||||
mutating do
|
invoke_options = deploy_options
|
||||||
invoke_options = deploy_options
|
|
||||||
|
|
||||||
say "Log into image registry...", :magenta
|
say "Log into image registry...", :magenta
|
||||||
invoke "kamal:cli:registry:login", [], invoke_options
|
invoke "kamal:cli:registry:login", [], invoke_options
|
||||||
|
|
||||||
if options[:skip_push]
|
if options[:skip_push]
|
||||||
say "Pull app image...", :magenta
|
say "Pull app image...", :magenta
|
||||||
invoke "kamal:cli:build:pull", [], invoke_options
|
invoke "kamal:cli:build:pull", [], invoke_options
|
||||||
else
|
else
|
||||||
say "Build and push app image...", :magenta
|
say "Build and push app image...", :magenta
|
||||||
invoke "kamal:cli:build:deliver", [], invoke_options
|
invoke "kamal:cli:build:deliver", [], invoke_options
|
||||||
end
|
end
|
||||||
|
|
||||||
run_hook "pre-deploy"
|
run_hook "pre-deploy"
|
||||||
|
|
||||||
|
with_lock do
|
||||||
say "Ensure Traefik is running...", :magenta
|
say "Ensure Traefik is running...", :magenta
|
||||||
invoke "kamal:cli:traefik:boot", [], invoke_options
|
invoke "kamal:cli:traefik:boot", [], invoke_options
|
||||||
|
|
||||||
@@ -58,17 +58,17 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
||||||
def redeploy
|
def redeploy
|
||||||
runtime = print_runtime do
|
runtime = print_runtime do
|
||||||
mutating do
|
invoke_options = deploy_options
|
||||||
invoke_options = deploy_options
|
|
||||||
|
|
||||||
if options[:skip_push]
|
if options[:skip_push]
|
||||||
say "Pull app image...", :magenta
|
say "Pull app image...", :magenta
|
||||||
invoke "kamal:cli:build:pull", [], invoke_options
|
invoke "kamal:cli:build:pull", [], invoke_options
|
||||||
else
|
else
|
||||||
say "Build and push app image...", :magenta
|
say "Build and push app image...", :magenta
|
||||||
invoke "kamal:cli:build:deliver", [], invoke_options
|
invoke "kamal:cli:build:deliver", [], invoke_options
|
||||||
end
|
end
|
||||||
|
|
||||||
|
with_lock do
|
||||||
run_hook "pre-deploy"
|
run_hook "pre-deploy"
|
||||||
|
|
||||||
say "Detect stale containers...", :magenta
|
say "Detect stale containers...", :magenta
|
||||||
@@ -85,7 +85,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
def rollback(version)
|
def rollback(version)
|
||||||
rolled_back = false
|
rolled_back = false
|
||||||
runtime = print_runtime do
|
runtime = print_runtime do
|
||||||
mutating do
|
with_lock do
|
||||||
invoke_options = deploy_options
|
invoke_options = deploy_options
|
||||||
|
|
||||||
KAMAL.config.version = version
|
KAMAL.config.version = version
|
||||||
@@ -193,7 +193,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
def remove
|
def remove
|
||||||
confirming "This will remove all containers and images. Are you sure?" do
|
confirming "This will remove all containers and images. Are you sure?" do
|
||||||
mutating do
|
with_lock do
|
||||||
invoke "kamal:cli:traefik:remove", [], options.without(:confirmed)
|
invoke "kamal:cli:traefik:remove", [], options.without(:confirmed)
|
||||||
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
||||||
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Kamal::Cli::Prune < Kamal::Cli::Base
|
class Kamal::Cli::Prune < Kamal::Cli::Base
|
||||||
desc "all", "Prune unused images and stopped containers"
|
desc "all", "Prune unused images and stopped containers"
|
||||||
def all
|
def all
|
||||||
mutating do
|
with_lock do
|
||||||
containers
|
containers
|
||||||
images
|
images
|
||||||
end
|
end
|
||||||
@@ -9,7 +9,7 @@ class Kamal::Cli::Prune < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "images", "Prune unused images"
|
desc "images", "Prune unused images"
|
||||||
def images
|
def images
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.hosts) do
|
||||||
execute *KAMAL.auditor.record("Pruned images"), verbosity: :debug
|
execute *KAMAL.auditor.record("Pruned images"), verbosity: :debug
|
||||||
execute *KAMAL.prune.dangling_images
|
execute *KAMAL.prune.dangling_images
|
||||||
@@ -24,7 +24,7 @@ class Kamal::Cli::Prune < Kamal::Cli::Base
|
|||||||
retain = options.fetch(:retain, KAMAL.config.retain_containers)
|
retain = options.fetch(:retain, KAMAL.config.retain_containers)
|
||||||
raise "retain must be at least 1" if retain < 1
|
raise "retain must be at least 1" if retain < 1
|
||||||
|
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.hosts) do
|
||||||
execute *KAMAL.auditor.record("Pruned containers"), verbosity: :debug
|
execute *KAMAL.auditor.record("Pruned containers"), verbosity: :debug
|
||||||
execute *KAMAL.prune.app_containers(retain: retain)
|
execute *KAMAL.prune.app_containers(retain: retain)
|
||||||
|
|||||||
@@ -23,25 +23,27 @@ class Kamal::Cli::Server < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "bootstrap", "Set up Docker to run Kamal apps"
|
desc "bootstrap", "Set up Docker to run Kamal apps"
|
||||||
def bootstrap
|
def bootstrap
|
||||||
missing = []
|
with_lock do
|
||||||
|
missing = []
|
||||||
|
|
||||||
on(KAMAL.hosts | KAMAL.accessory_hosts) do |host|
|
on(KAMAL.hosts | KAMAL.accessory_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…"
|
||||||
execute *KAMAL.docker.install
|
execute *KAMAL.docker.install
|
||||||
else
|
else
|
||||||
missing << host
|
missing << host
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
execute(*KAMAL.server.ensure_run_directory)
|
||||||
end
|
end
|
||||||
|
|
||||||
execute(*KAMAL.server.ensure_run_directory)
|
if missing.any?
|
||||||
end
|
raise "Docker is not installed on #{missing.join(", ")} and can't be automatically installed without having root access and either `wget` or `curl`. Install Docker manually: https://docs.docker.com/engine/install/"
|
||||||
|
end
|
||||||
|
|
||||||
if missing.any?
|
run_hook "docker-setup"
|
||||||
raise "Docker is not installed on #{missing.join(", ")} and can't be automatically installed without having root access and either `wget` or `curl`. Install Docker manually: https://docs.docker.com/engine/install/"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
run_hook "docker-setup"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Kamal::Cli::Traefik < Kamal::Cli::Base
|
class Kamal::Cli::Traefik < Kamal::Cli::Base
|
||||||
desc "boot", "Boot Traefik on servers"
|
desc "boot", "Boot Traefik on servers"
|
||||||
def boot
|
def boot
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.traefik_hosts) do
|
on(KAMAL.traefik_hosts) do
|
||||||
execute *KAMAL.registry.login
|
execute *KAMAL.registry.login
|
||||||
execute *KAMAL.traefik.start_or_run
|
execute *KAMAL.traefik.start_or_run
|
||||||
@@ -14,7 +14,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
def reboot
|
def reboot
|
||||||
confirming "This will cause a brief outage on each host. Are you sure?" do
|
confirming "This will cause a brief outage on each host. Are you sure?" do
|
||||||
mutating do
|
with_lock do
|
||||||
host_groups = options[:rolling] ? KAMAL.traefik_hosts : [ KAMAL.traefik_hosts ]
|
host_groups = options[:rolling] ? KAMAL.traefik_hosts : [ KAMAL.traefik_hosts ]
|
||||||
host_groups.each do |hosts|
|
host_groups.each do |hosts|
|
||||||
host_list = Array(hosts).join(",")
|
host_list = Array(hosts).join(",")
|
||||||
@@ -34,7 +34,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "start", "Start existing Traefik container on servers"
|
desc "start", "Start existing Traefik container on servers"
|
||||||
def start
|
def start
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.traefik_hosts) do
|
on(KAMAL.traefik_hosts) do
|
||||||
execute *KAMAL.auditor.record("Started traefik"), verbosity: :debug
|
execute *KAMAL.auditor.record("Started traefik"), verbosity: :debug
|
||||||
execute *KAMAL.traefik.start
|
execute *KAMAL.traefik.start
|
||||||
@@ -44,7 +44,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "stop", "Stop existing Traefik container on servers"
|
desc "stop", "Stop existing Traefik container on servers"
|
||||||
def stop
|
def stop
|
||||||
mutating do
|
with_lock 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, raise_on_non_zero_exit: false
|
execute *KAMAL.traefik.stop, raise_on_non_zero_exit: false
|
||||||
@@ -54,7 +54,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "restart", "Restart existing Traefik container on servers"
|
desc "restart", "Restart existing Traefik container on servers"
|
||||||
def restart
|
def restart
|
||||||
mutating do
|
with_lock do
|
||||||
stop
|
stop
|
||||||
start
|
start
|
||||||
end
|
end
|
||||||
@@ -91,7 +91,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "remove", "Remove Traefik container and image from servers"
|
desc "remove", "Remove Traefik container and image from servers"
|
||||||
def remove
|
def remove
|
||||||
mutating do
|
with_lock do
|
||||||
stop
|
stop
|
||||||
remove_container
|
remove_container
|
||||||
remove_image
|
remove_image
|
||||||
@@ -100,7 +100,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "remove_container", "Remove Traefik container from servers", hide: true
|
desc "remove_container", "Remove Traefik container from servers", hide: true
|
||||||
def remove_container
|
def remove_container
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.traefik_hosts) do
|
on(KAMAL.traefik_hosts) do
|
||||||
execute *KAMAL.auditor.record("Removed traefik container"), verbosity: :debug
|
execute *KAMAL.auditor.record("Removed traefik container"), verbosity: :debug
|
||||||
execute *KAMAL.traefik.remove_container
|
execute *KAMAL.traefik.remove_container
|
||||||
@@ -110,7 +110,7 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "remove_image", "Remove Traefik image from servers", hide: true
|
desc "remove_image", "Remove Traefik image from servers", hide: true
|
||||||
def remove_image
|
def remove_image
|
||||||
mutating do
|
with_lock do
|
||||||
on(KAMAL.traefik_hosts) do
|
on(KAMAL.traefik_hosts) do
|
||||||
execute *KAMAL.auditor.record("Removed traefik image"), verbosity: :debug
|
execute *KAMAL.auditor.record("Removed traefik image"), verbosity: :debug
|
||||||
execute *KAMAL.traefik.remove_image
|
execute *KAMAL.traefik.remove_image
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ require "active_support/core_ext/enumerable"
|
|||||||
require "active_support/core_ext/module/delegation"
|
require "active_support/core_ext/module/delegation"
|
||||||
|
|
||||||
class Kamal::Commander
|
class Kamal::Commander
|
||||||
attr_accessor :verbosity, :holding_lock
|
attr_accessor :verbosity, :holding_lock, :connected
|
||||||
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :traefik_hosts, :accessory_hosts, to: :specifics
|
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :traefik_hosts, :accessory_hosts, to: :specifics
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
self.verbosity = :info
|
self.verbosity = :info
|
||||||
self.holding_lock = false
|
self.holding_lock = false
|
||||||
|
self.connected = false
|
||||||
@specifics = nil
|
@specifics = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -137,6 +138,10 @@ class Kamal::Commander
|
|||||||
self.holding_lock
|
self.holding_lock
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def connected?
|
||||||
|
self.connected
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
# Lazy setup of SSHKit
|
# Lazy setup of SSHKit
|
||||||
def configure_sshkit_with(config)
|
def configure_sshkit_with(config)
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ class CliMainTest < CliTestCase
|
|||||||
test "deploy when locked" do
|
test "deploy when locked" do
|
||||||
Thread.report_on_exception = false
|
Thread.report_on_exception = false
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||||
|
Dir.stubs(:chdir)
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||||
.with { |*args| args == [ :mkdir, "-p", ".kamal" ] }
|
.with { |*args| args == [ :mkdir, "-p", ".kamal" ] }
|
||||||
|
|
||||||
@@ -113,6 +116,9 @@ class CliMainTest < CliTestCase
|
|||||||
test "deploy error when locking" do
|
test "deploy error when locking" do
|
||||||
Thread.report_on_exception = false
|
Thread.report_on_exception = false
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||||
|
Dir.stubs(:chdir)
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||||
.with { |*args| args == [ :mkdir, "-p", ".kamal" ] }
|
.with { |*args| args == [ :mkdir, "-p", ".kamal" ] }
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,15 @@ class CliServerTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "bootstrap already installed" do
|
test "bootstrap already installed" do
|
||||||
|
stub_setup
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(true).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(true).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
||||||
|
|
||||||
assert_equal "", run_command("bootstrap")
|
assert_equal "Acquiring the deploy lock...\nReleasing the deploy lock...", run_command("bootstrap")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "bootstrap install as non-root user" do
|
test "bootstrap install as non-root user" do
|
||||||
|
stub_setup
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(false).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(false).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
||||||
@@ -33,11 +35,13 @@ class CliServerTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "bootstrap install as root user" do
|
test "bootstrap install as root user" do
|
||||||
|
stub_setup
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(true).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(true).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:sh, "-c", "'curl -fsSL https://get.docker.com || wget -O - https://get.docker.com || echo \"exit 1\"'", "|", :sh).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:sh, "-c", "'curl -fsSL https://get.docker.com || wget -O - https://get.docker.com || echo \"exit 1\"'", "|", :sh).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
||||||
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
|
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(".kamal/hooks/pre-connect", anything).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(".kamal/hooks/docker-setup", anything).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(".kamal/hooks/docker-setup", anything).at_least_once
|
||||||
|
|
||||||
run_command("bootstrap").tap do |output|
|
run_command("bootstrap").tap do |output|
|
||||||
|
|||||||
Reference in New Issue
Block a user