diff --git a/lib/mrsk/cli/accessory.rb b/lib/mrsk/cli/accessory.rb index 1343a5f2..6d80e115 100644 --- a/lib/mrsk/cli/accessory.rb +++ b/lib/mrsk/cli/accessory.rb @@ -1,7 +1,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "boot [NAME]", "Boot new accessory service on host (use NAME=all to boot all accessories)" def boot(name) - with_lock do + mutating do if name == "all" MRSK.accessory_names.each { |accessory_name| boot(accessory_name) } else @@ -21,7 +21,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "upload [NAME]", "Upload accessory files to host", hide: true def upload(name) - with_lock do + mutating do with_accessory(name) do |accessory| on(accessory.hosts) do accessory.files.each do |(local, remote)| @@ -38,7 +38,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "directories [NAME]", "Create accessory directories on host", hide: true def directories(name) - with_lock do + mutating do with_accessory(name) do |accessory| on(accessory.hosts) do accessory.directories.keys.each do |host_path| @@ -51,7 +51,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container)" def reboot(name) - with_lock do + mutating do with_accessory(name) do |accessory| stop(name) remove_container(name) @@ -62,7 +62,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "start [NAME]", "Start existing accessory container on host" def start(name) - with_lock do + mutating do with_accessory(name) do |accessory| on(accessory.hosts) do execute *MRSK.auditor.record("Started #{name} accessory"), verbosity: :debug @@ -74,7 +74,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "stop [NAME]", "Stop existing accessory container on host" def stop(name) - with_lock do + mutating do with_accessory(name) do |accessory| on(accessory.hosts) do execute *MRSK.auditor.record("Stopped #{name} accessory"), verbosity: :debug @@ -86,7 +86,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "restart [NAME]", "Restart existing accessory container on host" def restart(name) - with_lock do + mutating do with_accessory(name) do stop(name) start(name) @@ -165,7 +165,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "remove [NAME]", "Remove accessory container, image and data directory from host (use NAME=all to remove all accessories)" option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question" def remove(name) - with_lock do + mutating do if name == "all" MRSK.accessory_names.each { |accessory_name| remove(accessory_name) } else @@ -183,7 +183,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "remove_container [NAME]", "Remove accessory container from host", hide: true def remove_container(name) - with_lock do + mutating do with_accessory(name) do |accessory| on(accessory.hosts) do execute *MRSK.auditor.record("Remove #{name} accessory container"), verbosity: :debug @@ -195,7 +195,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "remove_image [NAME]", "Remove accessory image from host", hide: true def remove_image(name) - with_lock do + mutating do with_accessory(name) do |accessory| on(accessory.hosts) do execute *MRSK.auditor.record("Removed #{name} accessory image"), verbosity: :debug @@ -207,7 +207,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true def remove_service_directory(name) - with_lock do + mutating do with_accessory(name) do |accessory| on(accessory.hosts) do execute *accessory.remove_service_directory diff --git a/lib/mrsk/cli/app.rb b/lib/mrsk/cli/app.rb index cc4a4cf4..40119d98 100644 --- a/lib/mrsk/cli/app.rb +++ b/lib/mrsk/cli/app.rb @@ -1,7 +1,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "boot", "Boot app on servers (or reboot app if already running)" def boot - with_lock do + mutating do hold_lock_on_error do say "Get most recent version available as an image...", :magenta unless options[:version] using_version(version_or_latest) do |version| @@ -43,7 +43,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "start", "Start existing app container on servers" def start - with_lock do + mutating do on(MRSK.hosts) do |host| roles = MRSK.roles_on(host) @@ -57,7 +57,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "stop", "Stop app container on servers" def stop - with_lock do + mutating do on(MRSK.hosts) do |host| roles = MRSK.roles_on(host) @@ -135,7 +135,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "stale_containers", "Detect app stale containers" option :stop, aliases: "-s", type: :boolean, default: false, desc: "Stop the stale containers found" def stale_containers - with_lock do + mutating do stop = options[:stop] cli = self @@ -202,7 +202,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "remove", "Remove app containers and images from servers" def remove - with_lock do + mutating do stop remove_containers remove_images @@ -211,7 +211,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "remove_container [VERSION]", "Remove app container with given version from servers", hide: true def remove_container(version) - with_lock do + mutating do on(MRSK.hosts) do |host| roles = MRSK.roles_on(host) @@ -225,7 +225,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "remove_containers", "Remove all app containers from servers", hide: true def remove_containers - with_lock do + mutating do on(MRSK.hosts) do |host| roles = MRSK.roles_on(host) @@ -239,7 +239,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "remove_images", "Remove all app images from servers", hide: true def remove_images - with_lock do + mutating do on(MRSK.hosts) do execute *MRSK.auditor.record("Removed all app images"), verbosity: :debug execute *MRSK.app.remove_images diff --git a/lib/mrsk/cli/base.rb b/lib/mrsk/cli/base.rb index 8834ec11..44df756e 100644 --- a/lib/mrsk/cli/base.rb +++ b/lib/mrsk/cli/base.rb @@ -72,28 +72,28 @@ module Mrsk::Cli puts " Finished all in #{sprintf("%.1f seconds", runtime)}" end - def with_lock - if MRSK.holding_lock? + def mutating + return yield if MRSK.holding_lock? + + MRSK.config.ensure_env_available + + run_hook "pre-connect" + + acquire_lock + + begin yield - else - run_hook "pre-connect" - - acquire_lock - - begin - yield - rescue - if MRSK.hold_lock_on_error? - error " \e[31mDeploy lock was not released\e[0m" - else - release_lock - end - - raise + rescue + if MRSK.hold_lock_on_error? + error " \e[31mDeploy lock was not released\e[0m" + else + release_lock end - release_lock + raise end + + release_lock end def acquire_lock diff --git a/lib/mrsk/cli/build.rb b/lib/mrsk/cli/build.rb index 9628c757..e52b3358 100644 --- a/lib/mrsk/cli/build.rb +++ b/lib/mrsk/cli/build.rb @@ -3,7 +3,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base desc "deliver", "Build app and push app image to registry then pull image on servers" def deliver - with_lock do + mutating do push pull end @@ -11,7 +11,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base desc "push", "Build and push app image to registry" def push - with_lock do + mutating do cli = self verify_local_dependencies @@ -37,7 +37,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base desc "pull", "Pull app image from registry onto servers" def pull - with_lock do + mutating do on(MRSK.hosts) do execute *MRSK.auditor.record("Pulled image with version #{MRSK.config.version}"), verbosity: :debug execute *MRSK.builder.clean, raise_on_non_zero_exit: false @@ -48,7 +48,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base desc "create", "Create a build setup" def create - with_lock do + mutating do run_locally do begin debug "Using builder: #{MRSK.builder.name}" @@ -67,7 +67,7 @@ class Mrsk::Cli::Build < Mrsk::Cli::Base desc "remove", "Remove build setup" def remove - with_lock do + mutating do run_locally do debug "Using builder: #{MRSK.builder.name}" execute *MRSK.builder.remove diff --git a/lib/mrsk/cli/main.rb b/lib/mrsk/cli/main.rb index 18371bbf..bf0d8917 100644 --- a/lib/mrsk/cli/main.rb +++ b/lib/mrsk/cli/main.rb @@ -2,7 +2,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base desc "setup", "Setup all accessories and deploy app to servers" def setup print_runtime do - with_lock do + mutating do invoke "mrsk:cli:server:bootstrap" invoke "mrsk:cli:accessory:boot", [ "all" ] deploy @@ -14,7 +14,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push" def deploy runtime = print_runtime do - with_lock do + mutating do invoke_options = deploy_options say "Log into image registry...", :magenta @@ -53,7 +53,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push" def redeploy runtime = print_runtime do - with_lock do + mutating do invoke_options = deploy_options if options[:skip_push] @@ -83,7 +83,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base def rollback(version) rolled_back = false runtime = print_runtime do - with_lock do + mutating do invoke_options = deploy_options MRSK.config.version = version @@ -180,7 +180,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base desc "remove", "Remove Traefik, app, accessories, and registry session from servers" option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question" def remove - with_lock do + mutating do if options[:confirmed] || ask("This will remove all containers and images. Are you sure?", limited_to: %w( y N ), default: "N") == "y" invoke "mrsk:cli:traefik:remove", [], options.without(:confirmed) invoke "mrsk:cli:app:remove", [], options.without(:confirmed) diff --git a/lib/mrsk/cli/prune.rb b/lib/mrsk/cli/prune.rb index de227e08..381ddfd7 100644 --- a/lib/mrsk/cli/prune.rb +++ b/lib/mrsk/cli/prune.rb @@ -1,7 +1,7 @@ class Mrsk::Cli::Prune < Mrsk::Cli::Base desc "all", "Prune unused images and stopped containers" def all - with_lock do + mutating do containers images end @@ -9,7 +9,7 @@ class Mrsk::Cli::Prune < Mrsk::Cli::Base desc "images", "Prune dangling images" def images - with_lock do + mutating do on(MRSK.hosts) do execute *MRSK.auditor.record("Pruned images"), verbosity: :debug execute *MRSK.prune.dangling_images @@ -20,7 +20,7 @@ class Mrsk::Cli::Prune < Mrsk::Cli::Base desc "containers", "Prune all stopped containers, except the last 5" def containers - with_lock do + mutating do on(MRSK.hosts) do execute *MRSK.auditor.record("Pruned containers"), verbosity: :debug execute *MRSK.prune.containers diff --git a/lib/mrsk/cli/traefik.rb b/lib/mrsk/cli/traefik.rb index ced84459..30fd10f3 100644 --- a/lib/mrsk/cli/traefik.rb +++ b/lib/mrsk/cli/traefik.rb @@ -1,7 +1,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "boot", "Boot Traefik on servers" def boot - with_lock do + mutating do on(MRSK.traefik_hosts) do execute *MRSK.registry.login execute *MRSK.traefik.run, raise_on_non_zero_exit: false @@ -11,7 +11,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "reboot", "Reboot Traefik on servers (stop container, remove container, start new container)" def reboot - with_lock do + mutating do stop remove_container boot @@ -20,7 +20,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "start", "Start existing Traefik container on servers" def start - with_lock do + mutating do on(MRSK.traefik_hosts) do execute *MRSK.auditor.record("Started traefik"), verbosity: :debug execute *MRSK.traefik.start, raise_on_non_zero_exit: false @@ -30,7 +30,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "stop", "Stop existing Traefik container on servers" def stop - with_lock do + mutating do on(MRSK.traefik_hosts) do execute *MRSK.auditor.record("Stopped traefik"), verbosity: :debug execute *MRSK.traefik.stop, raise_on_non_zero_exit: false @@ -40,7 +40,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "restart", "Restart existing Traefik container on servers" def restart - with_lock do + mutating do stop start end @@ -77,7 +77,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "remove", "Remove Traefik container and image from servers" def remove - with_lock do + mutating do stop remove_container remove_image @@ -86,7 +86,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "remove_container", "Remove Traefik container from servers", hide: true def remove_container - with_lock do + mutating do on(MRSK.traefik_hosts) do execute *MRSK.auditor.record("Removed traefik container"), verbosity: :debug execute *MRSK.traefik.remove_container @@ -96,7 +96,7 @@ class Mrsk::Cli::Traefik < Mrsk::Cli::Base desc "remove_image", "Remove Traefik image from servers", hide: true def remove_image - with_lock do + mutating do on(MRSK.traefik_hosts) do execute *MRSK.auditor.record("Removed traefik image"), verbosity: :debug execute *MRSK.traefik.remove_image diff --git a/lib/mrsk/configuration.rb b/lib/mrsk/configuration.rb index 2b00a699..ee6dce05 100644 --- a/lib/mrsk/configuration.rb +++ b/lib/mrsk/configuration.rb @@ -170,7 +170,7 @@ class Mrsk::Configuration end def valid? - ensure_required_keys_present && ensure_env_available && ensure_valid_mrsk_version + ensure_required_keys_present && ensure_valid_mrsk_version end @@ -205,6 +205,14 @@ class Mrsk::Configuration Mrsk::Configuration::Builder.new(config: self) end + # Will raise KeyError if any secret ENVs are missing + def ensure_env_available + env_args + roles.each(&:env_args) + + true + end + private # Will raise ArgumentError if any required config keys are missing def ensure_required_keys_present @@ -229,14 +237,6 @@ class Mrsk::Configuration true end - # Will raise KeyError if any secret ENVs are missing - def ensure_env_available - env_args - roles.each(&:env_args) - - true - end - def ensure_valid_mrsk_version if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Mrsk::VERSION) raise ArgumentError, "Current version is #{Mrsk::VERSION}, minimum required is #{minimum_version}" diff --git a/test/cli/main_test.rb b/test/cli/main_test.rb index a5ff9d93..728ce24e 100644 --- a/test/cli/main_test.rb +++ b/test/cli/main_test.rb @@ -116,6 +116,12 @@ class CliMainTest < CliTestCase end end + test "deploy with missing secrets" do + assert_raises(KeyError) do + run_command("deploy", config_file: "deploy_with_secrets") + end + end + test "redeploy" do invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } diff --git a/test/configuration_test.rb b/test/configuration_test.rb index 606bb389..0f7e12ff 100644 --- a/test/configuration_test.rb +++ b/test/configuration_test.rb @@ -166,7 +166,7 @@ class ConfigurationTest < ActiveSupport::TestCase assert_raises(KeyError) do config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ env: { "secret" => [ "PASSWORD" ] } - }) }) + }) }).ensure_env_available end end diff --git a/test/fixtures/deploy_with_secrets.yml b/test/fixtures/deploy_with_secrets.yml new file mode 100644 index 00000000..a03cecbf --- /dev/null +++ b/test/fixtures/deploy_with_secrets.yml @@ -0,0 +1,11 @@ +service: app +image: dhh/app +servers: + - "1.1.1.1" + - "1.1.1.2" +registry: + username: user + password: pw +env: + secret: + - PASSWORD