class Shuttle::Runner

Attributes

config[R]
config_path[R]
options[R]
target[R]

Public Class Methods

new(options) click to toggle source
# File lib/shuttle/runner.rb, line 9
def initialize(options)
  @options     = options
  @config_path = File.expand_path(options[:path])
  @target      = options[:target]

  if !File.exists?(config_path)
    raise ConfigError, "Config file #{config_path} does not exist"
  end

  @config_path = config_path
  @target = target

  if @options[:log]
    ENV["SHUTTLE_DEBUG"] = "1"
  end
end

Public Instance Methods

execute(command) click to toggle source
# File lib/shuttle/runner.rb, line 62
def execute(command)
  @config = load_config

  strategy = config.app.strategy || 'static'
  if strategy.nil?
    raise ConfigError, "Invalid strategy: #{strategy}"
  end

  if @config.target
    server = @config.target
  else
    if @config.targets.nil?
      raise ConfigError, "Please define deployment target"
    end

    server = @config.targets[target]
    if server.nil?
      raise ConfigError, "Target #{target} does not exist"
    end
  end

  validate_target(server)

  ssh = Net::SSH::Session.new(server.host, server.user, server.password)

  if options[:log]
    ssh.logger = Logger.new(STDOUT)
  end

  begin
    Timeout::timeout(10) { ssh.open }
  rescue Timeout::Error
    STDERR.puts "Unable to establish SSH connection to the server within 10 seconds"
    exit 1
  end
  
  klass = Shuttle.const_get(strategy.capitalize) rescue nil
  command.gsub!(/:/,'_')
  exit_code = 0

  if klass.nil?
    STDERR.puts "Invalid strategy: #{strategy}"
    exit 1
  end

  unless %w(setup deploy rollback).include?(command)
    STDERR.puts "Invalid command: #{command}"
    exit 1
  end

  integration = klass.new(config, ssh, server, target)

  puts "\n"
  puts "Shuttle v#{Shuttle::VERSION}\n"
  puts "\n"
  integration.log "Connected to #{server.user}@#{server.host}"
  
  if integration.respond_to?(command)
    time_start = Time.now

    begin
      if integration.deploy_running?
        deployer = ssh.read_file("#{integration.deploy_path}/.lock").strip
        message = "Another deployment is running."
        message << " Deployer: #{deployer}" if deployer.size > 0

        integration.error(message)
      end

      integration.disable_history
      integration.write_lock
      integration.export_environment
      integration.send(command.to_sym)
      integration.write_revision

    rescue DeployError => err
      integration.cleanup_release
      exit_code = 1
    rescue SystemExit
      # NOOP
      exit_code = 0
    rescue Interrupt
      STDERR.puts "Interrupted by user. Aborting deploy..."
      exit_code = 1
    rescue Exception => err
      integration.cleanup_release
      integration.log("Shuttle ERROR: #{err.message}", 'error')
      integration.log(err.backtrace.join("\n"), 'error')

      exit_code = 1
    ensure
      integration.release_lock
    end

    if exit_code == 0
      diff = (Float(Time.now - time_start) * 100).round / 100
      duration = ChronicDuration.output(diff, :format => :short)
      puts "\nExecution time: #{duration}\n"
    end

    puts "\n"
    exit(exit_code)

  else
    raise ConfigError, "Invalid command: #{command}"
  end

  ssh.close
rescue SocketError => err
  STDERR.puts "Socket error: #{err.message}"
  exit 1
rescue Net::SSH::AuthenticationFailed
  STDERR.puts "SSH Authentication failed"
  exit 1
end
load_config() click to toggle source
# File lib/shuttle/runner.rb, line 26
def load_config
  data = File.read(config_path).strip

  if data.empty?
    raise ConfigError, "Configuration file is empty"
  end

  if config_path =~ /\.toml$/
    parse_toml_data(data)
  else
    parse_yaml_data(data)
  end
end
parse_toml_data(data) click to toggle source
# File lib/shuttle/runner.rb, line 44
def parse_toml_data(data)
  Hashr.new(TOML::Parser.new(data).parsed)
end
parse_yaml_data(data) click to toggle source
# File lib/shuttle/runner.rb, line 40
def parse_yaml_data(data)
  Hashr.new(YAML.safe_load(data))
end
validate_target(target) click to toggle source
# File lib/shuttle/runner.rb, line 48
def validate_target(target)
  if target.host.nil?
    raise ConfigError, "Target host required"
  end

  if target.user.nil?
    raise ConfigError, "Target user required"
  end

  if target.deploy_to.nil?
    raise ConfigError, "Target deploy path required"
  end
end