Class: Puppet::Pops::Evaluator::DeferredResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/pops/evaluator/deferred_resolver.rb

Overview

Utility class to help resolve instances of Puppet::Pops::Types::PDeferredType::Deferred

Constant Summary collapse

DOLLAR =
'$'.freeze
DIG =
'dig'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(compiler, preprocess_deferred = true) ⇒ DeferredResolver

Returns a new instance of DeferredResolver.



72
73
74
75
76
77
78
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 72

def initialize(compiler, preprocess_deferred = true)
  @compiler = compiler
  # Always resolve in top scope
  @scope = @compiler.topscope
  @deferred_class = Puppet::Pops::Types::TypeFactory.deferred.implementation_class
  @preprocess_deferred = preprocess_deferred
end

Class Method Details

.resolve(value, compiler) ⇒ Object

Resolves a value such that a direct Deferred, or any nested Deferred values are resolved and used instead of the deferred value. A direct Deferred value, or nested deferred values inside of Array, Hash or Sensitive values are resolved and replaced inside of freshly created containers.

The resolution takes place in the topscope of the given compiler. Variable values are supposed to already have been set.

Parameters:

Returns:

  • (Object)

    the resolved value (a new Array, Hash, or Sensitive if needed), with all deferred values resolved



67
68
69
70
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 67

def self.resolve(value, compiler)
  resolver = new(compiler)
  resolver.resolve(value)
end

.resolve_and_replace(facts, catalog, environment = catalog.environment_instance, preprocess_deferred = true) ⇒ nil

Resolves and replaces all Deferred values in a catalog’s resource attributes found as direct values or nested inside Array, Hash or Sensitive values. Deferred values inside of custom Object instances are not resolved as this is expected to be done by such objects.

Parameters:

Returns:

  • (nil)

    does not return anything - the catalog is modified as a side effect



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 39

def self.resolve_and_replace(facts, catalog, environment = catalog.environment_instance, preprocess_deferred = true)
  compiler = Puppet::Parser::ScriptCompiler.new(environment, catalog.name, preprocess_deferred)
  resolver = new(compiler, preprocess_deferred)
  resolver.set_facts_variable(facts)
  # TODO:
  #    # When scripting the trusted data are always local, but set them anyway
  #    @scope.set_trusted(node.trusted_data)
  #
  #    # Server facts are always about the local node's version etc.
  #    @scope.set_server_facts(node.server_facts)

  resolver.resolve_futures(catalog)
  nil
end

Instance Method Details

#resolve(x) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 153

def resolve(x)
  if x.class == @deferred_class
    resolve_future(x)
  elsif x.is_a?(Array)
    x.map {|v| resolve(v) }
  elsif x.is_a?(Hash)
    result = {}
    x.each_pair {|k,v| result[k] = resolve(v) }
    result
  elsif x.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive)
    # rewrap in a new Sensitive after resolving any nested deferred values
    Puppet::Pops::Types::PSensitiveType::Sensitive.new(resolve(x.unwrap))
  elsif x.is_a?(Puppet::Pops::Types::PBinaryType::Binary)
    # use the ASCII-8BIT string that it wraps
    x.binary_buffer
  else
    x
  end
end

#resolve_future(f) ⇒ Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 191

def resolve_future(f)
  # If any of the arguments to a future is a future it needs to be resolved first
  func_name = f.name
  mapped_arguments = map_arguments(f.arguments)
  # if name starts with $ then this is a call to dig
  if func_name[0] == DOLLAR
    var_name = func_name[1..-1]
    func_name = DIG
    mapped_arguments.insert(0, @scope[var_name])
  end

  if @preprocess_deferred
    # call the function (name in deferred, or 'dig' for a variable)
    @scope.call_function(func_name, mapped_arguments)
  else
    # call the function later
    DeferredValue.new(
      Proc.new {
        # deferred functions can have nested deferred arguments
        resolved_arguments = mapped_arguments.map { |arg| resolve_lazy_args(arg) }
        @scope.call_function(func_name, resolved_arguments)
      }
    )
  end
end

#resolve_futures(catalog) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 86

def resolve_futures(catalog)
  catalog.resources.each do |r|
    overrides = {}
    r.parameters.each_pair do |k, v|
      resolved = resolve(v)
      case resolved
      when Puppet::Pops::Types::PSensitiveType::Sensitive
        # If the resolved value is instance of Sensitive - assign the unwrapped value
        # and mark it as sensitive if not already marked
        #
        resolved = resolved.unwrap
        mark_sensitive_parameters(r, k)

      when Puppet::Pops::Evaluator::DeferredValue
        # If the resolved value is a DeferredValue and it has an argument of type
        # PSensitiveType, mark it as sensitive. Since DeferredValues can nest,
        # we must walk all arguments, e.g. the DeferredValue may call the `epp`
        # function, where one of its arguments is a DeferredValue to call the
        # `vault:lookup` function.
        #
        # The DeferredValue.resolve method will unwrap the sensitive during
        # catalog application
        #
        if contains_sensitive_args?(v)
          mark_sensitive_parameters(r, k)
        end
      end
      overrides[ k ] = resolved
    end
    r.parameters.merge!(overrides) unless overrides.empty?
  end
end

#set_facts_variable(facts) ⇒ Object

Parameters:



82
83
84
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 82

def set_facts_variable(facts)
  @scope.set_facts(facts.nil? ? {} : facts.values)
end