class Hiera::Backend::Consul_backend
Public Class Methods
new()
click to toggle source
# File lib/hiera/backend/consul_backend.rb, line 6 def initialize() require 'net/http' require 'net/https' require 'json' @config = Config[:consul] if (@config[:host].nil? || @config[:port].nil?) raise "[hiera-consul]: Missing minimum configuration, please check hiera.yaml" end end
Public Instance Methods
lazy_connection_setup(scope)
click to toggle source
# File lib/hiera/backend/consul_backend.rb, line 16 def lazy_connection_setup(scope) if @consul.nil? @host = Backend.parse_string(@config[:host], scope) Hiera.debug("[hiera-consul]: Using host #{@host}") @consul = Net::HTTP.new(@host, @config[:port]) @consul.read_timeout = @config[:http_read_timeout] || 10 @consul.open_timeout = @config[:http_connect_timeout] || 10 @cache = {} if @config[:use_ssl] @consul.use_ssl = true if @config[:ssl_verify] == false @consul.verify_mode = OpenSSL::SSL::VERIFY_NONE else @consul.verify_mode = OpenSSL::SSL::VERIFY_PEER end if @config[:ssl_cert] store = OpenSSL::X509::Store.new store.add_cert(OpenSSL::X509::Certificate.new(File.read(@config[:ssl_ca_cert]))) @consul.cert_store = store @consul.key = OpenSSL::PKey::RSA.new(File.read(@config[:ssl_key])) @consul.cert = OpenSSL::X509::Certificate.new(File.read(@config[:ssl_cert])) end else @consul.use_ssl = false end build_cache! end end
lookup(key, scope, order_override, resolution_type)
click to toggle source
# File lib/hiera/backend/consul_backend.rb, line 49 def lookup(key, scope, order_override, resolution_type) if resolution_type == :array answer = [] elsif resolution_type == :hash answer = {} else answer = nil end begin lazy_connection_setup(scope) # Any failure to talk to consul results in the entire request failing. rescue Exception => e @consul=nil Hiera.debug("[hiera-consul]: Could not connect to Consul: #{e}") raise Exception, e.message unless @config[:failure] == 'graceful' return answer end begin paths = @config[:paths].map { |p| Backend.parse_string(p, scope, { 'key' => key }) } paths.insert(0, order_override) if order_override catch (:found) do paths.each do |path| Hiera.debug("[hiera-consul]: Checking path #{path}") # We only support querying the catalog or the kv store if path !~ /^\/v\d\/(catalog|kv)\// Hiera.debug("[hiera-consul]: We only support queries to catalog and kv and you asked #{path}, skipping") next end # Check that we are not looking somewhere that will make hiera crash subsequent lookups if "#{path}".match("//") Hiera.debug("[hiera-consul]: The specified path #{path}/#{key_delimited} is malformed, skipping") next end if path == 'services' if @cache.has_key?(key) answer = @cache[key] return answer end end #lookup fully qualified path [key, key.gsub('::', '/')].each do | key_delimited | this_answer = wrapquery("#{path}/#{key_delimited}") if resolution_type == :array answer = answer + this_answer unless ! this_answer elsif resolution_type == :hash answer = this_answer.merge(answer) unless ! this_answer #Earliest value takes precedence else #if resolution_type == :priority answer = this_answer throw :found if answer end end #lookup partial path plus yaml/json [key, key.gsub('::', '/')].each do | key_delimited | key_parts=key_delimited.split("/") Hiera.debug("[hiera-consul]: key_delimited is now #{key_delimited}") Hiera.debug("[hiera-consul]: key_parts is now #{key_parts}") # search most specific first hash_key_parts=[] while key_parts.size>0 do hash_key_parts = hash_key_parts + [key_parts.pop] key_reconstructed=key_parts.join('/') this_answer = wrapquery("#{path}/#{key_reconstructed}") hash_key_parts_copy = hash_key_parts while hash_key_parts_copy.size>0 do break unless this_answer.is_a? Hash this_answer=this_answer[hash_key_parts_copy[0]] hash_key_parts_copy.shift end next if this_answer.nil? next if hash_key_parts_copy.size>0 if resolution_type == :array answer = answer + this_answer unless ! this_answer elsif resolution_type == :hash answer = this_answer.merge(answer) unless ! this_answer #Earliest value takes precedence else #if resolution_type == :priority answer = this_answer throw :found if answer end end end #lookup base path plus yaml/json [key, key.gsub('::', '/')].each do | key_delimited | hash_key_parts=key_delimited.split("/") this_answer = wrapquery("#{path}") while hash_key_parts.size>0 do break unless this_answer.is_a? Hash this_answer=this_answer[hash_key_parts[0]] hash_key_parts.shift end next if this_answer.nil? next if hash_key_parts.size>0 if resolution_type == :array answer = answer + this_answer unless ! this_answer elsif resolution_type == :hash answer = this_answer.merge(answer) unless ! this_answer #Earliest value takes precedence else #if resolution_type == :priority answer = this_answer throw :found if answer end end Hiera.debug("[hiera-consul]: Answer is now #{answer}") end end # Any failure to talk to consul results in the entire request failing. rescue Exception => e Hiera.debug("[hiera-consul]: Could not connect to Consul: #{e}") raise Exception, e.message unless @config[:failure] == 'graceful' end answer end
parse_result(res)
click to toggle source
# File lib/hiera/backend/consul_backend.rb, line 167 def parse_result(res) require 'base64' answer = nil if res == "null" Hiera.debug("[hiera-consul]: Jumped as consul null is not valid") return answer end # Consul always returns an array res_array = JSON.parse(res) # See if we are a k/v return or a catalog return if res_array.length > 0 if res_array.first.include? 'Value' if res_array.first['Value'].nil? answer=nil else answer = Base64.decode64(res_array.first['Value']) end else answer = res_array end else Hiera.debug("[hiera-consul]: Jumped as array empty") end return answer end
Private Instance Methods
build_cache!()
click to toggle source
# File lib/hiera/backend/consul_backend.rb, line 245 def build_cache! services = wrapquery('/v1/catalog/services') return nil unless services.is_a? Hash services.each do |key, value| service = wrapquery("/v1/catalog/service/#{key}") next unless service.is_a? Array service.each do |node_hash| node = node_hash['Node'] node_hash.each do |property, value| # Value of a particular node next if property == 'ServiceID' unless property == 'Node' @cache["#{key}_#{property}_#{node}"] = value end unless @cache.has_key?("#{key}_#{property}") # Value of the first registered node @cache["#{key}_#{property}"] = value # Values of all nodes @cache["#{key}_#{property}_array"] = [value] else @cache["#{key}_#{property}_array"].push(value) end end end end Hiera.debug("[hiera-consul]: Cache #{@cache}") end
token(path)
click to toggle source
# File lib/hiera/backend/consul_backend.rb, line 195 def token(path) # Token is passed only when querying kv store if @config[:token] and path =~ /^\/v\d\/kv\// return "?token=#{@config[:token]}" else return nil end end
wrapquery(path)
click to toggle source
# File lib/hiera/backend/consul_backend.rb, line 204 def wrapquery(path) Hiera.debug("[hiera-consul]: Lookup #{path} on #{@host}:#{@config[:port]}") httpreq = Net::HTTP::Get.new("#{path}#{token(path)}") answer = nil # Exceptions will be caught at lookup level. result = @consul.request(httpreq) unless result.kind_of?(Net::HTTPSuccess) Hiera.debug("[hiera-consul]: HTTP response code was #{result.code}") return answer end answer = parse_result(result.body) Hiera.debug("[hiera-consul]: Answer from #{path} was #{answer}") success=false if @config[:autoconvert] if @config[:autoconvert].include? 'yaml' require 'yaml' begin answer = YAML.load(answer) Hiera.debug("[hiera-consul]: Answer was autoconverted as yaml") success=true rescue Exception Hiera.debug("[hiera-consul]: Answer was NOT autoconverted as yaml") end end if @config[:autoconvert].include? 'json' and ! success require 'json' begin answer = JSON.load(answer) Hiera.debug("[hiera-consul]: Answer was autoconverted as json") success=true rescue Exception Hiera.debug("[hiera-consul]: Answer was NOT autoconverted as json") end end end return answer end