From fb3353084f903c16d9b367d55d12adbd4f917a2d Mon Sep 17 00:00:00 2001 From: Donal McBreen Date: Wed, 22 Mar 2023 15:44:27 +0000 Subject: [PATCH 1/2] Default to deploying the config version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we don't supply a version when deploying we'll use the result of docker image ls to decide which image to boot. But that doesn't necessarily correspond to the one we have just built. E.g. if you do something like: ``` mrsk deploy # deploys git sha AAAAAAAAAAAAAA git commit --amend # update the commit message mrsk deploy # deploys git sha BBBBBBBBBBBBBB ``` In this case running `docker image ls` will give you the same image twice (because the contents are identical) with tags for both SHAs but the image we have just built will not be returned first. Maybe the order is random, but it always seems to come second as far as I have seen. i.e you'll get something like: ``` REPOSITORY TAG IMAGE ID CREATED SIZE foo/bar AAAAAAAAAAAAAA 6272349a9619 31 minutes ago 791MB foo/bar BBBBBBBBBBBBBB 6272349a9619 31 minutes ago 791MB ``` Since we already know what version we want to deploy from the config, let's just pass that through. --- lib/mrsk/cli/main.rb | 8 ++++++-- test/cli/main_test.rb | 8 ++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/mrsk/cli/main.rb b/lib/mrsk/cli/main.rb index 328af480..e98d7604 100644 --- a/lib/mrsk/cli/main.rb +++ b/lib/mrsk/cli/main.rb @@ -11,7 +11,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base desc "deploy", "Deploy app to servers" option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push" def deploy - invoke_options = options.without(:skip_push) + invoke_options = deploy_options runtime = print_runtime do say "Ensure curl and Docker are installed...", :magenta @@ -46,7 +46,7 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base desc "redeploy", "Deploy app to servers without bootstrapping servers, starting Traefik, pruning, and registry login" option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push" def redeploy - invoke_options = options.without(:skip_push) + invoke_options = deploy_options runtime = print_runtime do if options[:skip_push] @@ -203,4 +203,8 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base on(host) { container_names = capture_with_info(*MRSK.app.list_container_names).split("\n") } Array(container_names).include?(container_name) end + + def deploy_options + { "version" => MRSK.config.version }.merge(options.without("skip_push")) + end end diff --git a/test/cli/main_test.rb b/test/cli/main_test.rb index f72741dd..76638725 100644 --- a/test/cli/main_test.rb +++ b/test/cli/main_test.rb @@ -10,7 +10,7 @@ class CliMainTest < CliTestCase end test "deploy" do - invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => false } + invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options) @@ -31,7 +31,7 @@ class CliMainTest < CliTestCase end test "deploy with skip_push" do - invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => true } + invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options) @@ -52,7 +52,7 @@ class CliMainTest < CliTestCase end test "redeploy" do - invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => false} + invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options) @@ -65,7 +65,7 @@ class CliMainTest < CliTestCase end test "redeploy with skip_push" do - invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "skip_push" => true } + invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:pull", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options) From 1ed4a37da2b73125c37044d04e5a9a5ba0efd62a Mon Sep 17 00:00:00 2001 From: Donal McBreen Date: Thu, 23 Mar 2023 14:35:12 +0000 Subject: [PATCH 2/2] Pull latest image tag, so we can identity it `docker image ls` doesn't tell us what the latest deployed image is (e.g if we've rolled back). Pull the latest image tag through to the server so we can use it instead. --- lib/mrsk/cli/app.rb | 21 +++++++-------------- lib/mrsk/commands/app.rb | 13 ------------- lib/mrsk/commands/builder/base.rb | 1 + test/cli/app_test.rb | 5 ++--- test/cli/build_test.rb | 2 +- test/commands/app_test.rb | 6 ------ 6 files changed, 11 insertions(+), 37 deletions(-) diff --git a/lib/mrsk/cli/app.rb b/lib/mrsk/cli/app.rb index 796cd367..9b3ea596 100644 --- a/lib/mrsk/cli/app.rb +++ b/lib/mrsk/cli/app.rb @@ -2,7 +2,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base desc "boot", "Boot app on servers (or reboot app if already running)" def boot say "Get most recent version available as an image...", :magenta unless options[:version] - using_version(options[:version] || most_recent_version_available) do |version| + using_version(version_or_latest) do |version| say "Start container with version #{version} using a #{MRSK.config.readiness_delay}s readiness delay (or reboot if already running)...", :magenta cli = self @@ -70,7 +70,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base when options[:interactive] say "Get most recent version available as an image...", :magenta unless options[:version] - using_version(options[:version] || most_recent_version_available) do |version| + using_version(version_or_latest) do |version| say "Launching interactive command with version #{version} via SSH from new container on #{MRSK.primary_host}...", :magenta run_locally { exec MRSK.app.execute_in_new_container_over_ssh(cmd, host: MRSK.primary_host) } end @@ -88,7 +88,7 @@ class Mrsk::Cli::App < Mrsk::Cli::Base else say "Get most recent version available as an image...", :magenta unless options[:version] - using_version(options[:version] || most_recent_version_available) do |version| + using_version(version_or_latest) do |version| say "Launching command with version #{version} from new container...", :magenta on(MRSK.hosts) do |host| execute *MRSK.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug @@ -189,20 +189,13 @@ class Mrsk::Cli::App < Mrsk::Cli::Base end end - def most_recent_version_available(host: MRSK.primary_host) - version = nil - on(host) { version = capture_with_info(*MRSK.app.most_recent_version_from_available_images).strip } - - if version == "" - raise "Most recent image available was not tagged with a version (returned )" - else - version.presence - end - end - def current_running_version(host: MRSK.primary_host) version = nil on(host) { version = capture_with_info(*MRSK.app.current_running_version).strip } version.presence end + + def version_or_latest + options[:version] || "latest" + end end diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index e650217a..ad0a21d7 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -87,19 +87,6 @@ class Mrsk::Commands::App < Mrsk::Commands::Base "tail -n 1" end - def most_recent_version_from_available_images - pipe \ - docker(:image, :ls, "--format", '"{{.Tag}}"', config.repository), - "head -n 1" - end - - def all_versions_from_available_containers - pipe \ - docker(:image, :ls, "--format", '"{{.Tag}}"', config.repository), - "head -n 1" - end - - def list_containers docker :container, :ls, "--all", *filter_args end diff --git a/lib/mrsk/commands/builder/base.rb b/lib/mrsk/commands/builder/base.rb index 91276260..448ecca4 100644 --- a/lib/mrsk/commands/builder/base.rb +++ b/lib/mrsk/commands/builder/base.rb @@ -7,6 +7,7 @@ class Mrsk::Commands::Builder::Base < Mrsk::Commands::Base def pull docker :pull, config.absolute_image + docker :pull, config.latest_image end def build_options diff --git a/test/cli/app_test.rb b/test/cli/app_test.rb index 36fc0691..b2b6786a 100644 --- a/test/cli/app_test.rb +++ b/test/cli/app_test.rb @@ -28,9 +28,8 @@ class CliAppTest < CliTestCase .returns([ :docker, :run ]) run_command("boot").tap do |output| - assert_match "Rebooting container with same version 999 already deployed", output # Can't start what's already running - assert_match "docker container ls --all --filter name=app-999 --quiet | xargs docker container rm", output # Stop old running - assert_match "docker container ls --all --filter name=app-999 --quiet | xargs docker container rm", output # Remove old container + assert_match "Rebooting container with same version latest already deployed", output # Can't start what's already running + assert_match "docker container ls --all --filter name=app-latest --quiet | xargs docker container rm", output # Remove old container assert_match "docker run", output # Start new container end ensure diff --git a/test/cli/build_test.rb b/test/cli/build_test.rb index 44802549..d721373b 100644 --- a/test/cli/build_test.rb +++ b/test/cli/build_test.rb @@ -29,7 +29,7 @@ class CliBuildTest < CliTestCase test "pull" do run_command("pull").tap do |output| assert_match /docker image rm --force dhh\/app:999/, output - assert_match /docker pull dhh\/app:999/, output + assert_match /docker pull dhh\/app:latest/, output end end diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index 34596318..2651abdc 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -189,12 +189,6 @@ class CommandsAppTest < ActiveSupport::TestCase new_command.current_running_version.join(" ") end - test "most_recent_version_from_available_images" do - assert_equal \ - "docker image ls --format \"{{.Tag}}\" dhh/app | head -n 1", - new_command.most_recent_version_from_available_images.join(" ") - end - test "list_containers" do assert_equal \ "docker container ls --all --filter label=service=app",