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