Make rollbacks role-aware

Rollbacks stopped working after https://github.com/mrsked/mrsk/pull/99.

We'll confirm that a container is available for the first role on the
primary host before attempting to rollback.
This commit is contained in:
Donal McBreen
2023-04-12 09:45:50 +01:00
parent ab54dbdb8b
commit 43f7409de0
2 changed files with 30 additions and 18 deletions

View File

@@ -77,21 +77,26 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
with_lock do with_lock do
MRSK.config.version = version MRSK.config.version = version
if container_name_available?(MRSK.config.service_with_version) if container_available?(version)
say "Start version #{version}, then wait #{MRSK.config.readiness_delay}s for app to boot before stopping the old version...", :magenta say "Start version #{version}, then wait #{MRSK.config.readiness_delay}s for app to boot before stopping the old version...", :magenta
cli = self cli = self
old_version = nil old_version = nil
on(MRSK.hosts) do |host| on(MRSK.hosts) do |host|
old_version = capture_with_info(*MRSK.app.current_running_version).strip.presence roles = MRSK.roles_on(host)
execute *MRSK.app.start roles.each do |role|
app = MRSK.app(role: role)
old_version = capture_with_info(*app.current_running_version).strip.presence
execute *app.start
if old_version if old_version
sleep MRSK.config.readiness_delay sleep MRSK.config.readiness_delay
execute *MRSK.app.stop(version: old_version), raise_on_non_zero_exit: false execute *app.stop(version: old_version), raise_on_non_zero_exit: false
end
end end
end end
@@ -214,10 +219,15 @@ class Mrsk::Cli::Main < Mrsk::Cli::Base
subcommand "lock", Mrsk::Cli::Lock subcommand "lock", Mrsk::Cli::Lock
private private
def container_name_available?(container_name, host: MRSK.primary_host) def container_available?(version, host: MRSK.primary_host)
container_names = nil available = nil
on(host) { container_names = capture_with_info(*MRSK.app.list_container_names).split("\n") }
Array(container_names).include?(container_name) on(host) do
first_role = MRSK.roles_on(host).first
available = capture_with_info(*MRSK.app(role: first_role).container_id_for_version(version)).present?
end
available
end end
def deploy_options def deploy_options

View File

@@ -120,32 +120,34 @@ class CliMainTest < CliTestCase
end end
test "rollback bad version" do test "rollback bad version" do
# Mrsk::Cli::Main.any_instance.stubs(:container_available?).returns(false)
run_command("details") # Preheat MRSK const run_command("details") # Preheat MRSK const
run_command("rollback", "nonsense").tap do |output| run_command("rollback", "nonsense").tap do |output|
assert_match /docker container ls --all --filter label=service=app --format '{{ .Names }}'/, output assert_match /docker container ls --all --filter name=\^app-web-nonsense\$ --quiet/, output
assert_match /The app version 'nonsense' is not available as a container/, output assert_match /The app version 'nonsense' is not available as a container/, output
end end
end end
test "rollback good version" do test "rollback good version" do
Mrsk::Cli::Main.any_instance.stubs(:container_name_available?).returns(true) Mrsk::Cli::Main.any_instance.stubs(:container_available?).returns(true)
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:docker, :ps, "--filter", "label=service=app", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1").returns("version-to-rollback\n").at_least_once SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:docker, :ps, "--filter", "label=service=app", "--filter", "label=role=web", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1").returns("version-to-rollback\n").at_least_once
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:docker, :ps, "--filter", "label=service=app", "--filter", "label=role=workers", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1").returns("version-to-rollback\n").at_least_once
run_command("rollback", "123", config_file: "deploy_with_accessories").tap do |output| run_command("rollback", "123", config_file: "deploy_with_accessories").tap do |output|
assert_match "Start version 123", output assert_match "Start version 123", output
assert_match "docker start app-123", output assert_match "docker start app-web-123", output
assert_match "docker container ls --all --filter name=^app-version-to-rollback$ --quiet | xargs docker stop", output, "Should stop the container that was previously running" assert_match "docker container ls --all --filter name=^app-web-version-to-rollback$ --quiet | xargs docker stop", output, "Should stop the container that was previously running"
end end
end end
test "rollback without old version" do test "rollback without old version" do
Mrsk::Cli::Main.any_instance.stubs(:container_name_available?).returns(true) Mrsk::Cli::Main.any_instance.stubs(:container_available?).returns(true)
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:docker, :ps, "--filter", "label=service=app", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1").returns("").at_least_once SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:docker, :ps, "--filter", "label=service=app", "--filter", "label=role=web", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1").returns("").at_least_once
run_command("rollback", "123").tap do |output| run_command("rollback", "123").tap do |output|
assert_match "Start version 123", output assert_match "Start version 123", output
assert_match "docker start app-123", output assert_match "docker start app-web-123", output
assert_no_match "docker stop", output assert_no_match "docker stop", output
end end
end end