forked from basecamp/kamal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Switch to proper standalone executable with Thor
- Loading branch information
Showing
28 changed files
with
387 additions
and
307 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } | |
gemspec | ||
|
||
gem "debug" | ||
gem "railties" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#!/usr/bin/env ruby | ||
|
||
require "mrsk/cli" | ||
|
||
Mrsk::Cli::Main.start(ARGV) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,4 @@ module Mrsk | |
end | ||
|
||
require "mrsk/version" | ||
require "mrsk/engine" | ||
require "mrsk/commander" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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=<git-hash> 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=<git-hash> 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.