#!/usr/bin/ruby -w
require 'net/telnet'
$: << "#{File.dirname($0)}/inc/rexpect/inc" << "#{File.dirname($0)}/inc"
$expect_verbose = true
require 'RExpect'

# Provides mapping from person to hostname and passwd
# SECRETS = {
#  "joe"    => {:host_name => 'joes_host_name',   :passwd => 'joes_root_passwd'  },...}
#
require 'mapping'

ROOT_PROMPT = /([\n\m]|^)[^\n\r]*# /m
USER_PROMPT = /([\n\r]|^)[^\n\r]*\$ /m
MY_NAME = 'radmin@YOURHOSTNAME.HERE.COM'
PUBLIC_KEY = File.read("#{ENV['HOME']}/.ssh/id_rsa.pub")
VERY_VERY_OLD_VERSION='2.16'
VERY_OLD_VERSION='2.17'
OLD_VERSION='2.18'
DISTCC_VERSION='2.18.3'
CCACHE_VERSION='2.4'

def print_help_and_exit(plaint='Usage:-')
  puts "
#{plaint}

takeover hostname

Install public key, adds user distcc

"
  exit 1
end

def add_my_public_key( rex)
  rex.cmd "mkdir ~/.ssh"
  rex.cmd "chmod 0700 ~/.ssh"
  rex.cmd "echo >> ~/.ssh/authorized_keys"
  rex.cmd "echo '#{PUBLIC_KEY}' >> ~/.ssh/authorized_keys"
  rex.cmd "echo >> ~/.ssh/authorized_keys"
  rex.cmd "chmod 0700 ~/.ssh/authorized_keys"
end

def give_me_public_key_access( host_name, user, passwd)
  rex = RExpect.spawn("ssh -l #{user} #{host_name}")
  rex.time_out = 10
  
  prompt = USER_PROMPT
  prompt = ROOT_PROMPT if user == 'root'
  rex.prompt = prompt
  
  case rex.expect_one_of( [:yes, /Are you sure you want to continue connecting \(yes\/no\)\?/], 
                          [:passwd, /[pP]assword:/],
                          [:got_root, prompt])
  when :yes
    rex.puts 'yes'
    rex.expect( /password:/)
    rex.cmd passwd
  when :passwd
    rex.cmd passwd
  when :got_root
    return
  else
    raise "Connection error"
  end
  
  rex.puts 'ls -l .ssh'
  
  result = rex.expect_one_of( [:has_auth, /\bauthorized_keys\b/], 
                              [:no_ssh, /\.foo: No such file or directory/],
                              [:ssh_but_no_auth, prompt])
  
  case result
  when :has_auth
    rex.expect prompt
    # He has an authorized_keys, are we innit?
    rex.puts "grep '#{MY_NAME}' ~/.ssh/authorized_keys"
    rex.expect %r{grep '#{MY_NAME}' ~/.ssh/authorized_keys} # Don't match on echo back
    case rex.expect_one_of( [:should_work_then, /#{MY_NAME}/ ], [:not_there, prompt] )
    when :should_work_then
      puts "He has an .ssh/authorized_keys with me in, should have worked but didn't,  check permissions."
      exit(1)
    when :not_there
      add_my_public_key(rex)
    else
      raise "Infernal error"
    end
  when :no_ssh
    rex.expect prompt
    add_my_public_key(rex)
  when :ssh_but_no_auth
    add_my_public_key(rex)
  when nil
    raise "Failed"
  else
    raise "Infernal error"
  end

  rex.puts "exit"

  test_access( host_name, user)
end

def test_access( host_name, user)
  return if `ssh -l #{user} #{host_name} 'ls ~/.ssh'` =~ %r{ authorized_keys  }x

  puts "Public key access failed"

  exit(1)
end

def add_user( host_name, user, passwd)
  rex = RExpect.spawn( "ssh -l root #{host_name}")
  rex.time_out = 10
  rex.prompt = ROOT_PROMPT
  rex.cmd "adduser #{user}"
  rex.puts "passwd #{user}"
  sleep 1
  rex.expect( /new (UNIX )?password: /i)
  sleep 2
  rex.puts passwd
  rex.expect( /[Rr]etype [^\n\r]*password: /i)
  rex.puts passwd
  rex.puts ""
  rex.puts ""
  rex.puts ""
  rex.puts ""
  rex.puts ""
  rex.puts ""
  rex.puts "logout"
  give_me_public_key_access( host_name, user, passwd)
end

class NoRouteException < Exception
end

def ssh(user,host_name,cmd)
  ssh_cmd = "ssh -l #{user} #{host_name} '#{cmd}'"
  puts ssh_cmd
  result = `#{ssh_cmd} 2>&1`
  puts result
  raise NoRouteException,ssh_cmd if result =~ %r{No route to}
end

def install_distcc( host_name)
  tar_ball = "distcc-#{DISTCC_VERSION}.tar.bz2"
  ssh( 'distcc', host_name, "rm -r distcc-#{DISTCC_VERSION}*")
  ssh( 'distcc', host_name, "rm -r distcc-#{OLD_VERSION}*")
  ssh( 'distcc', host_name, "rm -r distcc-#{VERY_OLD_VERSION}*")
  ssh( 'distcc', host_name, "rm -r distcc-#{VERY_VERY_OLD_VERSION}*")
  scp =  "scp ~/stash/#{tar_ball} distcc@#{host_name}:"

  puts scp
  puts `#{scp}`
  ssh( 'distcc', host_name, "tar -xvjf #{tar_ball};cd distcc-#{DISTCC_VERSION};nice ./configure;nice make")
  ssh( 'root', host_name, "cd ~distcc/distcc-#{DISTCC_VERSION};nice make install")
end

def install_distcc_init( host_name)
  puts `scp /home/radmin/bin/distcc.init root@#{host_name}:/etc/init.d/distcc`
  ssh( 'root', host_name, "chmod 744 /etc/init.d/distcc;chkconfig --add distcc;/etc/init.d/distcc restart")
end

def install_ccache( host_name)
  puts "Installing ccache"
  tar_ball = "ccache-#{CCACHE_VERSION}.tar.gz"
  ssh( 'distcc', host_name, "rm -r ccache-#{CCACHE_VERSION}*")
  ssh( 'root', host_name, "rm -v /usr/bin/ccache /usr/local/bin/ccache")

  scp =  "scp ~/stash/#{tar_ball} distcc@#{host_name}:"

  puts scp
  puts `#{scp}`

  ssh( 'distcc', host_name, "tar -xvzf #{tar_ball};cd ccache-#{CCACHE_VERSION};nice ./configure --prefix=/usr;nice make")
  ssh( 'root', host_name, "cd ~distcc/ccache-#{CCACHE_VERSION};nice make install")
end

print_help_and_exit( "Insufficient arguments") if ARGV.length <= 0
print_help_and_exit( "Too many arguments") if ARGV.length > 1

Dir.chdir ENV['HOME']

target = ARGV.shift
todo = []
if target != 'all'
  print_help_and_exit( "Don't know the secrets of #{target}") unless SECRETS.has_key? target
  todo << target
else
  todo += SECRETS.keys.find_all{|t| SECRETS[t].has_key?( :host_name)}
end

todo.each do |target|
  secret = SECRETS[target]
  host_name = secret[:host_name]

  give_me_public_key_access( host_name, 'root', secret[:passwd])
  
  add_user( host_name, 'distcc', SECRETS['distcc'][:passwd])
  
  install_distcc( host_name)
  install_distcc_init( host_name)
  install_ccache(host_name)
end
