Server IP : 66.29.132.122 / Your IP : 3.128.226.255 Web Server : LiteSpeed System : Linux business142.web-hosting.com 4.18.0-553.lve.el8.x86_64 #1 SMP Mon May 27 15:27:34 UTC 2024 x86_64 User : admazpex ( 531) PHP Version : 7.2.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /proc/self/root/proc/self/root/proc/thread-self/root/proc/thread-self/root/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/hiera/ |
Upload File : |
require 'hiera/util' require 'hiera/interpolate' begin require 'deep_merge/rails_compat' rescue LoadError end class Hiera module Backend class Backend1xWrapper def initialize(wrapped) @wrapped = wrapped end def lookup(key, scope, order_override, resolution_type, context) Hiera.debug("Using Hiera 1.x backend API to access instance of class #{@wrapped.class.name}. Lookup recursion will not be detected") value = @wrapped.lookup(key, scope, order_override, resolution_type.is_a?(Hash) ? :hash : resolution_type) # The most likely cause when an old backend returns nil is that the key was not found. In any case, it is # impossible to know the difference between that and a found nil. The throw here preserves the old behavior. throw (:no_such_key) if value.nil? value end end class << self # Data lives in /var/lib/hiera by default. If a backend # supplies a datadir in the config it will be used and # subject to variable expansion based on scope def datadir(backend, scope) backend = backend.to_sym if Config[backend] && Config[backend][:datadir] dir = Config[backend][:datadir] else dir = Hiera::Util.var_dir end if !dir.is_a?(String) raise(Hiera::InvalidConfigurationError, "datadir for #{backend} cannot be an array") end interpolate_config(dir, scope, nil) end # Finds the path to a datafile based on the Backend#datadir # and extension # # If the file is not found nil is returned def datafile(backend, scope, source, extension) datafile_in(datadir(backend, scope), source, extension) end # @api private def datafile_in(datadir, source, extension) file = File.join(datadir, "#{source}.#{extension}") if File.exist?(file) file else Hiera.debug("Cannot find datafile #{file}, skipping") nil end end # Constructs a list of data sources to search # # If you give it a specific hierarchy it will just use that # else it will use the global configured one, failing that # it will just look in the 'common' data source. # # An override can be supplied that will be pre-pended to the # hierarchy. # # The source names will be subject to variable expansion based # on scope def datasources(scope, override=nil, hierarchy=nil) if hierarchy hierarchy = [hierarchy] elsif Config.include?(:hierarchy) hierarchy = [Config[:hierarchy]].flatten else hierarchy = ["common"] end hierarchy.insert(0, override) if override hierarchy.flatten.map do |source| source = interpolate_config(source, scope, override) if source == "" or source =~ /(^\/|\/\/|\/$)/ Hiera.debug("Ignoring bad definition in :hierarchy: \'#{source}\'") else yield(source) end end end # Constructs a list of data files to search # # If you give it a specific hierarchy it will just use that # else it will use the global configured one, failing that # it will just look in the 'common' data source. # # An override can be supplied that will be pre-pended to the # hierarchy. # # The source names will be subject to variable expansion based # on scope # # Only files that exist will be returned. If the file is missing, then # the block will not receive the file. # # @yield [String, String] the source string and the name of the resulting file # @api public def datasourcefiles(backend, scope, extension, override=nil, hierarchy=nil) datadir = Backend.datadir(backend, scope) Backend.datasources(scope, override, hierarchy) do |source| Hiera.debug("Looking for data source #{source}") file = datafile_in(datadir, source, extension) if file yield source, file end end end # Parse a string like <code>'%{foo}'</code> against a supplied # scope and additional scope. If either scope or # extra_scope includes the variable 'foo', then it will # be replaced else an empty string will be placed. # # If both scope and extra_data has "foo", then the value in scope # will be used. # # @param data [String] The string to perform substitutions on. # This will not be modified, instead a new string will be returned. # @param scope [#[]] The primary source of data for substitutions. # @param extra_data [#[]] The secondary source of data for substitutions. # @param context [#[]] Context can include :recurse_guard and :order_override. # @return [String] A copy of the data with all instances of <code>%{...}</code> replaced. # # @api public def parse_string(data, scope, extra_data={}, context={:recurse_guard => nil, :order_override => nil}) Hiera::Interpolate.interpolate(data, scope, extra_data, context) end # Parses a answer received from data files # # Ultimately it just pass the data through parse_string but # it makes some effort to handle arrays of strings as well def parse_answer(data, scope, extra_data={}, context={:recurse_guard => nil, :order_override => nil}) 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, extra_data, context) elsif data.is_a?(Hash) answer = {} data.each_pair do |key, val| interpolated_key = parse_string(key, scope, extra_data, context) answer[interpolated_key] = parse_answer(val, scope, extra_data, context) end return answer elsif data.is_a?(Array) answer = [] data.each do |item| answer << parse_answer(item, scope, extra_data, context) end return answer end end def resolve_answer(answer, resolution_type) case resolution_type when :array [answer].flatten.uniq.compact when :hash answer # Hash structure should be preserved else answer end end # Merges two hashes answers with the given or configured merge behavior. Behavior can be given # by passing _resolution_type_ as a Hash # # :merge_behavior: {:native|:deep|:deeper} # # Deep merge options use the Hash utility function provided by [deep_merge](https://github.com/danielsdeleo/deep_merge) # It uses the compatibility mode [deep_merge](https://github.com/danielsdeleo/deep_merge#using-deep_merge-in-rails) # # :native => Native Hash.merge # :deep => Use Hash.deeper_merge # :deeper => Use Hash.deeper_merge! # # @param left [Hash] left side of the merge # @param right [Hash] right side of the merge # @param resolution_type [String,Hash] The merge type, or if hash, the merge behavior and options # @return [Hash] The merged result # @see Hiera#lookup # def merge_answer(left,right,resolution_type=nil) behavior, options = if resolution_type.is_a?(Hash) merge = resolution_type.clone [merge.delete(:behavior), merge] else [Config[:merge_behavior], Config[:deep_merge_options] || {}] end case behavior when :deeper,'deeper' left.deeper_merge!(right, options) when :deep,'deep' left.deeper_merge(right, options) else # Native and undefined left.merge(right) end end # Calls out to all configured backends in the order they # were specified. The first one to answer will win. # # This lets you declare multiple backends, a possible # use case might be in Puppet where a Puppet module declares # default data using in-module data while users can override # using JSON/YAML etc. By layering the backends and putting # the Puppet one last you can override module author data # easily. # # Backend instances are cached so if you need to connect to any # databases then do so in your constructor, future calls to your # backend will not create new instances # @param key [String] The key to lookup. May be quoted with single or double quotes to avoid subkey traversal on dot characters # @param scope [#[]] The primary source of data for substitutions. # @param order_override [#[],nil] An override that will be pre-pended to the hierarchy definition. # @param resolution_type [Symbol,Hash,nil] One of :hash, :array,:priority or a Hash with deep merge behavior and options # @param context [#[]] Context used for internal processing # @return [Object] The value that corresponds to the given key or nil if no such value cannot be found # def lookup(key, default, scope, order_override, resolution_type, context = {:recurse_guard => nil}) @backends ||= {} answer = nil # order_override is kept as an explicit argument for backwards compatibility, but should be specified # in the context for internal handling. context ||= {} order_override ||= context[:order_override] context[:order_override] ||= order_override strategy = resolution_type.is_a?(Hash) ? :hash : resolution_type segments = Util.split_key(key) { |problem| ArgumentError.new("#{problem} in key: #{key}") } subsegments = nil if segments.size > 1 unless strategy.nil? || strategy == :priority raise ArgumentError, "Resolution type :#{strategy} is illegal when accessing values using dotted keys. Offending key was '#{key}'" end subsegments = segments.drop(1) end found = false Config[:backends].each do |backend| backend_constant = "#{backend.capitalize}_backend" if constants.include?(backend_constant) || constants.include?(backend_constant.to_sym) backend = (@backends[backend] ||= find_backend(backend_constant)) found_in_backend = false new_answer = catch(:no_such_key) do if subsegments.nil? value = backend.lookup(segments[0], scope, order_override, resolution_type, context) elsif backend.respond_to?(:lookup_with_segments) value = backend.lookup_with_segments(segments, scope, order_override, resolution_type, context) else value = backend.lookup(segments[0], scope, order_override, resolution_type, context) value = qualified_lookup(subsegments, value, key) unless subsegments.nil? end found_in_backend = true value end next unless found_in_backend found = true case strategy when :array raise Exception, "Hiera type mismatch for key '#{key}': 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 for key '#{key}': expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash answer ||= {} answer = merge_answer(new_answer, answer, resolution_type) else answer = new_answer break end end end answer = resolve_answer(answer, strategy) unless answer.nil? answer = parse_string(default, scope, {}, context) if !found && default.is_a?(String) return default if !found && answer.nil? return answer end def clear! @backends = {} end def qualified_lookup(segments, hash, full_key = nil) value = hash segments.each do |segment| throw :no_such_key if value.nil? if segment =~ /^[0-9]+$/ segment = segment.to_i unless value.instance_of?(Array) suffix = full_key.nil? ? '' : " from key '#{full_key}'" raise Exception, "Hiera type mismatch: Got #{value.class.name} when Array was expected to access value using '#{segment}'#{suffix}" end throw :no_such_key unless segment < value.size else unless value.respond_to?(:'[]') && !(value.instance_of?(Array) || value.instance_of?(String)) suffix = full_key.nil? ? '' : " from key '#{full_key}'" raise Exception, "Hiera type mismatch: Got #{value.class.name} when a hash-like object was expected to access value using '#{segment}'#{suffix}" end throw :no_such_key unless value.include?(segment) end value = value[segment] end value end def find_backend(backend_constant) backend = Backend.const_get(backend_constant).new return backend.method(:lookup).arity == 4 ? Backend1xWrapper.new(backend) : backend end private :find_backend def interpolate_config(entry, scope, override) if @config_lookup_context.nil? @config_lookup_context = { :is_interpolate_config => true, :order_override => override, :recurse_guard => Hiera::RecursiveGuard.new } begin Hiera::Interpolate.interpolate(entry, scope, {}, @config_lookup_context) ensure @config_lookup_context = nil end else # Nested call (will happen when interpolate method 'hiera' is used) Hiera::Interpolate.interpolate(entry, scope, {}, @config_lookup_context.merge(:order_override => override)) end end end end end