diff --git a/lib/kamal/cli/accessory.rb b/lib/kamal/cli/accessory.rb index bc84fe52..e73c6f39 100644 --- a/lib/kamal/cli/accessory.rb +++ b/lib/kamal/cli/accessory.rb @@ -207,12 +207,12 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base end end - desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true - def remove_service_directory(name) + desc "remove_app_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true + def remove_app_directory(name) with_lock do with_accessory(name) do |accessory, hosts| on(hosts) do - execute *accessory.remove_service_directory + execute *accessory.remove_app_directory end end end @@ -248,7 +248,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base stop(name) remove_container(name) remove_image(name) - remove_service_directory(name) + remove_app_directory(name) end def prepare(name) diff --git a/lib/kamal/cli/app.rb b/lib/kamal/cli/app.rb index 21a5ffdd..7359fdde 100644 --- a/lib/kamal/cli/app.rb +++ b/lib/kamal/cli/app.rb @@ -231,7 +231,7 @@ class Kamal::Cli::App < Kamal::Cli::Base stop remove_containers remove_images - remove_service_directory + remove_app_directory end end @@ -273,15 +273,15 @@ class Kamal::Cli::App < Kamal::Cli::Base end end - desc "remove_service_directory", "Remove the service directory from servers", hide: true - def remove_service_directory + desc "remove_app_directory", "Remove the service directory from servers", hide: true + def remove_app_directory with_lock do on(KAMAL.hosts) do |host| roles = KAMAL.roles_on(host) roles.each do |role| - execute *KAMAL.auditor.record("Removed #{KAMAL.config.service_directory} on all servers", role: role), verbosity: :debug - execute *KAMAL.server.remove_service_directory + execute *KAMAL.auditor.record("Removed #{KAMAL.config.app_directory} on all servers", role: role), verbosity: :debug + execute *KAMAL.server.remove_app_directory end end end diff --git a/lib/kamal/cli/base.rb b/lib/kamal/cli/base.rb index 37a9e046..0164765d 100644 --- a/lib/kamal/cli/base.rb +++ b/lib/kamal/cli/base.rb @@ -176,7 +176,7 @@ module Kamal::Cli def ensure_service_and_locks_directory on(KAMAL.hosts) do - execute(*KAMAL.server.ensure_service_directory) + execute(*KAMAL.server.ensure_app_directory) end on(KAMAL.primary_host) do diff --git a/lib/kamal/cli/proxy.rb b/lib/kamal/cli/proxy.rb index 94d219aa..4b02800f 100644 --- a/lib/kamal/cli/proxy.rb +++ b/lib/kamal/cli/proxy.rb @@ -150,11 +150,15 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base end desc "remove", "Remove proxy container and image from servers" + option :force, type: :boolean, default: false, desc: "Force removing proxy when apps are still installed" def remove with_lock do - stop - remove_container - remove_image + if removal_allowed?(options[:force]) + stop + remove_container + remove_image + remove_host_directory + end end end @@ -178,8 +182,37 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base end end + desc "remove_host_directory", "Remove proxy directory from servers", hide: true + def remove_host_directory + with_lock do + on(KAMAL.proxy_hosts) do + execute *KAMAL.auditor.record("Removed #{KAMAL.config.proxy_directory}"), verbosity: :debug + execute *KAMAL.proxy.remove_host_directory + end + end + end + private def reset_invocation(cli_class) instance_variable_get("@_invocations")[cli_class].pop end + + def removal_allowed?(force) + on(KAMAL.proxy_hosts) do |host| + app_count = capture_with_info(*KAMAL.server.app_directory_count).chomp.to_i + raise "The are other applications installed on #{host}" if app_count > 0 + end + + true + rescue SSHKit::Runner::ExecuteError => e + raise unless e.message.include?("The are other applications installed on") + + if force + say "Forcing, so removing the proxy, even though other apps are installed", :magenta + else + say "Not removing the proxy, as other apps are installed, ignore this check with kamal proxy remove --force", :magenta + end + + force + end end diff --git a/lib/kamal/commands/accessory.rb b/lib/kamal/commands/accessory.rb index 787f7d43..22220d3f 100644 --- a/lib/kamal/commands/accessory.rb +++ b/lib/kamal/commands/accessory.rb @@ -90,7 +90,7 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base end end - def remove_service_directory + def remove_app_directory [ :rm, "-rf", service_name ] end diff --git a/lib/kamal/commands/proxy.rb b/lib/kamal/commands/proxy.rb index cf01fa19..f5ea8cf4 100644 --- a/lib/kamal/commands/proxy.rb +++ b/lib/kamal/commands/proxy.rb @@ -67,6 +67,10 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy" end + def remove_host_directory + remove_directory config.proxy_directory + end + def cleanup_traefik chain \ docker(:container, :stop, "traefik"), diff --git a/lib/kamal/commands/server.rb b/lib/kamal/commands/server.rb index a619a82d..e8bf97e3 100644 --- a/lib/kamal/commands/server.rb +++ b/lib/kamal/commands/server.rb @@ -1,9 +1,15 @@ class Kamal::Commands::Server < Kamal::Commands::Base - def ensure_service_directory - make_directory config.service_directory + def ensure_app_directory + make_directory config.app_directory end - def remove_service_directory - remove_directory config.service_directory + def remove_app_directory + remove_directory config.app_directory + end + + def app_directory_count + pipe \ + [ :ls, config.apps_directory ], + [ :wc, "-l" ] end end diff --git a/lib/kamal/configuration.rb b/lib/kamal/configuration.rb index 264b83e9..1d6a445e 100644 --- a/lib/kamal/configuration.rb +++ b/lib/kamal/configuration.rb @@ -194,16 +194,24 @@ class Kamal::Configuration ".kamal" end - def service_directory - File.join run_directory, "apps", [ service, destination ].compact.join("-") + def apps_directory + File.join run_directory, "apps" + end + + def app_directory + File.join apps_directory, [ service, destination ].compact.join("-") + end + + def proxy_directory + File.join run_directory, "proxy" end def env_directory - File.join service_directory, "env" + File.join app_directory, "env" end def assets_directory - File.join service_directory, "assets" + File.join app_directory, "assets" end diff --git a/lib/kamal/configuration/proxy.rb b/lib/kamal/configuration/proxy.rb index 2d2efdfb..b7bd7ba9 100644 --- a/lib/kamal/configuration/proxy.rb +++ b/lib/kamal/configuration/proxy.rb @@ -61,7 +61,7 @@ class Kamal::Configuration::Proxy def config_volume Kamal::Configuration::Volume.new \ - host_path: File.join(config.run_directory, "proxy", "config"), + host_path: File.join(config.proxy_directory, "config"), container_path: "/root/.config/kamal-proxy" end diff --git a/test/cli/accessory_test.rb b/test/cli/accessory_test.rb index 5bb8762a..2dbff62d 100644 --- a/test/cli/accessory_test.rb +++ b/test/cli/accessory_test.rb @@ -166,7 +166,7 @@ class CliAccessoryTest < CliTestCase Kamal::Cli::Accessory.any_instance.expects(:stop).with("mysql") Kamal::Cli::Accessory.any_instance.expects(:remove_container).with("mysql") Kamal::Cli::Accessory.any_instance.expects(:remove_image).with("mysql") - Kamal::Cli::Accessory.any_instance.expects(:remove_service_directory).with("mysql") + Kamal::Cli::Accessory.any_instance.expects(:remove_app_directory).with("mysql") run_command("remove", "mysql", "-y") end @@ -175,11 +175,11 @@ class CliAccessoryTest < CliTestCase Kamal::Cli::Accessory.any_instance.expects(:stop).with("mysql") Kamal::Cli::Accessory.any_instance.expects(:remove_container).with("mysql") Kamal::Cli::Accessory.any_instance.expects(:remove_image).with("mysql") - Kamal::Cli::Accessory.any_instance.expects(:remove_service_directory).with("mysql") + Kamal::Cli::Accessory.any_instance.expects(:remove_app_directory).with("mysql") Kamal::Cli::Accessory.any_instance.expects(:stop).with("redis") Kamal::Cli::Accessory.any_instance.expects(:remove_container).with("redis") Kamal::Cli::Accessory.any_instance.expects(:remove_image).with("redis") - Kamal::Cli::Accessory.any_instance.expects(:remove_service_directory).with("redis") + Kamal::Cli::Accessory.any_instance.expects(:remove_app_directory).with("redis") run_command("remove", "all", "-y") end @@ -192,8 +192,8 @@ class CliAccessoryTest < CliTestCase assert_match "docker image rm --force mysql", run_command("remove_image", "mysql") end - test "remove_service_directory" do - assert_match "rm -rf app-mysql", run_command("remove_service_directory", "mysql") + test "remove_app_directory" do + assert_match "rm -rf app-mysql", run_command("remove_app_directory", "mysql") end test "hosts param respected" do diff --git a/test/cli/proxy_test.rb b/test/cli/proxy_test.rb index 1d98395f..0589e525 100644 --- a/test/cli/proxy_test.rb +++ b/test/cli/proxy_test.rb @@ -98,11 +98,36 @@ class CliProxyTest < CliTestCase end test "remove" do - Kamal::Cli::Proxy.any_instance.expects(:stop) - Kamal::Cli::Proxy.any_instance.expects(:remove_container) - Kamal::Cli::Proxy.any_instance.expects(:remove_image) + run_command("remove").tap do |output| + assert_match "/usr/bin/env ls .kamal/apps | wc -l", output + assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", output + assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output + assert_match "/usr/bin/env rm -r .kamal/proxy", output + end + end - run_command("remove") + test "remove with other apps" do + Thread.report_on_exception = false + + SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:ls, ".kamal/apps", "|", :wc, "-l").returns("1\n").twice + + run_command("remove").tap do |output| + assert_match "Not removing the proxy, as other apps are installed, ignore this check with kamal proxy remove --force", output + end + ensure + Thread.report_on_exception = true + end + + test "force remove with other apps" do + Thread.report_on_exception = false + + SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:ls, ".kamal/apps", "|", :wc, "-l").returns("1\n").twice + + run_command("remove").tap do |output| + assert_match "Not removing the proxy, as other apps are installed, ignore this check with kamal proxy remove --force", output + end + ensure + Thread.report_on_exception = true end test "remove_container" do @@ -117,6 +142,12 @@ class CliProxyTest < CliTestCase end end + test "remove_host_directory" do + run_command("remove_host_directory").tap do |output| + assert_match "/usr/bin/env rm -r .kamal/proxy", output + end + end + private def run_command(*command, fixture: :with_proxy) stdouted { Kamal::Cli::Proxy.start([ *command, "-c", "test/fixtures/deploy_#{fixture}.yml" ]) } diff --git a/test/commands/server_test.rb b/test/commands/server_test.rb index 46cf4309..5db2ac59 100644 --- a/test/commands/server_test.rb +++ b/test/commands/server_test.rb @@ -9,7 +9,7 @@ class CommandsServerTest < ActiveSupport::TestCase end test "ensure service directory" do - assert_equal "mkdir -p .kamal/apps/app", new_command.ensure_service_directory.join(" ") + assert_equal "mkdir -p .kamal/apps/app", new_command.ensure_app_directory.join(" ") end private diff --git a/test/integration/app_test.rb b/test/integration/app_test.rb index 121a96a5..40a896b1 100644 --- a/test/integration/app_test.rb +++ b/test/integration/app_test.rb @@ -49,5 +49,6 @@ class AppTest < IntegrationTest kamal :app, :remove assert_app_is_down + assert_app_directory_removed end end diff --git a/test/integration/integration_test.rb b/test/integration/integration_test.rb index a8e149c1..5c675da6 100644 --- a/test/integration/integration_test.rb +++ b/test/integration/integration_test.rb @@ -148,4 +148,16 @@ class IntegrationTest < ActiveSupport::TestCase def container_running?(host:, name:) docker_compose("exec #{host} docker ps --filter=name=#{name} | tail -n+2", capture: true).strip.present? end + + def assert_app_directory_removed + assert_directory_removed("./kamal/apps/#{@app}") + end + + def assert_proxy_directory_removed + assert_directory_removed("./kamal/proxy") + end + + def assert_directory_removed(directory) + assert docker_compose("exec vm1 ls #{directory} | wc -l", capture: true).strip == "0" + end end diff --git a/test/integration/main_test.rb b/test/integration/main_test.rb index fbcd0927..cefe2100 100644 --- a/test/integration/main_test.rb +++ b/test/integration/main_test.rb @@ -97,6 +97,8 @@ class MainTest < IntegrationTest kamal :remove, "-y" assert_no_images_or_containers + assert_app_directory_removed + assert_proxy_directory_removed end private diff --git a/test/integration/proxy_test.rb b/test/integration/proxy_test.rb index 752ec41b..d796eb6d 100644 --- a/test/integration/proxy_test.rb +++ b/test/integration/proxy_test.rb @@ -48,6 +48,7 @@ class ProxyTest < IntegrationTest kamal :proxy, :remove assert_proxy_not_running + assert_proxy_directory_removed kamal :env, :delete end