class Redoxed::Node

Attributes

auth[R]
email[RW]
from[RW]
group[R]
input[R]
ip[R]
last[R]
model[R]
msg[RW]
name[R]
output[R]
prompt[R]
repo[R]
retry[RW]
running[RW]
running?[RW]
stats[RW]
user[RW]
vars[R]

Public Class Methods

new(opt) click to toggle source
# File lib/redoxed/node.rb, line 12
def initialize(opt)
  Redoxed.logger.debug 'resolving DNS for %s...' % opt[:name]
  # remove the prefix if an IP Address is provided with one as IPAddr converts it to a network address.
  ip_addr, = opt[:ip].to_s.split("/")
  Redoxed.logger.debug 'IPADDR %s' % ip_addr.to_s
  @name = opt[:name]
  @ip = IPAddr.new(ip_addr).to_s rescue nil
  @ip ||= Resolv.new.getaddress(@name) if Redoxed.config.resolve_dns?
  @ip ||= @name
  @group = opt[:group]
  @model = resolve_model opt
  @input = resolve_input opt
  @output = resolve_output opt
  @auth = resolve_auth opt
  @prompt = resolve_prompt opt
  @vars = opt[:vars]
  @stats = Stats.new
  @retry = 0
  @repo = resolve_repo opt

  # model instance needs to access node instance
  @model.node = self
end

Public Instance Methods

last=(job) click to toggle source
# File lib/redoxed/node.rb, line 116
def last=(job)
  if job
    ostruct = OpenStruct.new
    ostruct.start  = job.start
    ostruct.end    = job.end
    ostruct.status = job.status
    ostruct.time   = job.time
    @last = ostruct
  else
    @last = nil
  end
end
modified() click to toggle source
# File lib/redoxed/node.rb, line 134
def modified
  @stats.update_mtime
end
reset() click to toggle source
# File lib/redoxed/node.rb, line 129
def reset
  @user = @email = @msg = @from = nil
  @retry = 0
end
run() click to toggle source
# File lib/redoxed/node.rb, line 36
def run
  status, config = :fail, nil
  @input.each do |input|
    # don't try input if model is missing config block, we may need strong config to class_name map
    cfg_name = input.to_s.split('::').last.downcase
    next unless @model.cfg[cfg_name] && (not @model.cfg[cfg_name].empty?)

    @model.input = input = input.new
    if (config = run_input(input))
      Redoxed.logger.debug "lib/redoxed/node.rb: #{input.class.name} ran for #{name} successfully"
      status = :success
      break
    else
      Redoxed.logger.debug "lib/redoxed/node.rb: #{input.class.name} failed for #{name}"
      status = :no_connection
    end
  end
  @model.input = nil
  [status, config]
end
run_input(input) click to toggle source
# File lib/redoxed/node.rb, line 57
def run_input(input)
  rescue_fail = {}
  [input.class::RescueFail, input.class.superclass::RescueFail].each do |hash|
    hash.each do |level, errors|
      errors.each do |err|
        rescue_fail[err] = level
      end
    end
  end
  begin
    input.connect(self) && input.get
  rescue *rescue_fail.keys => err
    resc = ''
    unless (level = rescue_fail[err.class])
      resc  = err.class.ancestors.find { |e| rescue_fail.has_key?(e) }
      level = rescue_fail[resc]
      resc  = " (rescued #{resc})"
    end
    Redoxed.logger.send(level, '%s raised %s%s with msg "%s"' % [ip, err.class, resc, err.message])
    false
  rescue StandardError => err
    crashdir  = Redoxed.config.crash.directory
    crashfile = Redoxed.config.crash.hostnames? ? name : ip.to_s
    FileUtils.mkdir_p(crashdir) unless File.directory?(crashdir)

    File.open File.join(crashdir, crashfile), 'w' do |fh|
      fh.puts Time.now.utc
      fh.puts err.message + ' [' + err.class.to_s + ']'
      fh.puts '-' * 50
      fh.puts err.backtrace
    end
    Redoxed.logger.error '%s raised %s with msg "%s", %s saved' % [ip, err.class, err.message, crashfile]
    false
  end
end
serialize() click to toggle source
# File lib/redoxed/node.rb, line 93
def serialize
  h = {
    name:      @name,
    full_name: @name,
    ip:        @ip,
    group:     @group,
    model:     @model.class.to_s,
    last:      nil,
    vars:      @vars,
    mtime:     @stats.mtime
  }
  h[:full_name] = [@group, @name].join('/') if @group
  if @last
    h[:last] = {
      start:  @last.start,
      end:    @last.end,
      status: @last.status,
      time:   @last.time
    }
  end
  h
end

Private Instance Methods

git_type(opt) click to toggle source
# File lib/redoxed/node.rb, line 228
def git_type(opt)
  type = opt[:output] || Redoxed.config.output.default
  return nil unless type[0..2] == "git"

  type
end
resolve_auth(opt) click to toggle source
# File lib/redoxed/node.rb, line 144
def resolve_auth(opt)
  # Resolve configured username/password
  {
    username: resolve_key(:username, opt),
    password: resolve_key(:password, opt)
  }
end
resolve_input(opt) click to toggle source
# File lib/redoxed/node.rb, line 152
def resolve_input(opt)
  inputs = resolve_key :input, opt, Redoxed.config.input.default
  inputs.split(/\s*,\s*/).map do |input|
    Redoxed.mgr.add_input(input) || raise(MethodNotFound, "#{input} not found for node #{ip}") unless Redoxed.mgr.input[input]

    Redoxed.mgr.input[input]
  end
end
resolve_key(key, opt, global = nil) click to toggle source
# File lib/redoxed/node.rb, line 193
def resolve_key(key, opt, global = nil)
  # resolve key, first get global, then get group then get node config
  key_sym = key.to_sym
  key_str = key.to_s
  value   = global
  Redoxed.logger.debug "node.rb: resolving node key '#{key}', with passed global value of '#{value}' and node value '#{opt[key_sym]}'"

  # global
  if (not value) && Redoxed.config.has_key?(key_str)
    value = Redoxed.config[key_str]
    Redoxed.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from global"
  end

  # group
  if Redoxed.config.groups.has_key?(@group)
    if Redoxed.config.groups[@group].has_key?(key_str)
      value = Redoxed.config.groups[@group][key_str]
      Redoxed.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from group"
    end
  end

  # model
  if Redoxed.config.models.has_key?(@model.class.name.to_s.downcase)
    if Redoxed.config.models[@model.class.name.to_s.downcase].has_key?(key_str)
      value = Redoxed.config.models[@model.class.name.to_s.downcase][key_str]
      Redoxed.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from model"
    end
  end

  # node
  value = opt[key_sym] || value
  Redoxed.logger.debug "node.rb: returning node key '#{key}' with value '#{value}'"
  value
end
resolve_model(opt) click to toggle source
# File lib/redoxed/node.rb, line 168
def resolve_model(opt)
  model = resolve_key :model, opt
  unless Redoxed.mgr.model[model]
    Redoxed.logger.debug "lib/redoxed/node.rb: Loading model #{model.inspect}"
    Redoxed.mgr.add_model(model) || raise(ModelNotFound, "#{model} not found for node #{ip}")
  end
  Redoxed.mgr.model[model].new
end
resolve_output(opt) click to toggle source
# File lib/redoxed/node.rb, line 161
def resolve_output(opt)
  output = resolve_key :output, opt, Redoxed.config.output.default
  Redoxed.mgr.add_output(output) || raise(MethodNotFound, "#{output} not found for node #{ip}") unless Redoxed.mgr.output[output]

  Redoxed.mgr.output[output]
end
resolve_prompt(opt) click to toggle source
# File lib/redoxed/node.rb, line 140
def resolve_prompt(opt)
  opt[:prompt] || @model.prompt || Redoxed.config.prompt
end
resolve_repo(opt) click to toggle source
# File lib/redoxed/node.rb, line 177
def resolve_repo(opt)
  type = git_type opt
  return nil unless type

  remote_repo = Redoxed.config.output.send(type).repo
  if remote_repo.is_a?(::String)
    if Redoxed.config.output.send(type).single_repo? || @group.nil?
      remote_repo
    else
      File.join(File.dirname(remote_repo), @group + '.git')
    end
  else
    remote_repo[@group]
  end
end