class Flor::Ganger

ganger | ˈɡaNGər | \ noun British \ the foreman of a gang of laborers.

The ganger receives the tasks from the flor executor, decides what tasker will be invoked and hands it the task.

Attributes

unit[R]

RESERVED_NAMES = %w[ tag ]

Public Class Methods

new(unit) click to toggle source
# File lib/flor/unit/ganger.rb, line 18
def initialize(unit)

  @unit = unit
end

Public Instance Methods

has_tasker?(exid, name) click to toggle source

Used by flor when it looks up for a variable and finds nothing. The last step is to ask the ganger if it knows about a tasker under the given (domain and) name.

If it returns true, flor knows there is a tasker under that name.

# File lib/flor/unit/ganger.rb, line 32
def has_tasker?(exid, name)

  #return false if RESERVED_NAMES.include?(name)

  d = Flor.domain(exid)

  !! (
    @unit.loader.tasker(d, 'ganger') ||
    @unit.loader.tasker(d, 'tasker') ||
    @unit.loader.tasker(d, name))
end
return(message) click to toggle source

Called by the tasker implementations when they’re done with a task and want to hand it back to flor. It might be a failure message.

# File lib/flor/unit/ganger.rb, line 95
def return(message)

  @unit.return(message)
end
shutdown() click to toggle source
# File lib/flor/unit/ganger.rb, line 23
def shutdown
end
task(executor, message) click to toggle source

Called by Flor::Scheduler. The ganger then has to hand the task (the message) to the proper tasker.

# File lib/flor/unit/ganger.rb, line 47
def task(executor, message)

  domain = message['exid'].split('-', 2).first
  #tname = message['tasker']
  tname = determine_tasker_name(executor, message)

  tconf =
    ( ! message['routed'] &&
     (@unit.loader.tasker(domain, 'ganger', message) ||
      @unit.loader.tasker(domain, 'tasker', message))) ||
    @unit.loader.tasker(domain, tname, message)

  fail ArgumentError.new(
    "tasker #{tname.inspect} not found"
  ) unless tconf

  if tconf.is_a?(Array)

    points = [ nil, message['point'] ]
    points << 'detask' if points.include?('cancel')
    points << 'task' if points.include?('return')

    tconf = tconf.find { |h| points.include?(h['point']) }
  end

  fail ArgumentError.new(
    "tconf #{tconf.inspect} not a hash"
  ) unless tconf.is_a?(Hash)

  message['tconf'] = tconf unless tconf['include_tconf'] == false

  message['vars'] = gather_vars(executor, tconf, message)

  m = Flor.dup_message(message)
    #
    # the tasker gets a copy of the message (and it can play with it
    # to its heart content), meanwhile the message is handed to the
    # "post" notifiers.

  @unit.caller.call(self, tconf, m)
    #
    # might return a re-routing message,
    # especially if it's a domain tasker
end

Protected Instance Methods

determine_tasker_name(executor, message) click to toggle source
# File lib/flor/unit/ganger.rb, line 157
def determine_tasker_name(executor, message)

  tname = message['tasker']

  return tname if tname

  n = executor.node(message)

  n['task']['tasker']
end
expand_filter(f) click to toggle source
# File lib/flor/unit/ganger.rb, line 108
def expand_filter(f)

  return f unless f.is_a?(Array)

  f.collect { |e|
    if e.is_a?(String)
      e
    elsif e.is_a?(Array) && e[0] == '_rxs' && e[1].is_a?(String)

      s = e[1]
      li, ri = s.index('/'), s.rindex('/')
      tail = s[ri + 1..-1]
      ops =
        (tail.index('i') ? Regexp::IGNORECASE : 0) |
        (tail.index('x') ? Regexp::EXTENDED : 0)
      Regexp.new(s[li + 1..ri - 1], ops)
    else
      nil
    end
  }.compact
end
gather_vars(executor, tconf, message) click to toggle source

By default, taskers don’t see the flor variables in the execution. If ‘include_vars’ or ‘exclude_vars’ is present in the configuration of the tasker, some or all of the variables are passed.

# File lib/flor/unit/ganger.rb, line 134
def gather_vars(executor, tconf, message)

  # try to return before a potentially costly call to executor.vars(nid)

  return nil if (tconf.keys & %w[ include_vars exclude_vars ]).empty?
    # default behaviour, don't pass variables to taskers

  iv = expand_filter(tconf['include_vars'])
  return nil if iv == false

  ev = expand_filter(tconf['exclude_vars'])
  return {} if ev == true

  vars = executor.vars(message['nid'])

  return vars if iv == true

  vars = vars.select { |k, v| var_match(k, iv) } if iv
  vars = vars.reject { |k, v| var_match(k, ev) } if ev

  vars
end
var_match(k, filter) click to toggle source
# File lib/flor/unit/ganger.rb, line 102
def var_match(k, filter)

  filter.each { |f| return true if (f.is_a?(String) ? k == f : f.match(k)) }
  false
end