Class: Puppet::Pops::Lookup::LookupAdapter Private

Inherits:
DataAdapter show all
Defined in:
lib/puppet/pops/lookup/lookup_adapter.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

A LookupAdapter is a specialized DataAdapter that uses its hash to store data providers. It also remembers the compiler that it is attached to and maintains a cache of _lookup options_ retrieved from the data providers associated with the compiler's environment.

Constant Summary collapse

LOOKUP_OPTIONS_PREFIX =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

LOOKUP_OPTIONS + '.'
LOOKUP_OPTIONS_PATTERN_START =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

'^'.freeze
HASH =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

'hash'.freeze
MERGE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

'merge'.freeze
CONVERT_TO =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

'convert_to'.freeze
NEW =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

'new'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from DataAdapter

#[], #[]=, #include?

Methods inherited from Adaptable::Adapter

adapt, adapt_new, associate_adapter, clear, get, instance_var_name, self_attr_name, type_name

Constructor Details

#initialize(compiler) ⇒ LookupAdapter

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of LookupAdapter


26
27
28
29
30
31
32
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 26

def initialize(compiler)
  super()
  @compiler = compiler
  @lookup_options = {}
  # Get a KeyRecorder from context, and set a "null recorder" if not defined
  @key_recorder = Puppet.lookup(:lookup_key_recorder) { KeyRecorder.singleton }
end

Class Method Details

.create_adapter(compiler) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


22
23
24
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 22

def self.create_adapter(compiler)
  new(compiler)
end

Instance Method Details

#convert_result(key, lookup_options, lookup_invocation, the_lookup) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Performs a possible conversion of the result of calling `the_lookup` lambda The conversion takes place if there is a 'convert_to' key in the lookup_options If there is no conversion, the result of calling `the_lookup` is returned otherwise the successfully converted value. Errors are raised if the convert_to is faulty (bad type string, or if a call to new(T, <args>) fails.


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 97

def convert_result(key, lookup_options, lookup_invocation, the_lookup)
  result = the_lookup.call
  convert_to = lookup_options[CONVERT_TO]
  return result if convert_to.nil?

  convert_to = convert_to.is_a?(Array) ? convert_to : [convert_to]
  if convert_to[0].is_a?(String)
    begin
      convert_to[0] = Puppet::Pops::Types::TypeParser.singleton.parse(convert_to[0])
    rescue StandardError => e
      raise Puppet::DataBinding::LookupError,
        _("Invalid data type in lookup_options for key '%{key}' could not parse '%{source}', error: '%{msg}") %
          { key: key, source: convert_to[0], msg: e.message}
    end
  end
  begin
    result = lookup_invocation.scope.call_function(NEW, [convert_to[0], result, *convert_to[1..-1]])
    # TRANSLATORS 'lookup_options', 'convert_to' and args_string variable should not be translated,
    args_string = Puppet::Pops::Types::StringConverter.singleton.convert(convert_to)
    lookup_invocation.report_text { _("Applying convert_to lookup_option with arguments %{args}") % { args: args_string } }
  rescue StandardError => e
    raise Puppet::DataBinding::LookupError,
      _("The convert_to lookup_option for key '%{key}' raised error: %{msg}") %
        { key: key, msg: e.message}
  end
  result
end

#extract_lookup_options_for_key(key, options) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 245

def extract_lookup_options_for_key(key, options)
  return nil if options.nil?

  rk = key.root_key
  key_opts = options[0]
  unless key_opts.nil?
    key_opt = key_opts[rk]
    return key_opt unless key_opt.nil?
  end

  patterns = options[1]
  patterns.each_pair { |pattern, value| return value if pattern =~ rk } unless patterns.nil?
  nil
end

#global_hiera_config_pathPathname

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the full path of the hiera.yaml config file


268
269
270
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 268

def global_hiera_config_path
  @global_hiera_config_path ||= Pathname.new(Puppet.settings[:hiera_config])
end

#global_only?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


279
280
281
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 279

def global_only?
  instance_variable_defined?(:@global_only) ? @global_only : false
end

#has_environment_data_provider?(lookup_invocation) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns `true` if an environment data provider version 5 is configured


262
263
264
265
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 262

def has_environment_data_provider?(lookup_invocation)
  ep = env_provider(lookup_invocation)
  ep.nil? ? false : ep.config(lookup_invocation).version >= 5
end

#lookup(key, lookup_invocation, merge) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Performs a lookup using global, environment, and module data providers. Merge the result using the given merge strategy. If the merge strategy is nil, then an attempt is made to find merge options in the `lookup_options` hash for an entry associated with the key. If no options are found, the no merge is performed and the first found entry is returned.


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 45

def lookup(key, lookup_invocation, merge)
  # The 'lookup_options' key is reserved and not found as normal data
  if key == LOOKUP_OPTIONS || key.start_with?(LOOKUP_OPTIONS_PREFIX)
    lookup_invocation.with(:invalid_key, LOOKUP_OPTIONS) do
      throw :no_such_key
    end
  end

  # Record that the key was looked up. This will record all keys for which a lookup is performed
  # except 'lookup_options' (since that is illegal from a user perspective,
  # and from an impact perspective is always looked up).
  @key_recorder.record(key)

  key = LookupKey.new(key)
  lookup_invocation.lookup(key, key.module_name) do
    if lookup_invocation.only_explain_options?
      catch(:no_such_key) { do_lookup(LookupKey::LOOKUP_OPTIONS, lookup_invocation, HASH) }
      nil
    else
      lookup_options = lookup_lookup_options(key, lookup_invocation) || {}

      if merge.nil?
        # Used cached lookup_options
        # merge = lookup_merge_options(key, lookup_invocation)
        merge = lookup_options[MERGE]
        lookup_invocation.report_merge_source(LOOKUP_OPTIONS) unless merge.nil?
      end
      convert_result(key.to_s, lookup_options, lookup_invocation, lambda do
        lookup_invocation.with(:data, key.to_s) do
          catch(:no_such_key) { return do_lookup(key, lookup_invocation, merge) }
          throw :no_such_key if lookup_invocation.global_only?
          key.dig(lookup_invocation, lookup_default_in_module(key, lookup_invocation))
        end
      end)
    end
  end
end

#lookup_default_in_module(key, lookup_invocation) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 178

def lookup_default_in_module(key, lookup_invocation)
  module_name = lookup_invocation.module_name

  # Do not attempt to do a lookup in a module unless the name is qualified.
  throw :no_such_key if module_name.nil?

  provider = module_provider(lookup_invocation, module_name)
  throw :no_such_key if provider.nil? || !provider.config(lookup_invocation).has_default_hierarchy?

  lookup_invocation.with(:scope, "Searching default_hierarchy of module \"#{module_name}\"") do
    merge_strategy = nil
    if merge_strategy.nil?
      @module_default_lookup_options ||= {}
      options = @module_default_lookup_options.fetch(module_name) do |k|
        meta_invocation = Invocation.new(lookup_invocation.scope)
        meta_invocation.lookup(LookupKey::LOOKUP_OPTIONS, k) do
          opts = nil
          lookup_invocation.with(:scope, "Searching for \"#{LookupKey::LOOKUP_OPTIONS}\"") do
            catch(:no_such_key) do
            opts = compile_patterns(
              validate_lookup_options(
                provider.key_lookup_in_default(LookupKey::LOOKUP_OPTIONS, meta_invocation, MergeStrategy.strategy(HASH)), k))
            end
          end
          @module_default_lookup_options[k] = opts
        end
      end
      lookup_options = extract_lookup_options_for_key(key, options)
      merge_strategy = lookup_options[MERGE] unless lookup_options.nil?
    end

    lookup_invocation.with(:scope, "Searching for \"#{key}\"") do
      provider.key_lookup_in_default(key, lookup_invocation, merge_strategy)
    end
  end
end

#lookup_global(key, lookup_invocation, merge_strategy) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 125

def lookup_global(key, lookup_invocation, merge_strategy)
  # hiera_xxx will always use global_provider regardless of data_binding_terminus setting
  terminus = lookup_invocation.hiera_xxx_call? ? :hiera : Puppet[:data_binding_terminus]
  case terminus
  when :hiera, 'hiera'
    provider = global_provider(lookup_invocation)
    throw :no_such_key if provider.nil?
    provider.key_lookup(key, lookup_invocation, merge_strategy)
  when :none, 'none', '', nil
    # If global lookup is disabled, immediately report as not found
    lookup_invocation.report_not_found(key)
    throw :no_such_key
  else
    lookup_invocation.with(:global, terminus) do
      catch(:no_such_key) do
        return lookup_invocation.report_found(key, Puppet::DataBinding.indirection.find(key.root_key,
          {:environment => environment, :variables => lookup_invocation.scope, :merge => merge_strategy}))
      end
      lookup_invocation.report_not_found(key)
      throw :no_such_key
    end
  end
rescue Puppet::DataBinding::LookupError => detail
  raise detail unless detail.issue_code.nil?
  error = Puppet::Error.new(_("Lookup of key '%{key}' failed: %{detail}") % { key: lookup_invocation.top_key, detail: detail.message })
  error.set_backtrace(detail.backtrace)
  raise error
end

#lookup_in_environment(key, lookup_invocation, merge_strategy) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


154
155
156
157
158
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 154

def lookup_in_environment(key, lookup_invocation, merge_strategy)
  provider = env_provider(lookup_invocation)
  throw :no_such_key if provider.nil?
  provider.key_lookup(key, lookup_invocation, merge_strategy)
end

#lookup_in_module(key, lookup_invocation, merge_strategy) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 160

def lookup_in_module(key, lookup_invocation, merge_strategy)
  module_name = lookup_invocation.module_name

  # Do not attempt to do a lookup in a module unless the name is qualified.
  throw :no_such_key if module_name.nil?

  provider = module_provider(lookup_invocation, module_name)
  if provider.nil?
    if environment.module(module_name).nil?
      lookup_invocation.report_module_not_found(module_name)
    else
      lookup_invocation.report_module_provider_not_found(module_name)
    end
    throw :no_such_key
  end
  provider.key_lookup(key, lookup_invocation, merge_strategy)
end

#lookup_lookup_options(key, lookup_invocation) ⇒ String, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Retrieve the lookup options that match the given `name`.


232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 232

def lookup_lookup_options(key, lookup_invocation)
  module_name = key.module_name

  # Retrieve the options for the module. We use nil as a key in case we have no module
  if !@lookup_options.include?(module_name)
    options = retrieve_lookup_options(module_name, lookup_invocation, MergeStrategy.strategy(HASH))
    @lookup_options[module_name] = options
  else
    options = @lookup_options[module_name]
  end
  extract_lookup_options_for_key(key, options)
end

#lookup_merge_options(key, lookup_invocation) ⇒ String, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Retrieve the merge options that match the given `name`.


221
222
223
224
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 221

def lookup_merge_options(key, lookup_invocation)
  lookup_options = lookup_lookup_options(key, lookup_invocation)
  lookup_options.nil? ? nil : lookup_options[MERGE]
end

#set_global_hiera_config_path(path) ⇒ LookupAdapter

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns self


274
275
276
277
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 274

def set_global_hiera_config_path(path)
  @global_hiera_config_path = Pathname.new(path)
  self
end

#set_global_onlyLookupAdapter

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Instructs the lookup framework to only perform lookups in the global layer


285
286
287
288
# File 'lib/puppet/pops/lookup/lookup_adapter.rb', line 285

def set_global_only
  @global_only = true
  self
end