module Gaptool::SSH

Constants

BATCH_SIZE
START_MARKER
STOP_MARKER

Public Class Methods

config() click to toggle source
# File lib/gaptool_client/ssh.rb, line 38
def self.config
  config = File.join(Dir.home, '.ssh', 'config')
  dir = File.dirname(config)
  parent = File.join(dir, '..')
  if File.exist?(config)
    Gaptool::Helpers.error "#{config}: not writable" unless File.writable?(config)
    content = File.read(config)
    File.open("#{config}.bck", 'w') { |f| f.write(content) }
  else
    if !File.exist?(dir)
      Gaptool::Helpers.error "Home directory #{parent} does not exists"\
        unless Dir.exist?(parent)
      Dir.mkdir(dir, 0700)
    elsif !File.directory?(dir)
      Gaptool::Helpers.error "#{dir}: not a directory"
    end
    content = ''
  end
  [config, content]
end
config_for(node) click to toggle source
# File lib/gaptool_client/ssh.rb, line 21
    def self.config_for(node)
      key = "\n  IdentityFile #{ssh_identity}" if ssh_identity
      host = Gaptool::API.get_host(node)
      <<-EOF
# -- #{node['instance']}
Host #{host} #{node['instance']}
  Hostname #{node['hostname']}
  User #{ENV['GT_USER']}
  LogLevel FATAL
  PreferredAuthentications publickey
  CheckHostIP no
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null#{key}
# -- end #{node['instance']}
  EOF
    end
configure_sshkit(opts = {}) click to toggle source
# File lib/gaptool_client/ssh.rb, line 87
def self.configure_sshkit(opts = {})
  SSHKit.config.output_verbosity = opts[:log_level] || Logger::WARN
  opts = {
    forward_agent: true,
    global_known_hosts_file: '/dev/null',
    keys_only: true,
    port: 22,
    user: ENV['GT_USER']
  }
  opts[:keys] = [ssh_identity] if ssh_identity
  SSHKit::Backend::Netssh.configure do |ssh|
    ssh.connection_timeout = 30
    ssh.ssh_options = opts
  end
end
exec(nodes, commands, opts = {}) click to toggle source
# File lib/gaptool_client/ssh.rb, line 103
def self.exec(nodes, commands, opts = {})
  logger = SSHKit::Formatter::Pretty.new(STDERR)
  serial = opts[:serial] || nodes.length == 1
  if opts[:update_ssh_config].nil? || opts[:update_ssh_config]
    nodes.each { |n| Gaptool::SSH.update_config_for(n, false) }
  end
  pre = opts[:pre_hooks] || []
  post = opts[:post_hooks] || []
  Gaptool::SSH.configure_sshkit(log_level: opts[:log_level])
  opts = {
    limit: opts[:batch_size].to_i || BATCH_SIZE,
    on_errors: opts[:continue_on_errors] ? :continue : :exit,
    wait: opts[:wait] || 0
  }
  runner_cls = if serial
                 SSHKit::Runner::SafeSequential
               else
                 SSHKit::Runner::SafeParallel
               end
  hosts = nodes.map { |n| Gaptool::Host.new(n) }
  runner = runner_cls.new(hosts, opts) do |host|
    pre.each { |h| instance_exec(host, &h) }
    commands.each do |cmd|
      next if cmd.nil? || cmd.empty?
      execute(:bash, "-l -c '#{cmd}'",
              interaction_handler: host.handler)
    end
    post.each { |h| instance_exec(host, &h) }
  end
  res = runner.execute

  unless res
    logger.error("#{runner.failed.length}/#{nodes.length} hosts failed")
    runner.failed.each do |desc|
      host = desc[:host]
      error = desc[:error]
      logger.error("#{host.name}> #{error.message}")
    end
    return runner.failed.length + 100
  end
  0
end
ssh_identity() click to toggle source
# File lib/gaptool_client/ssh.rb, line 15
def self.ssh_identity
  @ssh_id ||= if ENV['GT_SSH_KEY']
                File.realpath(File.expand_path(ENV['GT_SSH_KEY']))
              end
end
update_config_for(nodes, verbose = true) click to toggle source
# File lib/gaptool_client/ssh.rb, line 59
    def self.update_config_for(nodes, verbose = true)
      nodes = [nodes] unless nodes.is_a?(Array)
      config, content = Gaptool::SSH.config
      nodes.each do |node|
        snip = Gaptool::SSH.config_for(node)
        mark = "# -- #{node['instance']}"
        emark = "# -- end #{node['instance']}"

        if Regexp.new(mark).match(content)
          puts Rainbow("Updating ssh config for #{Gaptool::API.get_host(node)}").green if verbose
          content.gsub!(/#{mark}.*?#{emark}/m, snip.strip)
        elsif Regexp.new(STOP_MARKER).match(content)
          puts Rainbow("Adding ssh config for #{Gaptool::API.get_host(node)}").green if verbose
          content.gsub!(/#{STOP_MARKER}/m, snip + "\n" + STOP_MARKER)
        else
          puts Rainbow('No gt ssh config found: please run gt ssh-config').yellow
          puts Rainbow("Adding ssh config for #{Gaptool::API.get_host(node)}").green if verbose
          content = <<-EOF
#{content}
#{START_MARKER}
#{snip}
#{STOP_MARKER}
EOF
        end
      end
      File.open(config, 'w') { |f| f.write(content) }
    end