minifast/manic_baker

View on GitHub
lib/manic_baker/cli.rb

Summary

Maintainability
A
45 mins
Test Coverage
require "librarian/chef/cli"
require "thor"
require "thor/shell/mean"
require "fog"
require "manic_baker/config"
require "manic_baker/remote_config"
require "soloist/spotlight"
require "soloist/remote"

module ManicBaker
  class Cli < Thor
    include Thor::Shell::Mean

    desc "launch", "Launch a new instance, Alana"
    def launch(dataset = nil)
      unless dataset.nil?
        config.dataset = dataset
        config.save
      end

      check_dataset
      check_no_servers

      say_message_for(:start, :success, config.dataset)
      joyent.servers.create(config.to_hash)
      say_waiting_until { dataset_servers.first.state == "running" }
      say_message_for(:start, :success, dataset_servers.first.name)
    end

    desc "panic", "Destroy some instances or whatever?  Who cares."
    def panic
      check_dataset
      check_servers

      dataset_servers.each { |s| say_message_for(:stop, :success, s.name) }
      dataset_servers.each(&:destroy)
      say_waiting_until { !any_running? }
      say_message_for(:terminate, :success)
    end

    desc "ssh", "I'm just gonna take a moment okay?"
    def ssh
      check_dataset
      check_servers

      exec("ssh -i #{config.private_key_path} root@#{dataset_servers.first.public_ip_address}")
    end

    desc "bootstrap", "You know those boots are like 90s style right"
    def bootstrap
      check_dataset
      check_servers

      remote.upload("#{script_path}/", "script/")
      remote.system!("script/bootstrap.sh")
    end

    desc "chef", "Can you like make some spaghetti?  I'm so high."
    def chef
      check_dataset
      check_servers
      install_cookbooks if cheffile_exists?
      remote_config.run_chef
    end

    private

    def cheffile_exists?
      File.exists?(File.expand_path("../Cheffile", config_path))
    end

    def install_cookbooks
      Dir.chdir(File.dirname(config_path)) do
        Librarian::Chef::Cli.with_environment do
          Librarian::Chef::Cli.new.install
        end
      end
    end

    def any_running?
      dataset_servers.any? do |server|
        begin
          server.reload
          server.state == "running"
        rescue Excon::Errors::Gone
          false
        end
      end
    end

    def check_dataset
      if config.dataset.nil?
        raise Thor::Error.new("requires a dataset the first time out")
      end
    end

    def check_servers
      if dataset_servers.empty?
        raise Thor::Error.new("found zero servers with dataset #{config.dataset}")
      end
    end

    def check_no_servers
      unless dataset_servers.empty?
        raise Thor::Error.new("cannot clobber an existing instance")
      end
    end

    def script_path
      File.expand_path("../../../script", __FILE__)
    end

    def dataset_servers
      joyent.servers.reload.select do |server|
        server.dataset == config.dataset
      end
    end

    def say_waiting_until
      say_waiting
      say_until(".", nil, false) do
        yield.tap do |all_done|
          unless all_done
            say_boring if rand < 0.1
            sleep 1
          end
        end
      end
    end

    def remote_config
      @remote_config ||= ManicBaker::RemoteConfig.new(config, remote)
    end

    def remote
      @remote ||= Soloist::Remote.new(
        "root",
        dataset_servers.first.public_ip_address,
        config.private_key_path
      )
    end

    def joyent
      @joyent ||= Fog::Compute.new(
        provider: "Joyent",
        joyent_url: config.joyent_uri
      )
    end

    def config
      @config ||= ManicBaker::Config.from_file(config_path)
    end

    def config_path
      @config_path ||= Soloist::Spotlight.find!(".baker.yml")
    end
  end
end