From e7ac73be5afd149ae6d540e65070692c0e6f091f Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 10:14:31 +0100 Subject: [PATCH 01/10] Join in run_over_ssh instead of all over --- lib/mrsk/commands/accessory.rb | 4 ++-- lib/mrsk/commands/app.rb | 16 +++++++++------- lib/mrsk/commands/base.rb | 4 ++-- test/commands/accessory_test.rb | 4 ++-- test/commands/app_test.rb | 4 ++-- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/mrsk/commands/accessory.rb b/lib/mrsk/commands/accessory.rb index 0e9c5c12..be7d59b5 100644 --- a/lib/mrsk/commands/accessory.rb +++ b/lib/mrsk/commands/accessory.rb @@ -64,11 +64,11 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base end def execute_in_existing_container_over_ssh(*command) - run_over_ssh execute_in_existing_container(*command, interactive: true).join(" ") + run_over_ssh execute_in_existing_container(*command, interactive: true) end def execute_in_new_container_over_ssh(*command) - run_over_ssh execute_in_new_container(*command, interactive: true).join(" ") + run_over_ssh execute_in_new_container(*command, interactive: true) end def run_over_ssh(command) diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index ae4fce97..7dd66503 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -35,11 +35,13 @@ class Mrsk::Commands::App < Mrsk::Commands::Base end def follow_logs(host:, grep: nil) - run_over_ssh pipe( - current_container_id, - "xargs docker logs -t -n 10 -f 2>&1", - (%(grep "#{grep}") if grep) - ).join(" "), host: host + run_over_ssh \ + pipe( + current_container_id, + "xargs docker logs -t -n 10 -f 2>&1", + (%(grep "#{grep}") if grep) + ), + host: host end @@ -62,11 +64,11 @@ class Mrsk::Commands::App < Mrsk::Commands::Base end def execute_in_existing_container_over_ssh(*command, host:) - run_over_ssh execute_in_existing_container(*command, interactive: true).join(" "), host: host + run_over_ssh execute_in_existing_container(*command, interactive: true), host: host end def execute_in_new_container_over_ssh(*command, host:) - run_over_ssh execute_in_new_container(*command, interactive: true).join(" "), host: host + run_over_ssh execute_in_new_container(*command, interactive: true), host: host end diff --git a/lib/mrsk/commands/base.rb b/lib/mrsk/commands/base.rb index 9c0bd1c7..7b7d644c 100644 --- a/lib/mrsk/commands/base.rb +++ b/lib/mrsk/commands/base.rb @@ -8,8 +8,8 @@ module Mrsk::Commands @config = config end - def run_over_ssh(command, host:) - "ssh -t #{config.ssh_user}@#{host} '#{command}'" + def run_over_ssh(*command, host:) + "ssh -t #{config.ssh_user}@#{host} '#{command.join(" ")}'" end private diff --git a/test/commands/accessory_test.rb b/test/commands/accessory_test.rb index 8a68cbb7..60add274 100644 --- a/test/commands/accessory_test.rb +++ b/test/commands/accessory_test.rb @@ -81,14 +81,14 @@ class CommandsAccessoryTest < ActiveSupport::TestCase end test "execute in new container over ssh" do - @mysql.stub(:run_over_ssh, ->(cmd) { cmd }) do + @mysql.stub(:run_over_ssh, ->(cmd) { cmd.join(" ") }) do assert_match %r|docker run -it --rm -e MYSQL_ROOT_PASSWORD=secret123 -e MYSQL_ROOT_HOST=% mysql:8.0 mysql -u root|, @mysql.execute_in_new_container_over_ssh("mysql", "-u", "root") end end test "execute in existing container over ssh" do - @mysql.stub(:run_over_ssh, ->(cmd) { cmd }) do + @mysql.stub(:run_over_ssh, ->(cmd) { cmd.join(" ") }) do assert_match %r|docker exec -it app-mysql mysql -u root|, @mysql.execute_in_existing_container_over_ssh("mysql", "-u", "root") end diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index 2cbc0eec..b39a3781 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -38,14 +38,14 @@ class CommandsAppTest < ActiveSupport::TestCase end test "execute in new container over ssh" do - @app.stub(:run_over_ssh, ->(cmd, host:) { cmd }) do + @app.stub(:run_over_ssh, ->(cmd, host:) { cmd.join(" ") }) do assert_match %r|docker run -it --rm -e RAILS_MASTER_KEY=456 dhh/app:missing bin/rails c|, @app.execute_in_new_container_over_ssh("bin/rails", "c", host: "app-1") end end test "execute in existing container over ssh" do - @app.stub(:run_over_ssh, ->(cmd, host:) { cmd }) do + @app.stub(:run_over_ssh, ->(cmd, host:) { cmd.join(" ") }) do assert_match %r|docker exec -it app-missing bin/rails c|, @app.execute_in_existing_container_over_ssh("bin/rails", "c", host: "app-1") end From 77c63dcd0449c6a78e5e40130bc2bc5cd3488c63 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 10:14:35 +0100 Subject: [PATCH 02/10] Style --- lib/mrsk/commands/accessory.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mrsk/commands/accessory.rb b/lib/mrsk/commands/accessory.rb index be7d59b5..16e3b854 100644 --- a/lib/mrsk/commands/accessory.rb +++ b/lib/mrsk/commands/accessory.rb @@ -39,10 +39,10 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base end def follow_logs(grep: nil) - run_over_ssh pipe( - docker(:logs, service_name, "-t", "-n", "10", "-f", "2>&1"), - (%(grep "#{grep}") if grep) - ).join(" ") + run_over_ssh \ + pipe \ + docker(:logs, service_name, "-t", "-n", "10", "-f", "2>&1"), + (%(grep "#{grep}") if grep) end From 7077da5a64895581af6d69f8d8a2e33b2a4575da Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 10:15:43 +0100 Subject: [PATCH 03/10] Spacing --- lib/mrsk/cli/accessory.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mrsk/cli/accessory.rb b/lib/mrsk/cli/accessory.rb index 5bf9ff9b..97e16d37 100644 --- a/lib/mrsk/cli/accessory.rb +++ b/lib/mrsk/cli/accessory.rb @@ -7,6 +7,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base with_accessory(name) do |accessory| directories(name) upload(name) + on(accessory.host) do execute *MRSK.auditor.record("accessory #{name} boot"), verbosity: :debug execute *accessory.run From 6f1a3f5524a8c14c1e4f595d5374a5e5b92b57f2 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 10:16:24 +0100 Subject: [PATCH 04/10] Don't need this, just use containers --- lib/mrsk/cli/app.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/mrsk/cli/app.rb b/lib/mrsk/cli/app.rb index e4c71493..eb4e77f4 100644 --- a/lib/mrsk/cli/app.rb +++ b/lib/mrsk/cli/app.rb @@ -104,11 +104,6 @@ class Mrsk::Cli::App < Mrsk::Cli::Base on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.list_images) } end - desc "current", "Return the current running container ID" - def current - on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.current_container_id) } - end - desc "logs", "Show lines from app on servers" option :since, aliases: "-s", desc: "Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes)" option :lines, type: :numeric, aliases: "-n", desc: "Number of log lines to pull from each server" From 340929e7e78be7d74a234679a715974ab5f5438d Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 10:20:51 +0100 Subject: [PATCH 05/10] Use a version --- test/commands/app_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index b39a3781..c40e59a7 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -5,48 +5,48 @@ class CommandsAppTest < ActiveSupport::TestCase ENV["RAILS_MASTER_KEY"] = "456" @config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ] } - @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config) + @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config).tap { |c| c.version = "999" } end teardown do - ENV["RAILS_MASTER_KEY"] = nil + ENV.delete("RAILS_MASTER_KEY") end test "run" do assert_equal \ - [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-missing", "-e", "RAILS_MASTER_KEY=456", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:missing"], @app.run + [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-999", "-e", "RAILS_MASTER_KEY=456", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:999"], @app.run end test "run with volumes" do @config[:volumes] = ["/local/path:/container/path" ] assert_equal \ - [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-missing", "-e", "RAILS_MASTER_KEY=456", "--volume", "/local/path:/container/path", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:missing"], @app.run + [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-999", "-e", "RAILS_MASTER_KEY=456", "--volume", "/local/path:/container/path", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:999"], @app.run end test "execute in new container" do assert_equal \ - [ :docker, :run, "--rm", "-e", "RAILS_MASTER_KEY=456", "dhh/app:missing", "bin/rails", "db:setup" ], + [ :docker, :run, "--rm", "-e", "RAILS_MASTER_KEY=456", "dhh/app:999", "bin/rails", "db:setup" ], @app.execute_in_new_container("bin/rails", "db:setup") end test "execute in existing container" do assert_equal \ - [ :docker, :exec, "app-missing", "bin/rails", "db:setup" ], + [ :docker, :exec, "app-999", "bin/rails", "db:setup" ], @app.execute_in_existing_container("bin/rails", "db:setup") end test "execute in new container over ssh" do @app.stub(:run_over_ssh, ->(cmd, host:) { cmd.join(" ") }) do - assert_match %r|docker run -it --rm -e RAILS_MASTER_KEY=456 dhh/app:missing bin/rails c|, + assert_match %r|docker run -it --rm -e RAILS_MASTER_KEY=456 dhh/app:999 bin/rails c|, @app.execute_in_new_container_over_ssh("bin/rails", "c", host: "app-1") end end test "execute in existing container over ssh" do @app.stub(:run_over_ssh, ->(cmd, host:) { cmd.join(" ") }) do - assert_match %r|docker exec -it app-missing bin/rails c|, + assert_match %r|docker exec -it app-999 bin/rails c|, @app.execute_in_existing_container_over_ssh("bin/rails", "c", host: "app-1") end end From 74c7a6d5ded108cfbf67dc0a4f6dbd4ea088e015 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 10:31:04 +0100 Subject: [PATCH 06/10] Expand app command testing --- test/commands/app_test.rb | 83 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 4 deletions(-) diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index c40e59a7..f1fd211c 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -24,6 +24,70 @@ class CommandsAppTest < ActiveSupport::TestCase [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-999", "-e", "RAILS_MASTER_KEY=456", "--volume", "/local/path:/container/path", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:999"], @app.run end + test "run without master key" do + ENV["RAILS_MASTER_KEY"] = nil + @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config.tap { |c| c[:skip_master_key] = true }) + + assert @app.run.exclude?("RAILS_MASTER_KEY=456") + end + + test "start" do + assert_equal \ + [ :docker, :start, "app-999" ], + @app.start + end + + test "stop" do + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app", "|", :xargs, :docker, :stop ], + @app.stop + end + + test "info" do + assert_equal \ + [ :docker, :ps, "--filter", "label=service=app" ], + @app.info + end + + + test "logs" do + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs 2>&1" ], + @app.logs + + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs --since 5m 2>&1" ], + @app.logs(since: "5m") + + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs -n 100 2>&1" ], + @app.logs(lines: "100") + + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs --since 5m -n 100 2>&1" ], + @app.logs(since: "5m", lines: "100") + + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs 2>&1", "|", "grep 'my-id'" ], + @app.logs(grep: "my-id") + + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs --since 5m 2>&1", "|", "grep 'my-id'" ], + @app.logs(since: "5m", grep: "my-id") + end + + test "follow logs" do + @app.stub(:run_over_ssh, ->(cmd, host:) { cmd.join(" ") }) do + assert_equal \ + "docker ps -q --filter label=service=app | xargs docker logs -t -n 10 -f 2>&1", + @app.follow_logs(host: "app-1") + + assert_equal \ + "docker ps -q --filter label=service=app | xargs docker logs -t -n 10 -f 2>&1 | grep \"Completed\"", + @app.follow_logs(host: "app-1", grep: "Completed") + end + end + test "execute in new container" do assert_equal \ @@ -52,10 +116,21 @@ class CommandsAppTest < ActiveSupport::TestCase end - test "run without master key" do - ENV["RAILS_MASTER_KEY"] = nil - @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config.tap { |c| c[:skip_master_key] = true }) + test "current_container_id" do + assert_equal \ + [ :docker, :ps, "-q", "--filter", "label=service=app" ], + @app.current_container_id + end - assert @app.run.exclude?("RAILS_MASTER_KEY=456") + test "container_id_for" do + assert_equal \ + [ :docker, :container, :ls, "-a", "-f", "name=app-999", "-q" ], + @app.container_id_for(container_name: "app-999") + end + + test "current_running_version" do + assert_equal \ + [ :docker, :ps, "--filter", "label=service=app", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1" ], + @app.current_running_version end end From 78d4e1e1e9087dd5e5049134dbb684822188919e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 15:12:06 +0100 Subject: [PATCH 07/10] Easier to read --- test/commands/app_test.rb | 68 ++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index f1fd211c..d6a398e0 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -14,14 +14,16 @@ class CommandsAppTest < ActiveSupport::TestCase test "run" do assert_equal \ - [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-999", "-e", "RAILS_MASTER_KEY=456", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:999"], @app.run + "docker run -d --restart unless-stopped --name app-999 -e RAILS_MASTER_KEY=456 --label service=app --label role=web --label traefik.http.routers.app.rule='PathPrefix(`/`)' --label traefik.http.services.app.loadbalancer.healthcheck.path=/up --label traefik.http.services.app.loadbalancer.healthcheck.interval=1s --label traefik.http.middlewares.app.retry.attempts=3 --label traefik.http.middlewares.app.retry.initialinterval=500ms dhh/app:999", + @app.run.join(" ") end test "run with volumes" do @config[:volumes] = ["/local/path:/container/path" ] assert_equal \ - [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-999", "-e", "RAILS_MASTER_KEY=456", "--volume", "/local/path:/container/path", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:999"], @app.run + "docker run -d --restart unless-stopped --name app-999 -e RAILS_MASTER_KEY=456 --volume /local/path:/container/path --label service=app --label role=web --label traefik.http.routers.app.rule='PathPrefix(`/`)' --label traefik.http.services.app.loadbalancer.healthcheck.path=/up --label traefik.http.services.app.loadbalancer.healthcheck.interval=1s --label traefik.http.middlewares.app.retry.attempts=3 --label traefik.http.middlewares.app.retry.initialinterval=500ms dhh/app:999", + @app.run.join(" ") end test "run without master key" do @@ -33,47 +35,47 @@ class CommandsAppTest < ActiveSupport::TestCase test "start" do assert_equal \ - [ :docker, :start, "app-999" ], - @app.start + "docker start app-999", + @app.start.join(" ") end test "stop" do assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app", "|", :xargs, :docker, :stop ], - @app.stop + "docker ps -q --filter label=service=app | xargs docker stop", + @app.stop.join(" ") end test "info" do assert_equal \ - [ :docker, :ps, "--filter", "label=service=app" ], - @app.info + "docker ps --filter label=service=app", + @app.info.join(" ") end test "logs" do assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs 2>&1" ], - @app.logs + "docker ps -q --filter label=service=app | xargs docker logs 2>&1", + @app.logs.join(" ") assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs --since 5m 2>&1" ], - @app.logs(since: "5m") + "docker ps -q --filter label=service=app | xargs docker logs --since 5m 2>&1", + @app.logs(since: "5m").join(" ") assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs -n 100 2>&1" ], - @app.logs(lines: "100") + "docker ps -q --filter label=service=app | xargs docker logs -n 100 2>&1", + @app.logs(lines: "100").join(" ") assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs --since 5m -n 100 2>&1" ], - @app.logs(since: "5m", lines: "100") + "docker ps -q --filter label=service=app | xargs docker logs --since 5m -n 100 2>&1", + @app.logs(since: "5m", lines: "100").join(" ") assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs 2>&1", "|", "grep 'my-id'" ], - @app.logs(grep: "my-id") + "docker ps -q --filter label=service=app | xargs docker logs 2>&1 | grep 'my-id'", + @app.logs(grep: "my-id").join(" ") assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app", "|", "xargs docker logs --since 5m 2>&1", "|", "grep 'my-id'" ], - @app.logs(since: "5m", grep: "my-id") + "docker ps -q --filter label=service=app | xargs docker logs --since 5m 2>&1 | grep 'my-id'", + @app.logs(since: "5m", grep: "my-id").join(" ") end test "follow logs" do @@ -91,14 +93,14 @@ class CommandsAppTest < ActiveSupport::TestCase test "execute in new container" do assert_equal \ - [ :docker, :run, "--rm", "-e", "RAILS_MASTER_KEY=456", "dhh/app:999", "bin/rails", "db:setup" ], - @app.execute_in_new_container("bin/rails", "db:setup") + "docker run --rm -e RAILS_MASTER_KEY=456 dhh/app:999 bin/rails db:setup", + @app.execute_in_new_container("bin/rails", "db:setup").join(" ") end test "execute in existing container" do assert_equal \ - [ :docker, :exec, "app-999", "bin/rails", "db:setup" ], - @app.execute_in_existing_container("bin/rails", "db:setup") + "docker exec app-999 bin/rails db:setup", + @app.execute_in_existing_container("bin/rails", "db:setup").join(" ") end test "execute in new container over ssh" do @@ -118,19 +120,25 @@ class CommandsAppTest < ActiveSupport::TestCase test "current_container_id" do assert_equal \ - [ :docker, :ps, "-q", "--filter", "label=service=app" ], - @app.current_container_id + "docker ps -q --filter label=service=app", + @app.current_container_id.join(" ") end test "container_id_for" do assert_equal \ - [ :docker, :container, :ls, "-a", "-f", "name=app-999", "-q" ], - @app.container_id_for(container_name: "app-999") + "docker container ls -a -f name=app-999 -q", + @app.container_id_for(container_name: "app-999").join(" ") end test "current_running_version" do assert_equal \ - [ :docker, :ps, "--filter", "label=service=app", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1" ], - @app.current_running_version + "docker ps --filter label=service=app --format \"{{.Names}}\" | sed 's/-/\\n/g' | tail -n 1", + @app.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", + @app.most_recent_version_from_available_images.join(" ") end end From 64a5a790a774c42d73c91fbd758631c7c4dc7ea8 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 15:26:43 +0100 Subject: [PATCH 08/10] Ensure secret can be used alone --- lib/mrsk/configuration/role.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/mrsk/configuration/role.rb b/lib/mrsk/configuration/role.rb index f8e15da5..f8d4461c 100644 --- a/lib/mrsk/configuration/role.rb +++ b/lib/mrsk/configuration/role.rb @@ -96,7 +96,11 @@ class Mrsk::Configuration::Role def merged_env_with_secrets merged_env.tap do |new_env| new_env["secret"] = Array(config.env["secret"]) + Array(specialized_env["secret"]) - new_env["clear"] = (Array(config.env["clear"] || config.env) + Array(specialized_env["clear"] || specialized_env)).uniq + + clear_app_env = config.env["secret"] ? Array(config.env["clear"]) : Array(config.env["clear"] || config.env) + clear_role_env = specialized_env["secret"] ? Array(specialized_env["clear"]) : Array(specialized_env["clear"] || specialized_env) + + new_env["clear"] = (clear_app_env + clear_role_env).uniq end end end From cf9a402ad826677d6ce8ec619dd0df5bd06cd0ef Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 15:26:59 +0100 Subject: [PATCH 09/10] Stop treating RAILS_MASTER_KEY as special --- README.md | 13 ++++--------- lib/mrsk/commands/app.rb | 10 ---------- lib/mrsk/configuration.rb | 6 ------ test/commands/app_test.rb | 9 +-------- test/configuration_test.rb | 9 --------- 5 files changed, 5 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index e34db4ff..613981bd 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,15 @@ servers: registry: username: registry-user-name password: <%= ENV.fetch("MRSK_REGISTRY_PASSWORD") %> +env: + secret: + - RAILS_MASTER_KEY ``` Now you're ready to deploy a multi-arch image to the servers: ``` -MRSK_REGISTRY_PASSWORD=pw mrsk deploy +RAILS_MASTER_KEY=123 MRSK_REGISTRY_PASSWORD=pw mrsk deploy ``` This will: @@ -265,14 +268,6 @@ ARG RUBY_VERSION FROM ruby:$RUBY_VERSION-slim as base ``` -### Using without RAILS_MASTER_KEY - -If you're using MRSK with older Rails apps that predate RAILS_MASTER_KEY, or with a non-Rails app, you can skip the default usage and reference: - -```yaml -skip_master_key: true -``` - ### Using accessories for database, cache, search services You can manage your accessory services via MRSK as well. The services will build off public images, and will not be automatically updated when you deploy: diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index 7dd66503..9c8407ac 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -6,7 +6,6 @@ class Mrsk::Commands::App < Mrsk::Commands::Base "-d", "--restart unless-stopped", "--name", service_with_version, - *rails_master_key_arg, *role.env_args, *config.volume_args, *role.label_args, @@ -56,7 +55,6 @@ class Mrsk::Commands::App < Mrsk::Commands::Base docker :run, ("-it" if interactive), "--rm", - *rails_master_key_arg, *config.env_args, *config.volume_args, config.absolute_image, @@ -130,12 +128,4 @@ class Mrsk::Commands::App < Mrsk::Commands::Base def service_filter [ "--filter", "label=service=#{config.service}" ] end - - def rails_master_key_arg - if master_key = config.master_key - [ "-e", redact("RAILS_MASTER_KEY=#{master_key}") ] - else - [] - end - end end diff --git a/lib/mrsk/configuration.rb b/lib/mrsk/configuration.rb index 6e7dff38..c2dfc188 100644 --- a/lib/mrsk/configuration.rb +++ b/lib/mrsk/configuration.rb @@ -110,12 +110,6 @@ class Mrsk::Configuration { user: ssh_user, auth_methods: [ "publickey" ] } end - def master_key - unless raw_config.skip_master_key - ENV["RAILS_MASTER_KEY"] || File.read(Pathname.new(File.expand_path("config/master.key"))) - end - end - def valid? ensure_required_keys_present && ensure_env_available diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index d6a398e0..aaa0e751 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -4,7 +4,7 @@ class CommandsAppTest < ActiveSupport::TestCase setup do ENV["RAILS_MASTER_KEY"] = "456" - @config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ] } + @config = { service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" }, servers: [ "1.1.1.1" ], env: { "secret" => [ "RAILS_MASTER_KEY" ] } } @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config).tap { |c| c.version = "999" } end @@ -26,13 +26,6 @@ class CommandsAppTest < ActiveSupport::TestCase @app.run.join(" ") end - test "run without master key" do - ENV["RAILS_MASTER_KEY"] = nil - @app = Mrsk::Commands::App.new Mrsk::Configuration.new(@config.tap { |c| c[:skip_master_key] = true }) - - assert @app.run.exclude?("RAILS_MASTER_KEY=456") - end - test "start" do assert_equal \ "docker start app-999", diff --git a/test/configuration_test.rb b/test/configuration_test.rb index 7cbebabd..5146d516 100644 --- a/test/configuration_test.rb +++ b/test/configuration_test.rb @@ -143,15 +143,6 @@ class ConfigurationTest < ActiveSupport::TestCase assert_equal "app", @config.ssh_options[:user] end - test "master key" do - assert_equal "456", @config.master_key - end - - test "skip master key" do - config = Mrsk::Configuration.new(@deploy.tap { |c| c[:skip_master_key] = true }) - assert_nil @config.master_key - end - test "volume_args" do assert_equal ["--volume", "/local/path:/container/path"], @config.volume_args end From 45207f0c4ffda5cf7a8325f2a81129869410e063 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 4 Feb 2023 15:27:41 +0100 Subject: [PATCH 10/10] Explain the dance --- lib/mrsk/configuration/role.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/mrsk/configuration/role.rb b/lib/mrsk/configuration/role.rb index f8d4461c..dbac24bc 100644 --- a/lib/mrsk/configuration/role.rb +++ b/lib/mrsk/configuration/role.rb @@ -97,6 +97,7 @@ class Mrsk::Configuration::Role merged_env.tap do |new_env| new_env["secret"] = Array(config.env["secret"]) + Array(specialized_env["secret"]) + # If there's no secret/clear split, everything is clear clear_app_env = config.env["secret"] ? Array(config.env["clear"]) : Array(config.env["clear"] || config.env) clear_role_env = specialized_env["secret"] ? Array(specialized_env["clear"]) : Array(specialized_env["clear"] || specialized_env)