class Puppet::Pops::Lookup::HieraConfig
@api private
Constants
- ALL_FUNCTION_KEYS
- CONFIG_FILE_NAME
- FUNCTION_KEYS
- FUNCTION_PROVIDERS
- KEY_BACKEND
- KEY_DATADIR
- KEY_DATA_DIG
- KEY_DATA_HASH
- KEY_DEFAULTS
- KEY_DEFAULT_HIERARCHY
- KEY_EXTENSION
- KEY_GLOB
- KEY_GLOBS
- KEY_HIERARCHY
- KEY_LOGGER
- KEY_LOOKUP_KEY
- KEY_MAPPED_PATHS
- KEY_NAME
- KEY_OPTIONS
- KEY_PATH
- KEY_PATHS
- KEY_PLAN_HIERARCHY
- KEY_URI
- KEY_URIS
- KEY_V3_BACKEND
- KEY_V3_DATA_HASH
- KEY_V3_LOOKUP_KEY
- KEY_V4_DATA_HASH
- KEY_VERSION
- LOCATION_KEYS
Attributes
Public Class Methods
# File lib/puppet/pops/lookup/hiera_config.rb 102 def self.config_exist?(config_root) 103 config_path = config_root + CONFIG_FILE_NAME 104 config_path.exist? 105 end
Creates a new HieraConfig
from the given config_root. This is where the 'hiera.yaml' is expected to be found and is also the base location used when resolving relative paths.
@param lookup_invocation [Invocation] Invocation
data containing scope, overrides, and defaults @param config_path
[Pathname] Absolute path to the configuration file @param owner [ConfiguredDataProvider] The data provider that will own the created configuration @return [LookupConfiguration] the configuration
# File lib/puppet/pops/lookup/hiera_config.rb 127 def self.create(lookup_invocation, config_path, owner) 128 if config_path.is_a?(Hash) 129 config_path = nil 130 loaded_config = config_path 131 else 132 config_root = config_path.parent 133 if config_path.exist? 134 env_context = EnvironmentContext.adapt(lookup_invocation.scope.compiler.environment) 135 loaded_config = env_context.cached_file_data(config_path) do |content| 136 parsed = Puppet::Util::Yaml.safe_load(content, [Symbol], config_path) 137 138 # For backward compatibility, we must treat an empty file, or a yaml that doesn't 139 # produce a Hash as Hiera version 3 default. 140 if parsed.is_a?(Hash) 141 parsed 142 else 143 Puppet.warning(_("%{config_path}: File exists but does not contain a valid YAML hash. Falling back to Hiera version 3 default config") % { config_path: config_path }) 144 HieraConfigV3::DEFAULT_CONFIG_HASH 145 end 146 end 147 else 148 config_path = nil 149 loaded_config = HieraConfigV5::DEFAULT_CONFIG_HASH 150 end 151 end 152 153 version = loaded_config[KEY_VERSION] || loaded_config[:version] 154 version = version.nil? ? 3 : version.to_i 155 case version 156 when 5 157 HieraConfigV5.new(config_root, config_path, loaded_config, owner) 158 when 4 159 HieraConfigV4.new(config_root, config_path, loaded_config, owner) 160 when 3 161 HieraConfigV3.new(config_root, config_path, loaded_config, owner) 162 else 163 issue = Issues::HIERA_UNSUPPORTED_VERSION 164 raise Puppet::DataBinding::LookupError.new( 165 issue.format(:version => version), config_path, nil, nil, nil, issue.issue_code) 166 end 167 end
Creates a new HieraConfig
from the given config_root. This is where the 'lookup.yaml' is expected to be found and is also the base location used when resolving relative paths.
@param config_path
[Pathname] Absolute path to the configuration @param loaded_config [Hash] the loaded configuration
# File lib/puppet/pops/lookup/hiera_config.rb 176 def initialize(config_root, config_path, loaded_config, owner) 177 @config_root = config_root 178 @config_path = config_path 179 @loaded_config = loaded_config 180 @config = validate_config(self.class.symkeys_to_string(@loaded_config), owner) 181 @data_providers = nil 182 end
# File lib/puppet/pops/lookup/hiera_config.rb 107 def self.symkeys_to_string(struct) 108 case(struct) 109 when Hash 110 map = {} 111 struct.each_pair {|k,v| map[ k.is_a?(Symbol) ? k.to_s : k] = symkeys_to_string(v) } 112 map 113 when Array 114 struct.map { |v| symkeys_to_string(v) } 115 else 116 struct 117 end 118 end
# File lib/puppet/pops/lookup/hiera_config.rb 83 def self.v4_function_config(config_root, function_name, owner) 84 unless Puppet[:strict] == :off 85 Puppet.warn_once('deprecations', 'legacy_provider_function', 86 _("Using of legacy data provider function '%{function_name}'. Please convert to a 'data_hash' function") % { function_name: function_name }) 87 end 88 HieraConfigV5.new(config_root, nil, 89 { 90 KEY_VERSION => 5, 91 KEY_HIERARCHY => [ 92 { 93 KEY_NAME => "Legacy function '#{function_name}'", 94 KEY_V4_DATA_HASH => function_name 95 } 96 ] 97 }.freeze, 98 owner 99 ) 100 end
Private Class Methods
# File lib/puppet/pops/lookup/hiera_config.rb 340 def self.not_implemented(impl, method_name) 341 raise NotImplementedError, "The class #{impl.class.name} should have implemented the method #{method_name}()" 342 end
Public Instance Methods
Returns the data providers for this config
@param lookup_invocation [Invocation] Invocation
data containing scope, overrides, and defaults @param parent_data_provider [DataProvider] The data provider that loaded this configuration @return [Array<DataProvider>] the data providers
# File lib/puppet/pops/lookup/hiera_config.rb 198 def configured_data_providers(lookup_invocation, parent_data_provider, use_default_hierarchy = false) 199 unless @data_providers && scope_interpolations_stable?(lookup_invocation) 200 if @data_providers 201 lookup_invocation.report_text { _('Hiera configuration recreated due to change of scope variables used in interpolation expressions') } 202 end 203 slc_invocation = ScopeLookupCollectingInvocation.new(lookup_invocation.scope) 204 begin 205 @data_providers = create_configured_data_providers(slc_invocation, parent_data_provider, false) 206 if has_default_hierarchy? 207 @default_data_providers = create_configured_data_providers(slc_invocation, parent_data_provider, true) 208 end 209 rescue StandardError => e 210 # Raise a LookupError with a RUNTIME_ERROR issue to prevent this being translated to an evaluation error triggered in the pp file 211 # where the lookup started 212 if e.message =~ /^Undefined variable '([^']+)'/ 213 var = $1 214 fail(Issues::HIERA_UNDEFINED_VARIABLE, { :name => var }, find_line_matching(/%\{['"]?#{var}['"]?}/)) 215 end 216 raise e 217 end 218 @scope_interpolations = slc_invocation.scope_interpolations 219 end 220 use_default_hierarchy ? @default_data_providers : @data_providers 221 end
@api private
# File lib/puppet/pops/lookup/hiera_config.rb 268 def create_configured_data_providers(lookup_invocation, parent_data_provider, use_default_hierarchy) 269 self.class.not_implemented(self, 'create_configured_data_providers') 270 end
# File lib/puppet/pops/lookup/hiera_config.rb 284 def create_hiera3_backend_provider(name, backend, parent_data_provider, datadir, paths, hiera3_config) 285 # Custom backend. Hiera v3 must be installed, it's logger configured, and it must be made aware of the loaded config 286 require 'hiera' 287 if Hiera::Config.instance_variable_defined?(:@config) && (current_config = Hiera::Config.instance_variable_get(:@config)).is_a?(Hash) 288 current_config.each_pair do |key, val| 289 case key 290 when :hierarchy, :backends 291 hiera3_config[key] = ([val] + [hiera3_config[key]]).flatten.uniq 292 else 293 hiera3_config[key] = val 294 end 295 end 296 else 297 if hiera3_config.include?(KEY_LOGGER) 298 Hiera.logger = hiera3_config[KEY_LOGGER].to_s 299 else 300 Hiera.logger = 'puppet' 301 end 302 end 303 304 unless Hiera::Interpolate.const_defined?(:PATCHED_BY_HIERA_5) 305 # Replace the class methods 'hiera_interpolate' and 'alias_interpolate' with a method that wires back and performs global 306 # lookups using the lookup framework. This is necessary since the classic Hiera is made aware only of custom backends. 307 class << Hiera::Interpolate 308 hiera_interpolate = Proc.new do |data, key, scope, extra_data, context| 309 override = context[:order_override] 310 invocation = Puppet::Pops::Lookup::Invocation.current 311 unless override.nil? && invocation.global_only? 312 invocation = Puppet::Pops::Lookup::Invocation.new(scope) 313 invocation.set_global_only 314 invocation.set_hiera_v3_location_overrides(override) unless override.nil? 315 end 316 Puppet::Pops::Lookup::LookupAdapter.adapt(scope.compiler).lookup(key, invocation, nil) 317 end 318 319 send(:remove_method, :hiera_interpolate) 320 send(:remove_method, :alias_interpolate) 321 send(:define_method, :hiera_interpolate, hiera_interpolate) 322 send(:define_method, :alias_interpolate, hiera_interpolate) 323 end 324 Hiera::Interpolate.send(:const_set, :PATCHED_BY_HIERA_5, true) 325 end 326 327 Hiera::Config.instance_variable_set(:@config, hiera3_config) 328 329 # Use a special lookup_key that delegates to the backend 330 paths = nil if !paths.nil? && paths.empty? 331 create_data_provider(name, parent_data_provider, KEY_V3_BACKEND, 'hiera_v3_data', { KEY_DATADIR => datadir, KEY_BACKEND => backend }, paths) 332 end
# File lib/puppet/pops/lookup/hiera_config.rb 184 def fail(issue, args = EMPTY_HASH, line = nil) 185 raise Puppet::DataBinding::LookupError.new( 186 issue.format(args.merge(:label => self)), @config_path, line, nil, nil, issue.issue_code) 187 end
Find first line in configuration that matches regexp after given line. Comments are stripped
# File lib/puppet/pops/lookup/hiera_config.rb 224 def find_line_matching(regexp, start_line = 1) 225 line_number = 0 226 File.foreach(@config_path) do |line| 227 line_number += 1 228 next if line_number < start_line 229 quote = nil 230 stripped = '' 231 line.each_codepoint do |cp| 232 if cp == 0x22 || cp == 0x27 # double or single quote 233 if quote == cp 234 quote = nil 235 elsif quote.nil? 236 quote = cp 237 end 238 elsif cp == 0x23 # unquoted hash mark 239 break 240 end 241 stripped << cp 242 end 243 return line_number if stripped =~ regexp 244 end 245 nil 246 end
# File lib/puppet/pops/lookup/hiera_config.rb 189 def has_default_hierarchy? 190 false 191 end
# File lib/puppet/pops/lookup/hiera_config.rb 280 def name 281 "hiera configuration version #{version}" 282 end
# File lib/puppet/pops/lookup/hiera_config.rb 248 def scope_interpolations_stable?(lookup_invocation) 249 if @scope_interpolations.empty? 250 true 251 else 252 scope = lookup_invocation.scope 253 lookup_invocation.without_explain do 254 @scope_interpolations.all? do |key, root_key, segments, old_value| 255 value = scope[root_key] 256 unless value.nil? || segments.empty? 257 found = nil; 258 catch(:no_such_key) { found = sub_lookup(key, lookup_invocation, segments, value) } 259 value = found; 260 end 261 old_value.eql?(value) 262 end 263 end 264 end 265 end
# File lib/puppet/pops/lookup/hiera_config.rb 272 def validate_config(config, owner) 273 self.class.not_implemented(self, 'validate_config') 274 end
Private Instance Methods
# File lib/puppet/pops/lookup/hiera_config.rb 336 def create_data_provider(name, parent_data_provider, function_kind, function_name, options, locations) 337 FUNCTION_PROVIDERS[function_kind].new(name, parent_data_provider, function_name, options, locations) 338 end