module XP5K::Rake::DSL

Private Instance Methods

get_width() click to toggle source
# File lib/xp5k/rake/dsl.rb, line 191
def get_width
  result = ENV["TERM"] ? `tput cols` : 80
  result.to_i
end
on(hosts, *args) { || ... } click to toggle source
# File lib/xp5k/rake/dsl.rb, line 51
def on(hosts, *args, &block)

  logs = Hash.new { |h,k| h[k] = [] }
  errors = Hash.new { |h,k| h[k] = [] }
  ssh_session = {}
  current_server = ""
  all_connected = false
  failed_servers = []
  hosts = [hosts] if hosts.class == String

  XP5K::Config[:user] ||= ENV["USER"]
  XP5K::Config[:gateway] ||= XP5K::Config[:user] + "@access.grid5000.fr"

  commands = (args.last.class == String or args.last.class == Array) ? (args.last.class == String ? [args.pop] : args.pop ) : []
  options = args.last.class == Hash ? args.pop : {}
  options[:user] ||= 'root'
  options[:environment] ||= {}
  cmd_env = options[:environment].map do |key, value|
    "#{key}=#{value}"
  end

  options[:retry] ||= ( XP5K::Config[:onRetry] ||= false )
  options[:retryCount] ||= ( XP5K::Config[:onRetryCount] ||= 3 )
  options[:retryDelay] ||= ( XP5K::Config[:onRetryDelay] ||= 3 )

  # net/ssh specific options
  options[:ssh] ||= {}

  if block_given?
    case result = yield
    when String
      commands << result
    when Array
      commands.push(result).flatten!
    else
      raise "<on> block must return String or Array"
    end
  end

  retryCount = XP5K::Config[:onRetryCount]

  until all_connected
    failed = false
    gateway_options = {}
    gateway_options[:config] = XP5K::Config[:ssh_config] || true
    gateway_user, gateway_host = XP5K::Config[:gateway].match(/^(?:([^;,:=]+)@|)(.*?)$/)[1,2]
    gateway = Net::SSH::Gateway.new(gateway_host, gateway_user, gateway_options)
    workq = Queue.new
    hosts.each{ |host| workq << host }
    workers = (0...10).map do
      Thread.new do
        begin
          while host = workq.pop(true)
            begin
              Timeout.timeout(5) do
                ssh_session[host] = gateway.ssh(host, options[:user], options[:ssh])
                puts "Connected to #{host}..."
              end
            rescue Timeout::Error, Net::SSH::Disconnect, Exception => e
              if not options[:retry]
                puts "Removing #{host} (#{e.message})..."
                hosts.delete host
                failed_servers << host
              elsif retryCount > 0
                puts "Error connecting to #{host}. Retry in #{options[:retryDelay]}s (#{retryCount} attempts)."
                retryCount -= 1
                sleep options[:retryDelay]
              else
                raise "Error connecting to #{host} after #{options[:retryCount]} attempts."
              end
                failed = true
            end
          end

        rescue ThreadError
        end

      end
    end; "ok"
    workers.map(&:join); "ok"

    all_connected = true if !failed
  end

  workq = Queue.new
  hosts.each{ |host| workq << host }
  workers = (0...10).map do
    Thread.new do
      begin
        while host = workq.pop(true)
          begin
            commands.each do |command|
              stdout = ""
              command.prepend(cmd_env.join(' ') + ' ') unless cmd_env.empty?
              puts "[command][#{host}] #{command}"
              ssh_session[host].exec!(command) do |channel, stream, data|
                stdout << data
                errors[host] << data.chomp if stream == :err
                puts "[#{stream}][#{host}] #{data}" if data.chomp != ""
              end
              logs[host] = stdout
            end
          rescue Exception => e
            puts "[#{host}] " + e.message
          end
        end
      rescue ThreadError
      end
    end
  end; "ok"
  workers.map(&:join); "ok"

  # Print the result sorting by hostname
  errors.sort.each do |error|
    puts "---- stderr on #{error.first} #{"-" * (get_width - error.first.length - 16)} "
    puts "#{error[1]}"
  end
  logs.sort.each do |key, value|
    puts "---- #{key} #{"-" * (get_width - key.length - 6)}"
    puts value
  end
  puts "Servers unreachable : #{failed_servers.inspect}" if !failed_servers.empty?

  # Clean all ssh connections
  puts "Closing ssh connections..."
  hosts.each do |host|
    ssh_session[host].close
    gateway.close ssh_session[host].transport.port
  end
  gateway.shutdown!

  # returns the output
  # as a map : node => [out1, ..., outn]
  return logs
end
role(*args, &block) click to toggle source
# File lib/xp5k/rake/dsl.rb, line 14
def role(*args, &block)
  hosts = []
  procblock = nil
  if block_given?
    raise 'Arguments not allowed with block' unless args[1].nil?
    procblock = block
  else
    case args[1]
    when String
      hosts = [args[1]]
    when Array
      hosts = args[1]
    else
      raise "Role <#{args.first}> argument must be a String or an Array"
    end
  end

  if not existing_role = XP5K::Role.findByName(args.first)
    XP5K::Role.new(name: args.first, size: hosts.length, servers: hosts, proc: procblock).add
  else
    existing_role.size = hosts.length
    existing_role.servers = hosts
    existing_role.proc = procblock
  end

end
roles(*args) click to toggle source
# File lib/xp5k/rake/dsl.rb, line 42
def roles(*args)
  hosts = []
  args.each do |rolename|
    hosts << XP5K::Role.findByName(rolename).servers
  end
  hosts.flatten!
end
run(command) click to toggle source
# File lib/xp5k/rake/dsl.rb, line 187
def run(command)

end