Switch to a Commander base to allow lazy loading config
This commit is contained in:
@@ -3,6 +3,4 @@ end
|
|||||||
|
|
||||||
require "mrsk/version"
|
require "mrsk/version"
|
||||||
require "mrsk/engine"
|
require "mrsk/engine"
|
||||||
|
require "mrsk/commander"
|
||||||
require "mrsk/configuration"
|
|
||||||
require "mrsk/commands"
|
|
||||||
|
|||||||
45
lib/mrsk/commander.rb
Normal file
45
lib/mrsk/commander.rb
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
require "mrsk/configuration"
|
||||||
|
require "mrsk/commands/app"
|
||||||
|
require "mrsk/commands/prune"
|
||||||
|
require "mrsk/commands/traefik"
|
||||||
|
require "mrsk/commands/registry"
|
||||||
|
|
||||||
|
class Mrsk::Commander
|
||||||
|
attr_reader :config_file, :config, :verbose
|
||||||
|
|
||||||
|
def initialize(config_file:, verbose: false)
|
||||||
|
@config_file, @verbose = config_file, verbose
|
||||||
|
end
|
||||||
|
|
||||||
|
def config
|
||||||
|
@config ||= Mrsk::Configuration.load_file(config_file).tap { |config| setup_with(config) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def app
|
||||||
|
@app ||= Mrsk::Commands::App.new(config)
|
||||||
|
end
|
||||||
|
|
||||||
|
def traefik
|
||||||
|
@traefik ||= Mrsk::Commands::Traefik.new(config)
|
||||||
|
end
|
||||||
|
|
||||||
|
def registry
|
||||||
|
@registry ||= Mrsk::Commands::Registry.new(config)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verbosity(level)
|
||||||
|
old_level = SSHKit.config.output_verbosity
|
||||||
|
SSHKit.config.output_verbosity = level
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
SSHKit.config.output_verbosity = old_level
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# Lazy setup of SSHKit
|
||||||
|
def setup_with(config)
|
||||||
|
SSHKit::Backend::Netssh.configure { |ssh| ssh.ssh_options = config.ssh_options }
|
||||||
|
SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs
|
||||||
|
SSHKit.config.output_verbosity = :debug if verbose
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
require_relative "setup"
|
require_relative "setup"
|
||||||
|
|
||||||
app = Mrsk::Commands::App.new(MRSK_CONFIG)
|
|
||||||
|
|
||||||
namespace :mrsk do
|
namespace :mrsk do
|
||||||
namespace :app do
|
namespace :app do
|
||||||
desc "Deliver a newly built app image to servers"
|
desc "Deliver a newly built app image to servers"
|
||||||
@@ -12,30 +10,30 @@ namespace :mrsk do
|
|||||||
run_locally do
|
run_locally do
|
||||||
begin
|
begin
|
||||||
info "Building multi-architecture images may take a while (run with VERBOSE=1 for progress logging)"
|
info "Building multi-architecture images may take a while (run with VERBOSE=1 for progress logging)"
|
||||||
execute *app.push
|
execute *MRSK.app.push
|
||||||
rescue SSHKit::Command::Failed => e
|
rescue SSHKit::Command::Failed => e
|
||||||
error "Missing compatible buildx builder, so creating a new one first"
|
error "Missing compatible buildx builder, so creating a new one first"
|
||||||
execute *app.create_new_builder
|
execute *MRSK.app.create_new_builder
|
||||||
execute *app.push
|
execute *MRSK.app.push
|
||||||
end
|
end
|
||||||
end unless ENV["VERSION"]
|
end unless ENV["VERSION"]
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Pull app image from the registry onto servers"
|
desc "Pull app image from the registry onto servers"
|
||||||
task :pull do
|
task :pull do
|
||||||
on(MRSK_CONFIG.hosts) { execute *app.pull }
|
on(MRSK.config.hosts) { execute *MRSK.app.pull }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Run app on servers (or start them if they've already been run)"
|
desc "Run app on servers (or start them if they've already been run)"
|
||||||
task :run do
|
task :run do
|
||||||
MRSK_CONFIG.roles.each do |role|
|
MRSK.config.roles.each do |role|
|
||||||
on(role.hosts) do |host|
|
on(role.hosts) do |host|
|
||||||
begin
|
begin
|
||||||
execute *app.run(role: role.name)
|
execute *MRSK.app.run(role: role.name)
|
||||||
rescue SSHKit::Command::Failed => e
|
rescue SSHKit::Command::Failed => e
|
||||||
if e.message =~ /already in use/
|
if e.message =~ /already in use/
|
||||||
error "Container with same version already deployed on #{host}, starting that instead"
|
error "Container with same version already deployed on #{host}, starting that instead"
|
||||||
execute *app.start, host: host
|
execute *MRSK.app.start, host: host
|
||||||
else
|
else
|
||||||
raise
|
raise
|
||||||
end
|
end
|
||||||
@@ -46,12 +44,12 @@ namespace :mrsk do
|
|||||||
|
|
||||||
desc "Start existing app on servers (use VERSION=<git-hash> to designate which version)"
|
desc "Start existing app on servers (use VERSION=<git-hash> to designate which version)"
|
||||||
task :start do
|
task :start do
|
||||||
on(MRSK_CONFIG.hosts) { execute *app.start, raise_on_non_zero_exit: false }
|
on(MRSK.config.hosts) { execute *MRSK.app.start, raise_on_non_zero_exit: false }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Stop app on servers"
|
desc "Stop app on servers"
|
||||||
task :stop do
|
task :stop do
|
||||||
on(MRSK_CONFIG.hosts) { execute *app.stop, raise_on_non_zero_exit: false }
|
on(MRSK.config.hosts) { execute *MRSK.app.stop, raise_on_non_zero_exit: false }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Start app on servers (use VERSION=<git-hash> to designate which version)"
|
desc "Start app on servers (use VERSION=<git-hash> to designate which version)"
|
||||||
@@ -59,54 +57,54 @@ namespace :mrsk do
|
|||||||
|
|
||||||
desc "Display information about app containers"
|
desc "Display information about app containers"
|
||||||
task :info do
|
task :info do
|
||||||
on(MRSK_CONFIG.hosts) { |host| puts "App Host: #{host}\n" + capture(*app.info) + "\n\n" }
|
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.info) + "\n\n" }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Execute a custom task on servers passed in as CMD='bin/rake some:task'"
|
desc "Execute a custom task on servers passed in as CMD='bin/rake some:task'"
|
||||||
task :exec do
|
task :exec do
|
||||||
on(MRSK_CONFIG.hosts) { |host| puts "App Host: #{host}\n" + capture(*app.exec(ENV["CMD"])) + "\n\n" }
|
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec(ENV["CMD"])) + "\n\n" }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Start Rails Console on primary host"
|
desc "Start Rails Console on primary host"
|
||||||
task :console do
|
task :console do
|
||||||
puts "Launching Rails console on #{MRSK_CONFIG.primary_host}..."
|
puts "Launching Rails console on #{MRSK.config.primary_host}..."
|
||||||
exec app.console
|
exec app.console
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :exec do
|
namespace :exec do
|
||||||
desc "Execute Rails command on servers, like CMD='runner \"puts %(Hello World)\""
|
desc "Execute Rails command on servers, like CMD='runner \"puts %(Hello World)\""
|
||||||
task :rails do
|
task :rails do
|
||||||
on(MRSK_CONFIG.hosts) { |host| puts "App Host: #{host}\n" + capture(*app.exec("bin/rails", ENV["CMD"])) + "\n\n" }
|
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec("bin/rails", ENV["CMD"])) + "\n\n" }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Execute a custom task on the first defined server"
|
desc "Execute a custom task on the first defined server"
|
||||||
task :once do
|
task :once do
|
||||||
on(MRSK_CONFIG.primary_host) { puts capture(*app.exec(ENV["CMD"])) }
|
on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec(ENV["CMD"])) }
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :once do
|
namespace :once do
|
||||||
desc "Execute Rails command on the first defined server, like CMD='runner \"puts %(Hello World)\""
|
desc "Execute Rails command on the first defined server, like CMD='runner \"puts %(Hello World)\""
|
||||||
task :rails do
|
task :rails do
|
||||||
on(MRSK_CONFIG.primary_host) { puts capture(*app.exec("bin/rails", ENV["CMD"])) }
|
on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec("bin/rails", ENV["CMD"])) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "List all the app containers currently on servers"
|
desc "List all the app containers currently on servers"
|
||||||
task :containers do
|
task :containers do
|
||||||
on(MRSK_CONFIG.hosts) { |host| puts "App Host: #{host}\n" + capture(*app.list_containers) + "\n\n" }
|
on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.list_containers) + "\n\n" }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Tail logs from app containers"
|
desc "Tail logs from app containers"
|
||||||
task :logs do
|
task :logs do
|
||||||
on(MRSK_CONFIG.hosts) { execute *app.logs }
|
on(MRSK.config.hosts) { execute *MRSK.app.logs }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Remove app containers and images from servers"
|
desc "Remove app containers and images from servers"
|
||||||
task remove: %i[ stop ] do
|
task remove: %i[ stop ] do
|
||||||
on(MRSK_CONFIG.hosts) do
|
on(MRSK.config.hosts) do
|
||||||
execute *app.remove_containers
|
execute *MRSK.app.remove_containers
|
||||||
execute *app.remove_images
|
execute *MRSK.app.remove_images
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
require_relative "setup"
|
require_relative "setup"
|
||||||
|
|
||||||
prune = Mrsk::Commands::Prune.new(MRSK_CONFIG)
|
|
||||||
|
|
||||||
namespace :mrsk do
|
namespace :mrsk do
|
||||||
desc "Prune unused images and stopped containers"
|
desc "Prune unused images and stopped containers"
|
||||||
task prune: %w[ prune:containers prune:images ]
|
task prune: %w[ prune:containers prune:images ]
|
||||||
@@ -9,12 +7,12 @@ namespace :mrsk do
|
|||||||
namespace :prune do
|
namespace :prune do
|
||||||
desc "Prune unused images older than 30 days"
|
desc "Prune unused images older than 30 days"
|
||||||
task :images do
|
task :images do
|
||||||
on(MRSK_CONFIG.hosts) { verbosity(:debug) { execute *prune.images } }
|
on(MRSK.config.hosts) { MRSK.verbosity(:debug) { execute *MRSK.prune.images } }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Prune stopped containers for the service older than 3 days"
|
desc "Prune stopped containers for the service older than 3 days"
|
||||||
task :containers do
|
task :containers do
|
||||||
on(MRSK_CONFIG.hosts) { verbosity(:debug) { execute *prune.containers } }
|
on(MRSK.config.hosts) { MRSK.verbosity(:debug) { execute *MRSK.prune.containers } }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
require_relative "setup"
|
require_relative "setup"
|
||||||
|
|
||||||
registry = Mrsk::Commands::Registry.new(MRSK_CONFIG)
|
|
||||||
|
|
||||||
namespace :mrsk do
|
namespace :mrsk do
|
||||||
namespace :registry do
|
namespace :registry do
|
||||||
desc "Login to the registry locally and remotely"
|
desc "Login to the registry locally and remotely"
|
||||||
task :login do
|
task :login do
|
||||||
run_locally { execute *registry.login }
|
run_locally { execute *MRSK.registry.login }
|
||||||
on(MRSK_CONFIG.hosts) { execute *registry.login }
|
on(MRSK.config.hosts) { execute *MRSK.registry.login }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Logout of the registry remotely"
|
desc "Logout of the registry remotely"
|
||||||
task :logout do
|
task :logout do
|
||||||
on(MRSK_CONFIG.hosts) { execute *registry.logout }
|
on(MRSK.config.hosts) { execute *MRSK.registry.logout }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace :mrsk do
|
|||||||
desc "Setup Docker on the remote servers"
|
desc "Setup Docker on the remote servers"
|
||||||
task :bootstrap do
|
task :bootstrap do
|
||||||
# FIXME: Detect when apt-get is not available and use the appropriate alternative
|
# FIXME: Detect when apt-get is not available and use the appropriate alternative
|
||||||
on(MRSK_CONFIG.hosts) { execute "apt-get install docker.io -y" }
|
on(MRSK.config.hosts) { execute "apt-get install docker.io -y" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,26 +3,4 @@ require "sshkit/dsl"
|
|||||||
|
|
||||||
include SSHKit::DSL
|
include SSHKit::DSL
|
||||||
|
|
||||||
if (config_file = Rails.root.join("config/deploy.yml")).exist?
|
MRSK = Mrsk::Commander.new config_file: Rails.root.join("config/deploy.yml"), verbose: ENV["VERBOSE"]
|
||||||
MRSK_CONFIG = Mrsk::Configuration.load_file(config_file)
|
|
||||||
|
|
||||||
SSHKit::Backend::Netssh.configure { |ssh| ssh.ssh_options = MRSK_CONFIG.ssh_options }
|
|
||||||
|
|
||||||
# No need to use /usr/bin/env, just clogs up the logs
|
|
||||||
SSHKit.config.command_map[:docker] = "docker"
|
|
||||||
else
|
|
||||||
# MRSK is missing config/deploy.yml – run 'rake mrsk:init'
|
|
||||||
MRSK_CONFIG = Mrsk::Configuration.new({}, validate: false)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Allow easy full verbosity mode
|
|
||||||
SSHKit.config.output_verbosity = :debug if ENV["VERBOSE"]
|
|
||||||
|
|
||||||
# Set a different verbosity level for the duration of the yield
|
|
||||||
def verbosity(level)
|
|
||||||
old_level = SSHKit.config.output_verbosity
|
|
||||||
SSHKit.config.output_verbosity = level
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
SSHKit.config.output_verbosity = old_level
|
|
||||||
end
|
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
require_relative "setup"
|
require_relative "setup"
|
||||||
|
|
||||||
traefik = Mrsk::Commands::Traefik.new(MRSK_CONFIG)
|
|
||||||
|
|
||||||
namespace :mrsk do
|
namespace :mrsk do
|
||||||
namespace :traefik do
|
namespace :traefik do
|
||||||
desc "Run Traefik on servers"
|
desc "Run Traefik on servers"
|
||||||
task :run do
|
task :run do
|
||||||
on(MRSK_CONFIG.role(:web).hosts) { execute *traefik.run, raise_on_non_zero_exit: false }
|
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.run, raise_on_non_zero_exit: false }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Start existing Traefik on servers"
|
desc "Start existing Traefik on servers"
|
||||||
task :start do
|
task :start do
|
||||||
on(MRSK_CONFIG.role(:web).hosts) { execute *traefik.start, raise_on_non_zero_exit: false }
|
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.start, raise_on_non_zero_exit: false }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Stop Traefik on servers"
|
desc "Stop Traefik on servers"
|
||||||
task :stop do
|
task :stop do
|
||||||
on(MRSK_CONFIG.role(:web).hosts) { execute *traefik.stop, raise_on_non_zero_exit: false }
|
on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.stop, raise_on_non_zero_exit: false }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Restart Traefik on servers"
|
desc "Restart Traefik on servers"
|
||||||
@@ -24,14 +22,14 @@ namespace :mrsk do
|
|||||||
|
|
||||||
desc "Display information about Traefik containers from servers"
|
desc "Display information about Traefik containers from servers"
|
||||||
task :info do
|
task :info do
|
||||||
on(MRSK_CONFIG.role(:web).hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*traefik.info) + "\n\n" }
|
on(MRSK.config.role(:web).hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.info) + "\n\n" }
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Remove Traefik container and image from servers"
|
desc "Remove Traefik container and image from servers"
|
||||||
task remove: %i[ stop ] do
|
task remove: %i[ stop ] do
|
||||||
on(MRSK_CONFIG.role(:web).hosts) do
|
on(MRSK.config.role(:web).hosts) do
|
||||||
execute *traefik.remove_container
|
execute *MRSK.traefik.remove_container
|
||||||
execute *traefik.remove_image
|
execute *MRSK.traefik.remove_image
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
require "test_helper"
|
require "test_helper"
|
||||||
require "mrsk/configuration"
|
require "mrsk/configuration"
|
||||||
require "mrsk/commands"
|
require "mrsk/commands/app"
|
||||||
|
|
||||||
ENV["VERSION"] = "123"
|
ENV["VERSION"] = "123"
|
||||||
ENV["RAILS_MASTER_KEY"] = "456"
|
ENV["RAILS_MASTER_KEY"] = "456"
|
||||||
|
|||||||
12
test/commander_test.rb
Normal file
12
test/commander_test.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
require "test_helper"
|
||||||
|
require "mrsk/commander"
|
||||||
|
|
||||||
|
class CommanderTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@mrsk = Mrsk::Commander.new config_file: Pathname.new(File.expand_path("fixtures/deploy.erb.yml", __dir__))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "lazy configuration" do
|
||||||
|
assert_equal Mrsk::Configuration, @mrsk.config.class
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user