From fed64ef244e64fe6b5e9353724263d024a11373b Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 14 Jan 2023 11:31:37 +0100 Subject: [PATCH] Switch to proper standalone executable with Thor --- Gemfile | 1 + Gemfile.lock | 10 +- bin/mrsk | 5 + lib/mrsk.rb | 1 - lib/mrsk/cli.rb | 9 ++ lib/mrsk/cli/app.rb | 98 +++++++++++++++++++ lib/mrsk/cli/base.rb | 27 +++++ lib/mrsk/cli/build.rb | 53 ++++++++++ lib/mrsk/cli/main.rb | 87 ++++++++++++++++ lib/mrsk/cli/prune.rb | 19 ++++ lib/mrsk/cli/registry.rb | 14 +++ lib/mrsk/cli/server.rb | 8 ++ .../mrsk => mrsk/cli}/templates/deploy.yml | 4 +- lib/mrsk/cli/traefik.rb | 44 +++++++++ lib/mrsk/commander.rb | 9 +- lib/mrsk/commands/app.rb | 8 +- lib/mrsk/configuration.rb | 4 +- lib/mrsk/engine.rb | 4 - lib/tasks/mrsk/app.rake | 97 ------------------ lib/tasks/mrsk/build.rake | 52 ---------- lib/tasks/mrsk/mrsk.rake | 37 ------- lib/tasks/mrsk/prune.rake | 18 ---- lib/tasks/mrsk/registry.rake | 16 --- lib/tasks/mrsk/server.rake | 10 -- lib/tasks/mrsk/setup.rb | 6 -- lib/tasks/mrsk/templates/mrsk | 8 -- lib/tasks/mrsk/traefik.rake | 41 -------- mrsk.gemspec | 4 +- 28 files changed, 387 insertions(+), 307 deletions(-) create mode 100755 bin/mrsk create mode 100644 lib/mrsk/cli.rb create mode 100644 lib/mrsk/cli/app.rb create mode 100644 lib/mrsk/cli/base.rb create mode 100644 lib/mrsk/cli/build.rb create mode 100644 lib/mrsk/cli/main.rb create mode 100644 lib/mrsk/cli/prune.rb create mode 100644 lib/mrsk/cli/registry.rb create mode 100644 lib/mrsk/cli/server.rb rename lib/{tasks/mrsk => mrsk/cli}/templates/deploy.yml (88%) create mode 100644 lib/mrsk/cli/traefik.rb delete mode 100755 lib/mrsk/engine.rb delete mode 100644 lib/tasks/mrsk/app.rake delete mode 100644 lib/tasks/mrsk/build.rake delete mode 100644 lib/tasks/mrsk/mrsk.rake delete mode 100644 lib/tasks/mrsk/prune.rake delete mode 100644 lib/tasks/mrsk/registry.rake delete mode 100644 lib/tasks/mrsk/server.rake delete mode 100644 lib/tasks/mrsk/setup.rb delete mode 100755 lib/tasks/mrsk/templates/mrsk delete mode 100644 lib/tasks/mrsk/traefik.rake diff --git a/Gemfile b/Gemfile index ceed4117..8e9e4f6e 100644 --- a/Gemfile +++ b/Gemfile @@ -4,3 +4,4 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } gemspec gem "debug" +gem "railties" diff --git a/Gemfile.lock b/Gemfile.lock index 46ad7d25..55c75b0a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,8 +2,9 @@ PATH remote: . specs: mrsk (0.0.3) - railties (>= 7.0.0) + activesupport (>= 7.0) sshkit (~> 1.21) + thor (~> 1.2) GEM remote: https://rubygems.org/ @@ -46,11 +47,11 @@ GEM net-scp (4.0.0) net-ssh (>= 2.6.5, < 8.0.0) net-ssh (7.0.1) - nokogiri (1.14.0.rc1-arm64-darwin) + nokogiri (1.14.0-arm64-darwin) racc (~> 1.4) - nokogiri (1.14.0.rc1-x86_64-darwin) + nokogiri (1.14.0-x86_64-darwin) racc (~> 1.4) - nokogiri (1.14.0.rc1-x86_64-linux) + nokogiri (1.14.0-x86_64-linux) racc (~> 1.4) racc (1.6.2) rack (2.2.5) @@ -90,6 +91,7 @@ PLATFORMS DEPENDENCIES debug mrsk! + railties BUNDLED WITH 2.4.3 diff --git a/bin/mrsk b/bin/mrsk new file mode 100755 index 00000000..11341e9b --- /dev/null +++ b/bin/mrsk @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require "mrsk/cli" + +Mrsk::Cli::Main.start(ARGV) diff --git a/lib/mrsk.rb b/lib/mrsk.rb index af755fc7..3adf2bef 100644 --- a/lib/mrsk.rb +++ b/lib/mrsk.rb @@ -2,5 +2,4 @@ module Mrsk end require "mrsk/version" -require "mrsk/engine" require "mrsk/commander" diff --git a/lib/mrsk/cli.rb b/lib/mrsk/cli.rb new file mode 100644 index 00000000..5413e350 --- /dev/null +++ b/lib/mrsk/cli.rb @@ -0,0 +1,9 @@ +require "mrsk" + +MRSK = Mrsk::Commander.new \ + config_file: Pathname.new(File.expand_path("config/deploy.yml")) + +module Mrsk::Cli +end + +require "mrsk/cli/main" diff --git a/lib/mrsk/cli/app.rb b/lib/mrsk/cli/app.rb new file mode 100644 index 00000000..d374fcfd --- /dev/null +++ b/lib/mrsk/cli/app.rb @@ -0,0 +1,98 @@ +require "mrsk/cli/base" + +class Mrsk::Cli::App < Mrsk::Cli::Base + desc "boot", "Boot app on servers (or start them if they've already been booted)" + def boot + MRSK.config.roles.each do |role| + on(role.hosts) do |host| + begin + execute *MRSK.app.run(role: role.name) + rescue SSHKit::Command::Failed => e + if e.message =~ /already in use/ + error "Container with same version already deployed on #{host}, starting that instead" + execute *MRSK.app.start, host: host + else + raise + end + end + end + end + end + + desc "start", "Start existing app on servers (use --version= to designate specific version)" + option :version, desc: "Defaults to the most recent git-hash in local repository" + def start + if (version = options[:version]).present? + on(MRSK.config.hosts) { execute *MRSK.app.start(version: version), raise_on_non_zero_exit: false } + else + on(MRSK.config.hosts) { execute *MRSK.app.start, raise_on_non_zero_exit: false } + end + end + + desc "stop", "Stop app on servers" + def stop + on(MRSK.config.hosts) { execute *MRSK.app.stop, raise_on_non_zero_exit: false } + end + + desc "restart", "Start app on servers (use VERSION= to designate which version)" + def restart + invoke :stop + invoke :start + end + + desc "details", "Display details about app containers" + def details + on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.info, verbosity: Logger::INFO) + "\n\n" } + end + + desc "exec [CMD]", "Execute a custom task on servers passed in as CMD='bin/rake some:task'" + option :once, type: :boolean, default: false + def exec(cmd) + if options[:once] + on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec(cmd), verbosity: Logger::INFO) } + else + on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec(cmd), verbosity: Logger::INFO) + "\n\n" } + end + end + + desc "console [HOST]", "Start Rails Console on primary host (or designated HOST)" + def console(host = MRSK.config.primary_host) + puts "Launching Rails console on #{host}..." + exec MRSK.app.console(host: host) + end + + desc "runner [EXPRESSION]", "Execute Rails runner with given expression" + option :once, type: :boolean, default: false, desc: + def runner(expression) + if options[:once] + on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec("bin/rails", "runner", "'#{expression}'"), verbosity: Logger::INFO) } + else + on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec("bin/rails", "runner", "'#{expression}'"), verbosity: Logger::INFO) + "\n\n" } + end + end + + desc "containers", "List all the app containers currently on servers" + def containers + on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.list_containers) + "\n\n" } + end + + desc "logs", "Show last 100 log lines from app on servers" + def logs + # FIXME: Catch when app containers aren't running + on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.logs) + "\n\n" } + end + + desc "remove", "Remove app containers and images from servers" + option :only, default: "", desc: "Use 'containers' or 'images'" + def remove + case options[:only] + when "containers" + on(MRSK.config.hosts) { execute *MRSK.app.remove_containers } + when "images" + on(MRSK.config.hosts) { execute *MRSK.app.remove_images } + else + on(MRSK.config.hosts) { execute *MRSK.app.remove_containers } + on(MRSK.config.hosts) { execute *MRSK.app.remove_images } + end + end +end diff --git a/lib/mrsk/cli/base.rb b/lib/mrsk/cli/base.rb new file mode 100644 index 00000000..a2821915 --- /dev/null +++ b/lib/mrsk/cli/base.rb @@ -0,0 +1,27 @@ +require "thor" +require "sshkit" +require "sshkit/dsl" + +module Mrsk::Cli + class Base < Thor + include SSHKit::DSL + + def self.exit_on_failure?() true end + + class_option :verbose, type: :boolean, aliases: "-v", desc: "Detailed logging" + + def initialize(*) + super + MRSK.verbose = options[:verbose] + end + + private + def print_runtime + started_at = Time.now + yield + ensure + runtime = Time.now - started_at + puts " Finished all in #{sprintf("%.1f seconds", runtime)}" + end + end +end diff --git a/lib/mrsk/cli/build.rb b/lib/mrsk/cli/build.rb new file mode 100644 index 00000000..715574d1 --- /dev/null +++ b/lib/mrsk/cli/build.rb @@ -0,0 +1,53 @@ +require "mrsk/cli/base" + +class Mrsk::Cli::Build < Mrsk::Cli::Base + desc "deliver", "Deliver a newly built app image to servers" + def deliver + invoke :push + invoke :pull + end + + desc "push", "Build locally and push app image to registry" + def push + run_locally do + begin + debug "Using builder: #{MRSK.builder.name}" + info "Building image may take a while (run with --verbose for progress logging)" + execute *MRSK.builder.push + rescue SSHKit::Command::Failed => e + error "Missing compatible builder, so creating a new one first" + execute *MRSK.builder.create + execute *MRSK.builder.push + end + end + end + + desc "pull", "Pull app image from the registry onto servers" + def pull + on(MRSK.config.hosts) { execute *MRSK.builder.pull } + end + + desc "create", "Create a local build setup" + def create + run_locally do + debug "Using builder: #{MRSK.builder.name}" + execute *MRSK.builder.create + end + end + + desc "remove", "Remove local build setup" + def remove + run_locally do + debug "Using builder: #{MRSK.builder.name}" + execute *MRSK.builder.remove + end + end + + desc "details", "Show the name of the configured builder" + def details + run_locally do + puts "Builder: #{MRSK.builder.name} (#{MRSK.builder.target.class.name})" + puts capture(*MRSK.builder.info) + end + end +end diff --git a/lib/mrsk/cli/main.rb b/lib/mrsk/cli/main.rb new file mode 100644 index 00000000..607c5fca --- /dev/null +++ b/lib/mrsk/cli/main.rb @@ -0,0 +1,87 @@ +require "mrsk/cli/base" + +require "mrsk/cli/app" +require "mrsk/cli/build" +require "mrsk/cli/prune" +require "mrsk/cli/registry" +require "mrsk/cli/server" +require "mrsk/cli/traefik" + +class Mrsk::Cli::Main < Mrsk::Cli::Base + desc "ship", "Ship the app to servers" + def ship + print_runtime do + invoke "mrsk:cli:server:bootstrap" + invoke "mrsk:cli:registry:login" + invoke "mrsk:cli:build:deliver" + invoke "mrsk:cli:traefik:boot" + invoke "mrsk:cli:app:stop" + invoke "mrsk:cli:app:boot" + invoke "mrsk:cli:prune:all" + end + end + + desc "reship", "Ship new version of the app to servers (without bootstrapping servers, starting Traefik, pruning, and registry login)" + def reship + print_runtime do + invoke "mrsk:cli:build:deliver" + invoke "mrsk:cli:app:stop" + invoke "mrsk:cli:app:boot" + end + end + + desc "rollback [VERSION]", "Rollback the app to VERSION (that must already be on servers)" + def rollback(version) + invoke "mrsk:cli:app:restart" + end + + desc "details", "Display details about Traefik and app containers" + def details + invoke "mrsk:cli:traefik:details" + invoke "mrsk:cli:app:details" + end + + desc "install", "Create config stub in config/deploy.yml and binstub in bin/mrsk" + def install + require "fileutils" + + if (deploy_file = Pathname.new(File.expand_path("config/deploy.yml"))).exist? + puts "Config file already exists in config/deploy.yml (remove first to create a new one)" + else + FileUtils.cp_r Pathname.new(File.expand_path("templates/deploy.yml", __dir__)), deploy_file + puts "Created configuration file in config/deploy.yml" + end + + if (binstub = Pathname.new(File.expand_path("bin/mrsk"))).exist? + puts "Binstub already exists in bin/mrsk (remove first to create a new one)" + else + `bundle binstubs mrsk` + puts "Created binstub file in bin/mrsk" + end + end + + desc "remove", "Remove Traefik, app, and registry session from servers" + def remove + invoke "mrsk:cli:traefik:remove" + invoke "mrsk:cli:app:remove" + invoke "mrsk:cli:registry:logout" + end + + desc "app", "Manage the application" + subcommand "app", Mrsk::Cli::App + + desc "build", "Build the application image" + subcommand "build", Mrsk::Cli::Build + + desc "prune", "Prune old application images and containers" + subcommand "prune", Mrsk::Cli::Prune + + desc "registry", "Login and out of the image registry" + subcommand "registry", Mrsk::Cli::Registry + + desc "server", "Bootstrap servers with Docker" + subcommand "server", Mrsk::Cli::Server + + desc "traefik", "Manage the Traefik load balancer" + subcommand "traefik", Mrsk::Cli::Traefik +end diff --git a/lib/mrsk/cli/prune.rb b/lib/mrsk/cli/prune.rb new file mode 100644 index 00000000..9dea45e6 --- /dev/null +++ b/lib/mrsk/cli/prune.rb @@ -0,0 +1,19 @@ +require "mrsk/cli/base" + +class Mrsk::Cli::Prune < Mrsk::Cli::Base + desc "all", "Prune unused images and stopped containers" + def all + invoke :containers + invoke :images + end + + desc "images", "Prune unused images older than 30 days" + def images + on(MRSK.config.hosts) { execute *MRSK.prune.images } + end + + desc "containers", "Prune stopped containers for the service older than 3 days" + def containers + on(MRSK.config.hosts) { execute *MRSK.prune.containers } + end +end diff --git a/lib/mrsk/cli/registry.rb b/lib/mrsk/cli/registry.rb new file mode 100644 index 00000000..716e5f5e --- /dev/null +++ b/lib/mrsk/cli/registry.rb @@ -0,0 +1,14 @@ +require "mrsk/cli/base" + +class Mrsk::Cli::Registry < Mrsk::Cli::Base + desc "login", "Login to the registry locally and remotely" + def login + run_locally { execute *MRSK.registry.login } + on(MRSK.config.hosts) { execute *MRSK.registry.login } + end + + desc "logout", "Logout of the registry remotely" + def logout + on(MRSK.config.hosts) { execute *MRSK.registry.logout } + end +end diff --git a/lib/mrsk/cli/server.rb b/lib/mrsk/cli/server.rb new file mode 100644 index 00000000..9121d63e --- /dev/null +++ b/lib/mrsk/cli/server.rb @@ -0,0 +1,8 @@ +require "mrsk/cli/base" + +class Mrsk::Cli::Server < Mrsk::Cli::Base + desc "bootstrap", "Ensure Docker is installed on the servers" + def bootstrap + on(MRSK.config.hosts) { execute "which docker || apt-get install docker.io -y" } + end +end diff --git a/lib/tasks/mrsk/templates/deploy.yml b/lib/mrsk/cli/templates/deploy.yml similarity index 88% rename from lib/tasks/mrsk/templates/deploy.yml rename to lib/mrsk/cli/templates/deploy.yml index 23ebb91c..1c813442 100644 --- a/lib/tasks/mrsk/templates/deploy.yml +++ b/lib/mrsk/cli/templates/deploy.yml @@ -18,7 +18,5 @@ env: registry: # Specify the registry server, if you're not using Docker Hub # server: registry.digitalocean.com / ghcr.io / ... - - # Set credentials with bin/rails credentials:edit username: my-user - password: my-password-should-go-in-credentials + password: my-password-should-go-somewhere-safe diff --git a/lib/mrsk/cli/traefik.rb b/lib/mrsk/cli/traefik.rb new file mode 100644 index 00000000..658ef7dc --- /dev/null +++ b/lib/mrsk/cli/traefik.rb @@ -0,0 +1,44 @@ +require "mrsk/cli/base" + +class Mrsk::Cli::Traefik < Mrsk::Cli::Base + desc "boot", "Boot Traefik on servers" + def boot + on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.run, raise_on_non_zero_exit: false } + end + + desc "start", "Start existing Traefik on servers" + def start + on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.start, raise_on_non_zero_exit: false } + end + + desc "stop", "Stop Traefik on servers" + def stop + on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.stop, raise_on_non_zero_exit: false } + end + + desc "restart", "Restart Traefik on servers" + def restart + invoke :stop + invoke :start + end + + desc "details", "Display details about Traefik containers from servers" + def details + on(MRSK.config.role(:web).hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.info) + "\n\n" } + end + + desc "logs", "Show last 100 log lines from Traefik on servers" + def logs + on(MRSK.config.hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.logs) + "\n\n" } + end + + desc "remove", "Remove Traefik container and image from servers" + def remove + invoke :stop + + on(MRSK.config.role(:web).hosts) do + execute *MRSK.traefik.remove_container + execute *MRSK.traefik.remove_image + end + end +end diff --git a/lib/mrsk/commander.rb b/lib/mrsk/commander.rb index e6cffd9b..26c87b5d 100644 --- a/lib/mrsk/commander.rb +++ b/lib/mrsk/commander.rb @@ -6,14 +6,15 @@ require "mrsk/commands/traefik" require "mrsk/commands/registry" class Mrsk::Commander - attr_reader :config_file, :config, :verbose + attr_reader :config + attr_accessor :verbose - def initialize(config_file:, verbose: false) - @config_file, @verbose = config_file, verbose + def initialize(config_file:) + @config_file = config_file end def config - @config ||= Mrsk::Configuration.load_file(config_file).tap { |config| setup_with(config) } + @config ||= Mrsk::Configuration.load_file(@config_file).tap { |config| setup_with(config) } end diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index 7e613507..42245ddd 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -15,8 +15,8 @@ class Mrsk::Commands::App < Mrsk::Commands::Base role.cmd end - def start - docker :start, config.service_with_version + def start(version: config.version) + docker :start, "#{config.service}-#{version}" end def stop @@ -40,8 +40,8 @@ class Mrsk::Commands::App < Mrsk::Commands::Base *command end - def console - "ssh -t #{config.ssh_user}@#{config.primary_host} '#{exec("bin/rails", "c", interactive: true).join(" ")}'" + def console(host: config.primary_host) + "ssh -t #{config.ssh_user}@#{host} '#{exec("bin/rails", "c", interactive: true).join(" ")}'" end def list_containers diff --git a/lib/mrsk/configuration.rb b/lib/mrsk/configuration.rb index a0e33d73..8c19808a 100644 --- a/lib/mrsk/configuration.rb +++ b/lib/mrsk/configuration.rb @@ -1,5 +1,7 @@ require "active_support/ordered_options" require "active_support/core_ext/string/inquiry" +require "active_support/core_ext/module/delegation" +require "pathname" require "erb" class Mrsk::Configuration @@ -91,7 +93,7 @@ class Mrsk::Configuration end def master_key - ENV["RAILS_MASTER_KEY"] || File.read(Rails.root.join("config/master.key")) + ENV["RAILS_MASTER_KEY"] || File.read(Pathname.new(File.expand_path("config/master.key"))) end diff --git a/lib/mrsk/engine.rb b/lib/mrsk/engine.rb deleted file mode 100755 index 87f2d298..00000000 --- a/lib/mrsk/engine.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Mrsk - class Engine < ::Rails::Engine - end -end diff --git a/lib/tasks/mrsk/app.rake b/lib/tasks/mrsk/app.rake deleted file mode 100644 index 5f8aef3f..00000000 --- a/lib/tasks/mrsk/app.rake +++ /dev/null @@ -1,97 +0,0 @@ -require_relative "setup" - -namespace :mrsk do - namespace :app do - desc "Run app on servers (or start them if they've already been run)" - task :run do - MRSK.config.roles.each do |role| - on(role.hosts) do |host| - begin - execute *MRSK.app.run(role: role.name) - rescue SSHKit::Command::Failed => e - if e.message =~ /already in use/ - error "Container with same version already deployed on #{host}, starting that instead" - execute *MRSK.app.start, host: host - else - raise - end - end - end - end - end - - desc "Start existing app on servers (use VERSION= to designate which version)" - task :start do - on(MRSK.config.hosts) { execute *MRSK.app.start, raise_on_non_zero_exit: false } - end - - desc "Stop app on servers" - task :stop do - on(MRSK.config.hosts) { execute *MRSK.app.stop, raise_on_non_zero_exit: false } - end - - desc "Start app on servers (use VERSION= to designate which version)" - task restart: %i[ stop start ] - - desc "Display information about app containers" - task :info do - on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.info) + "\n\n" } - end - - desc "Execute a custom task on servers passed in as CMD='bin/rake some:task'" - task :exec do - on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec(ENV["CMD"])) + "\n\n" } - end - - desc "Start Rails Console on primary host" - task :console do - puts "Launching Rails console on #{MRSK.config.primary_host}..." - exec app.console - end - - namespace :exec do - desc "Execute Rails command on servers, like CMD='runner \"puts %(Hello World)\"" - task :rails do - on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.exec("bin/rails", ENV["CMD"])) + "\n\n" } - end - - desc "Execute a custom task on the first defined server" - task :once do - on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec(ENV["CMD"])) } - end - - namespace :once do - desc "Execute Rails command on the first defined server, like CMD='runner \"puts %(Hello World)\"" - task :rails do - on(MRSK.config.primary_host) { puts capture(*MRSK.app.exec("bin/rails", ENV["CMD"])) } - end - end - end - - desc "List all the app containers currently on servers" - task :containers do - on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.list_containers) + "\n\n" } - end - - desc "Show last 100 log lines from app on servers" - task :logs do - # FIXME: Catch when app containers aren't running - on(MRSK.config.hosts) { |host| puts "App Host: #{host}\n" + capture(*MRSK.app.logs) + "\n\n" } - end - - desc "Remove app containers and images from servers" - task remove: %w[ remove:containers remove:images ] - - namespace :remove do - desc "Remove app containers from servers" - task :containers do - on(MRSK.config.hosts) { execute *MRSK.app.remove_containers } - end - - desc "Remove app images from servers" - task :images do - on(MRSK.config.hosts) { execute *MRSK.app.remove_images } - end - end - end -end diff --git a/lib/tasks/mrsk/build.rake b/lib/tasks/mrsk/build.rake deleted file mode 100644 index cf5bc639..00000000 --- a/lib/tasks/mrsk/build.rake +++ /dev/null @@ -1,52 +0,0 @@ -require_relative "setup" - -namespace :mrsk do - namespace :build do - desc "Deliver a newly built app image to servers" - task deliver: %i[ push pull ] - - desc "Build locally and push app image to registry" - task :push do - run_locally do - begin - debug "Using builder: #{MRSK.builder.name}" - info "Building image may take a while (run with VERBOSE=1 for progress logging)" - execute *MRSK.builder.push - rescue SSHKit::Command::Failed => e - error "Missing compatible builder, so creating a new one first" - execute *MRSK.builder.create - execute *MRSK.builder.push - end - end unless ENV["VERSION"] - end - - desc "Pull app image from the registry onto servers" - task :pull do - on(MRSK.config.hosts) { execute *MRSK.builder.pull } - end - - desc "Create a local build setup" - task :create do - run_locally do - debug "Using builder: #{MRSK.builder.name}" - execute *MRSK.builder.create - end - end - - desc "Remove local build setup" - task :remove do - run_locally do - debug "Using builder: #{MRSK.builder.name}" - execute *MRSK.builder.remove - end - end - - desc "Show the name of the configured builder" - task :info do - run_locally do - puts "Builder: #{MRSK.builder.name} (#{MRSK.builder.target.class.name})" - puts capture(*MRSK.builder.info) - end - end - end -end diff --git a/lib/tasks/mrsk/mrsk.rake b/lib/tasks/mrsk/mrsk.rake deleted file mode 100644 index 748dd18b..00000000 --- a/lib/tasks/mrsk/mrsk.rake +++ /dev/null @@ -1,37 +0,0 @@ -require_relative "setup" - -namespace :mrsk do - desc "Ship the app to servers that will have Docker installed if missing" - task ship: %w[ server:bootstrap deploy ] - - desc "Push the latest version of the app, ensure Traefik is running, then restart app" - task deploy: %w[ registry:login build:deliver traefik:run app:stop app:run prune ] - - desc "Rollback to VERSION=x that was already run as a container on servers" - task rollback: %w[ app:restart ] - - desc "Display information about Traefik and app containers" - task info: %w[ traefik:info app:info ] - - desc "Create config stub in config/deploy.yml" - task :init do - require "fileutils" - - if (deploy_file = Rails.root.join("config/deploy.yml")).exist? - puts "Config file already exists in config/deploy.yml (remove first to create a new one)" - else - FileUtils.cp_r Pathname.new(File.expand_path("templates/deploy.yml", __dir__)), deploy_file - puts "Created configuration file in config/deploy.yml" - end - - if (binstub = Rails.root.join("bin/mrsk")).exist? - puts "Binstub already exists in bin/mrsk (remove first to create a new one)" - else - FileUtils.cp_r Pathname.new(File.expand_path("templates/mrsk", __dir__)), binstub - puts "Created binstub file in bin/mrsk" - end - end - - desc "Remove Traefik, app, and registry session from servers" - task remove: %w[ traefik:remove app:remove registry:logout ] -end diff --git a/lib/tasks/mrsk/prune.rake b/lib/tasks/mrsk/prune.rake deleted file mode 100644 index 2c0f3a36..00000000 --- a/lib/tasks/mrsk/prune.rake +++ /dev/null @@ -1,18 +0,0 @@ -require_relative "setup" - -namespace :mrsk do - desc "Prune unused images and stopped containers" - task prune: %w[ prune:containers prune:images ] - - namespace :prune do - desc "Prune unused images older than 30 days" - task :images do - on(MRSK.config.hosts) { execute *MRSK.prune.images } - end - - desc "Prune stopped containers for the service older than 3 days" - task :containers do - on(MRSK.config.hosts) { execute *MRSK.prune.containers } - end - end -end diff --git a/lib/tasks/mrsk/registry.rake b/lib/tasks/mrsk/registry.rake deleted file mode 100644 index 773cd28f..00000000 --- a/lib/tasks/mrsk/registry.rake +++ /dev/null @@ -1,16 +0,0 @@ -require_relative "setup" - -namespace :mrsk do - namespace :registry do - desc "Login to the registry locally and remotely" - task :login do - run_locally { execute *MRSK.registry.login } - on(MRSK.config.hosts) { execute *MRSK.registry.login } - end - - desc "Logout of the registry remotely" - task :logout do - on(MRSK.config.hosts) { execute *MRSK.registry.logout } - end - end -end diff --git a/lib/tasks/mrsk/server.rake b/lib/tasks/mrsk/server.rake deleted file mode 100644 index 68747b0d..00000000 --- a/lib/tasks/mrsk/server.rake +++ /dev/null @@ -1,10 +0,0 @@ -require_relative "setup" - -namespace :mrsk do - namespace :server do - desc "Setup Docker on the remote servers" - task :bootstrap do - on(MRSK.config.hosts) { execute "which docker || apt-get install docker.io -y" } - end - end -end diff --git a/lib/tasks/mrsk/setup.rb b/lib/tasks/mrsk/setup.rb deleted file mode 100644 index 4ff2eb23..00000000 --- a/lib/tasks/mrsk/setup.rb +++ /dev/null @@ -1,6 +0,0 @@ -require "sshkit" -require "sshkit/dsl" - -include SSHKit::DSL - -MRSK = Mrsk::Commander.new config_file: Rails.root.join("config/deploy.yml"), verbose: ENV["VERBOSE"] diff --git a/lib/tasks/mrsk/templates/mrsk b/lib/tasks/mrsk/templates/mrsk deleted file mode 100755 index 6d11b783..00000000 --- a/lib/tasks/mrsk/templates/mrsk +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -if [ "${*}" == "" ]; then - # Improve so list matches - exec bin/rake -T mrsk -else - exec bin/rake "mrsk:$@" -fi diff --git a/lib/tasks/mrsk/traefik.rake b/lib/tasks/mrsk/traefik.rake deleted file mode 100644 index 3716283b..00000000 --- a/lib/tasks/mrsk/traefik.rake +++ /dev/null @@ -1,41 +0,0 @@ -require_relative "setup" - -namespace :mrsk do - namespace :traefik do - desc "Run Traefik on servers" - task :run do - on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.run, raise_on_non_zero_exit: false } - end - - desc "Start existing Traefik on servers" - task :start do - on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.start, raise_on_non_zero_exit: false } - end - - desc "Stop Traefik on servers" - task :stop do - on(MRSK.config.role(:web).hosts) { execute *MRSK.traefik.stop, raise_on_non_zero_exit: false } - end - - desc "Restart Traefik on servers" - task restart: %i[ stop start ] - - desc "Display information about Traefik containers from servers" - task :info do - on(MRSK.config.role(:web).hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.info) + "\n\n" } - end - - desc "Show last 100 log lines from Traefik on servers" - task :logs do - on(MRSK.config.hosts) { |host| puts "Traefik Host: #{host}\n" + capture(*MRSK.traefik.logs) + "\n\n" } - end - - desc "Remove Traefik container and image from servers" - task remove: %i[ stop ] do - on(MRSK.config.role(:web).hosts) do - execute *MRSK.traefik.remove_container - execute *MRSK.traefik.remove_image - end - end - end -end diff --git a/mrsk.gemspec b/mrsk.gemspec index 090c8604..8bbc829b 100644 --- a/mrsk.gemspec +++ b/mrsk.gemspec @@ -10,7 +10,9 @@ Gem::Specification.new do |spec| spec.license = "MIT" spec.files = Dir["lib/**/*", "MIT-LICENSE", "README.md"] + spec.executables = %w[ mrsk ] - spec.add_dependency "railties", ">= 7.0.0" + spec.add_dependency "activesupport", ">= 7.0" spec.add_dependency "sshkit", "~> 1.21" + spec.add_dependency "thor", "~> 1.2" end