From 31389bc7b544938778ff11a13c51813037d17630 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 20 Jan 2023 17:18:32 +0100 Subject: [PATCH] Global option for designating primary host only --- lib/mrsk/cli/app.rb | 32 ++++++++------------------------ lib/mrsk/cli/base.rb | 7 +++++-- lib/mrsk/commander.rb | 20 ++++++++++++++------ lib/mrsk/commands/app.rb | 4 ++-- lib/mrsk/configuration.rb | 6 +++--- test/commander_test.rb | 13 ++++++++++--- test/configuration_test.rb | 10 +++++++--- 7 files changed, 49 insertions(+), 43 deletions(-) diff --git a/lib/mrsk/cli/app.rb b/lib/mrsk/cli/app.rb index 7fcf1c24..613d39cf 100644 --- a/lib/mrsk/cli/app.rb +++ b/lib/mrsk/cli/app.rb @@ -39,49 +39,33 @@ class Mrsk::Cli::App < Mrsk::Cli::Base on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.info) } end - desc "exec [CMD]", "Execute a custom task on servers passed in as CMD='bin/rake some:task'" - option :once, type: :boolean, default: false, desc: "Only perform command on primary host" + desc "exec [CMD]", "Execute a custom command on servers" option :run, type: :boolean, default: false, desc: "Start a new container to run the command rather than reusing existing" def exec(cmd) runner = options[:run] ? :run_exec : :exec - - if options[:once] - on(MRSK.config.primary_host) { puts capture_with_info(*MRSK.app.send(runner, cmd)) } - else - on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.send(runner, cmd)) } - end + on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.send(runner, cmd)) } end - desc "console", "Start Rails Console on primary host" - option :host, desc: "Start console on a different host" + desc "console", "Start Rails Console on primary host (or specific host set by --hosts)" def console - host = options[:host] || MRSK.config.primary_host - run_locally do - puts "Launching Rails console on #{host}..." - exec MRSK.app.console(host: host) + puts "Launching Rails console on #{MRSK.primary_host}..." + exec MRSK.app.console(host: MRSK.primary_host) end end desc "bash", "Start a bash session on primary host" option :host, desc: "Start bash on a different host" def bash - host = options[:host] || MRSK.config.primary_host - run_locally do - puts "Launching bash session on #{host}..." - exec MRSK.app.bash(host: host) + puts "Launching bash session on #{MRSK.primary_host}..." + exec MRSK.app.bash(host: MRSK.primary_host) end end desc "runner [EXPRESSION]", "Execute Rails runner with given expression" - option :once, type: :boolean, default: false, desc: "Only perform runner on primary host" def runner(expression) - if options[:once] - on(MRSK.config.primary_host) { puts capture_with_info(*MRSK.app.exec("bin/rails", "runner", "'#{expression}'")) } - else - on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.exec("bin/rails", "runner", "'#{expression}'")) } - end + on(MRSK.hosts) { |host| puts_by_host host, capture_with_info(*MRSK.app.exec("bin/rails", "runner", "'#{expression}'")) } end desc "containers", "List all the app containers currently on servers" diff --git a/lib/mrsk/cli/base.rb b/lib/mrsk/cli/base.rb index e825d6c7..567f19b3 100644 --- a/lib/mrsk/cli/base.rb +++ b/lib/mrsk/cli/base.rb @@ -9,6 +9,7 @@ module Mrsk::Cli class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging" + class_option :primary, type: :boolean, aliases: "-p", desc: "Run commands only on primary host instead of all" class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma)" class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma)" @@ -25,9 +26,11 @@ module Mrsk::Cli MRSK.tap do |commander| commander.config_file = Pathname.new(File.expand_path(options[:config_file])) commander.destination = options[:destination] - commander.hosts = options[:hosts]&.split(",") - commander.roles = options[:roles]&.split(",") commander.verbose = options[:verbose] + + commander.specific_hosts = options[:hosts]&.split(",") + commander.specific_roles = options[:roles]&.split(",") + commander.specific_primary! if options[:primary] end end diff --git a/lib/mrsk/commander.rb b/lib/mrsk/commander.rb index dff49b0e..8ea7f9de 100644 --- a/lib/mrsk/commander.rb +++ b/lib/mrsk/commander.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/enumerable" + require "mrsk/configuration" require "mrsk/commands/app" require "mrsk/commands/builder" @@ -16,20 +18,26 @@ class Mrsk::Commander @config ||= Mrsk::Configuration.create_from(config_file, destination: destination).tap { |config| setup_with(config) } end - def hosts=(hosts) - @hosts = hosts if hosts.present? + attr_accessor :specific_hosts + + def specific_primary! + self.specific_hosts = [ config.primary_web_host ] end - def roles=(role_names) - @hosts = config.roles.select { |r| role_names.include?(r.name) }.flat_map(&:hosts) if role_names.present? + def specific_roles=(role_names) + self.specific_hosts = config.roles.select { |r| role_names.include?(r.name) }.flat_map(&:hosts) if role_names.present? + end + + def primary_host + specific_hosts&.sole || config.primary_web_host end def hosts - @hosts || config.all_hosts + specific_hosts || config.all_hosts end def traefik_hosts - @hosts || config.traefik_hosts + specific_hosts || config.traefik_hosts end diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index 14c1f3fa..e1faf9dc 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -57,11 +57,11 @@ class Mrsk::Commands::App < Mrsk::Commands::Base *command end - def console(host: config.primary_host) + def console(host:) exec_over_ssh "bin/rails", "c", host: host end - def bash(host: config.primary_host) + def bash(host:) exec_over_ssh "bash", host: host end diff --git a/lib/mrsk/configuration.rb b/lib/mrsk/configuration.rb index 5891fb6d..40c50fe1 100644 --- a/lib/mrsk/configuration.rb +++ b/lib/mrsk/configuration.rb @@ -52,7 +52,7 @@ class Mrsk::Configuration roles.flat_map(&:hosts) end - def primary_host + def primary_web_host role(:web).hosts.first end @@ -101,8 +101,8 @@ class Mrsk::Configuration def to_h { roles: role_names, - hosts: hosts, - primary_host: primary_host, + hosts: all_hosts, + primary_host: primary_web_host, version: version, repository: repository, absolute_image: absolute_image, diff --git a/test/commander_test.rb b/test/commander_test.rb index 558611c9..5b3ed297 100644 --- a/test/commander_test.rb +++ b/test/commander_test.rb @@ -13,17 +13,24 @@ class CommanderTest < ActiveSupport::TestCase test "overwriting hosts" do assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @mrsk.hosts - @mrsk.hosts = [ "1.2.3.4", "1.2.3.5" ] + @mrsk.specific_hosts = [ "1.2.3.4", "1.2.3.5" ] assert_equal [ "1.2.3.4", "1.2.3.5" ], @mrsk.hosts end test "overwriting hosts with roles" do assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @mrsk.hosts - @mrsk.roles = [ "workers", "web" ] + @mrsk.specific_roles = [ "workers", "web" ] assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @mrsk.hosts - @mrsk.roles = [ "workers" ] + @mrsk.specific_roles = [ "workers" ] assert_equal [ "1.1.1.3", "1.1.1.4" ], @mrsk.hosts end + + test "overwriting hosts with primary" do + assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @mrsk.hosts + + @mrsk.specific_primary! + assert_equal [ "1.1.1.1" ], @mrsk.hosts + end end diff --git a/test/configuration_test.rb b/test/configuration_test.rb index d6ea9c5d..b61df46c 100644 --- a/test/configuration_test.rb +++ b/test/configuration_test.rb @@ -48,9 +48,9 @@ class ConfigurationTest < ActiveSupport::TestCase assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @config_with_roles.all_hosts end - test "primary host" do - assert_equal "1.1.1.1", @config.primary_host - assert_equal "1.1.1.1", @config_with_roles.primary_host + test "primary web host" do + assert_equal "1.1.1.1", @config.primary_web_host + assert_equal "1.1.1.1", @config_with_roles.primary_web_host end test "traefik hosts" do @@ -123,4 +123,8 @@ class ConfigurationTest < ActiveSupport::TestCase config = Mrsk::Configuration.create_from dest_config_file, destination: "missing" end end + + test "to_h" do + assert_equal({ :roles=>["web"], :hosts=>["1.1.1.1", "1.1.1.2"], :primary_host=>"1.1.1.1", :version=>"123", :repository=>"dhh/app", :absolute_image=>"dhh/app:123", :service_with_version=>"app-123", :env_args=>["-e", "REDIS_URL=redis://x/y"], :ssh_options=>{:user=>"root", :auth_methods=>["publickey"]} }, @config.to_h) + end end