class Hiera::Backend::Router_backend

Attributes

backends[R]
config[RW]

Public Class Methods

new(cache = nil) click to toggle source
# File lib/hiera/backend/router_backend.rb, line 22
def initialize(cache = nil)
  @cache = cache || Filecache.new
  @backends = {}
  Hiera.debug("[hiera-router] I'm here!")
  self.config = Config.config
  self.config[:hierarchy] = Config[:router][:paths] if Config[:router][:paths]

  if backend_list = Config[:router][:backends]
    Hiera.debug("[hiera-router] Initializing backends: #{backend_list.keys.join(',')}")
    backend_list.each do |backend, backend_config|
      Hiera.debug("[hiera-router] Initializing backend '#{backend}'")
      backend_classname = backend_config['backend_class'] || backend_config[:backend_class] || backend
      full_backend_classname = "#{backend_classname.capitalize}_backend"
      backend_config_override = backend_config['backend_key'] || backend_config[:backend_key] || backend_classname
      Hiera.debug("[hiera-router] Backend class for '#{backend}' will be '#{backend_classname}'")

      backend_config_override_config = Config[backend_config_override.to_sym] || Config[:router][backend_config_override.to_sym] || {}

      backend_config = self.config.clone
      backend_config.delete(:router)
      if backend_config_override_config[:hierarchy]
        backend_config[:hierarchy] = backend_config_override_config[:hierarchy]
      end

      backend_config[:backends] = [backend_classname]
      backend_config[backend_classname.to_sym] = backend_config_override_config
      backend_config = symbolize_keys(backend_config)

      Config.load(backend_config)
      require "hiera/backend/#{full_backend_classname.downcase}"
      backend_inst = Hiera::Backend.const_get(full_backend_classname).new
      Config.load(config)
      @backends[backend.to_sym] = {
        :instance => backend_inst,
        :config => backend_config,
      }
    end
  end

  Hiera.debug("[hiera-router] hiera router initialized")
end

Public Instance Methods

lookup(lookup_key, scope, order_override, resolution_type) click to toggle source
# File lib/hiera/backend/router_backend.rb, line 63
def lookup(lookup_key, scope, order_override, resolution_type)
  options = {
    :scope => scope,
    :key => lookup_key,
    :order_override => order_override,
    :resolution_type => resolution_type,
  }

  key_path = Util.split_key(lookup_key)
  key = key_path.shift

  answer = nil
  strategy = resolution_type.is_a?(Hash) ? :hash : resolution_type

  Hiera.debug("[hiera-router] Looking up #{key} in yaml backend (and then return path #{key_path.inspect})")

  Backend.datasources(scope, order_override) do |source|
    yaml_file = Backend.datafile(:router, scope, source, 'yaml') || next

    data = @cache.read(yaml_file, Hash) do |cached_data|
      begin
        Hiera.debug("[hiera-router] Looking + loading data source #{source} ('#{yaml_file}')")
        YAML.load(cached_data) || {}
      rescue
        Hiera.debug("[hiera-router] something wrong with source #{source} '#{yaml_file}' -- returning an empty result")
        {}
      end
    end

    next if data.empty?
    next unless data.include?(key)

    Hiera.debug("[hiera-router] Found #{key} in #{source}")

    new_answer = parse_answer(data[key], scope, options)
    next if new_answer.nil?

    case strategy
    when :array
      raise Exception, "Hiera type mismatch: expected Array and got #{new_answer.class}" unless new_answer.kind_of? Array or new_answer.kind_of? String
      answer ||= []
      answer << new_answer
    when :hash
      raise Exception, "Hiera type mismatch: expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash
      answer ||= {}
      answer = Backend.merge_answer(new_answer, answer, resolution_type)
    else
      answer = new_answer
      break
    end
  end

  while e = key_path.shift
    break unless answer
    raise Exception, "Hiera subkey '#{e}' not found" unless answer.include?(e)
    answer = answer[e]
  end

  answer = Backend.resolve_answer(answer, strategy) unless answer.nil?

  return answer
end
parse_answer(data, scope, options, path = []) click to toggle source
# File lib/hiera/backend/router_backend.rb, line 139
def parse_answer(data, scope, options, path = [])
  if data.is_a?(Numeric) or data.is_a?(TrueClass) or data.is_a?(FalseClass)
    return data
  elsif data.is_a?(String)
    return parse_string(data, scope, options, path)
  elsif data.is_a?(Hash)
    answer = {}
    data.each_pair do |key, val|
      interpolated_key = Backend.parse_string(key, scope)
      subpath = path + [interpolated_key]
      answer[interpolated_key] = parse_answer(val, scope, options, subpath)
    end

    return answer
  elsif data.is_a?(Array)
    answer = []
    data.each do |item|
      answer << parse_answer(item, scope, options)
    end

    return answer
  end
end
parse_string(data, scope, options, path = []) click to toggle source
# File lib/hiera/backend/router_backend.rb, line 163
def parse_string(data, scope, options, path = [])
  if match = data.match(/^backend\[([^,]+)(?:,(.*))?\]$/)
    backend_name, backend_parameters = match.captures
    backend_options = options
    backend_options = backend_options.merge(backend_parameters) if backend_parameters
    Hiera.debug("[hiera-router] Calling hiera with '#{backend_name}'...")
    if backend = self.backends[backend_name.to_sym]
      backend_instance = backend[:instance]
      key = Util.split_key(backend_options[:key]).first
      Hiera.debug("[hiera-router] Backend class: #{backend_instance.class.name}")
      Config.load(backend[:config])
      result = backend_instance.lookup(key, backend_options[:scope], nil, backend_options[:resolution_type])
      Config.load(self.config)
    else
      Hiera.warn "Backend '#{backend_name}' was not configured; returning the data as-is."
      result = data
    end
    Hiera.debug("[hiera-router] Call to '#{backend_name}' finished.")
    return recursive_key_from_hash(result, path)
  else
    Backend.parse_string(data, scope)
  end
end
recursive_key_from_hash(hash, path) click to toggle source
# File lib/hiera/backend/router_backend.rb, line 126
def recursive_key_from_hash(hash, path)
  focus = hash
  path.each do |key|
    if focus.is_a?(Hash) and focus.include?(key)
      focus = focus[key]
    else
      return nil
    end
  end

  return focus
end
symbolize_keys(hash) click to toggle source
# File lib/hiera/backend/router_backend.rb, line 18
def symbolize_keys(hash)
  hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v }
end