class Etcenv::Environment

Constants

INCLUDE_KEY
MAX_DEPTH_DEFAULT

Attributes

cluster_index[R]
env[R]
etcd[R]
max_depth[RW]
root_key[R]

Public Class Methods

new(etcd, root_key, max_depth: MAX_DEPTH_DEFAULT) click to toggle source
# File lib/etcenv/environment.rb, line 16
def initialize(etcd, root_key, max_depth: MAX_DEPTH_DEFAULT)
  @etcd = etcd
  @root_key = root_key
  @max_depth = max_depth
  @lock = Mutex.new
  load
end

Public Instance Methods

expanded_env() click to toggle source
# File lib/etcenv/environment.rb, line 27
def expanded_env
  VariableExpander.expand(env)
end
keys() click to toggle source
# File lib/etcenv/environment.rb, line 35
def keys
  modified_indices.keys
end
load() click to toggle source
# File lib/etcenv/environment.rb, line 39
def load
  @lock.synchronize do
    flush
    env = {}
    includes.each do |name|
      env.merge! fetch(name)
    end
    env.delete '.include'
    @env = env
  end
  self
end
modified_indices() click to toggle source
# File lib/etcenv/environment.rb, line 31
def modified_indices
  @modified_indices ||= {}
end

Private Instance Methods

cache() click to toggle source
# File lib/etcenv/environment.rb, line 79
def cache
  @cache ||= {}
end
default_prefix() click to toggle source
# File lib/etcenv/environment.rb, line 67
def default_prefix
  root_key.sub(/^(.*)\/.+?$/, '\1')
end
fetch(name) click to toggle source
# File lib/etcenv/environment.rb, line 83
def fetch(name)
  key = resolve_key(name)
  return cache[key] if cache[key]

  resp = @etcd.get(key)
  node = resp.node
  @cluster_index = [@cluster_index, resp.etcd_index].compact.min

  if node.etcvault_error
    raise EtcvaultFailure, node.etcvault_error
  end

  if node.dir
    dir = {}
    index = 0

    node.children.each do |child|
      name = child.key.sub(/^.*\//, '')

      index = [index, child.modified_index].max
      if child.dir
        next
      else
        dir[name] = child.value
        if child.etcvault_error
          raise EtcvaultFailure, child.etcvault_error
        end
      end
    end
  else
    dir = {key.sub(/^.*\//, '') => node.value}
    index = node.modified_index
  end

  modified_indices[key] = index
  cache[key] = dir
rescue Etcd::KeyNotFound
  raise KeyNotFound, "Couldn't find key #{key}"
end
flush() click to toggle source
# File lib/etcenv/environment.rb, line 54
def flush
  @env = {}
  @includes = nil
  @cache = {}
  @modified_indices = {}
  @cluster_index = nil
  self
end
includes() click to toggle source
# File lib/etcenv/environment.rb, line 63
def includes
  @includes ||= solve_include_order(root_key)
end
resolve_key(key) click to toggle source
# File lib/etcenv/environment.rb, line 71
def resolve_key(key)
  if key.start_with?('/')
    key
  else
    default_prefix + '/' + key
  end
end
solve_include_order(name, path = []) click to toggle source
# File lib/etcenv/environment.rb, line 123
def solve_include_order(name, path = [])
  if path.include?(name)
    raise LoopError, "Found an include loop at path: #{path.inspect}"
  end

  path = path + [name]
  if max_depth < path.size
    raise DepthLimitError, "Reached maximum depth (path: #{path.inspect})"
  end

  node = fetch(name)

  if node[INCLUDE_KEY]
    node[INCLUDE_KEY].split(/,\s*/).flat_map do |x|
      solve_include_order(x, path)
    end + [name]
  else
    [name]
  end
end