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 =
'$'
DIG =
'dig'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(compiler, preprocess_deferred = true) ⇒ DeferredResolver

Returns a new instance of DeferredResolver.



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

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



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

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



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

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



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

def resolve(x)
  if x.instance_of?(@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



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

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..]
    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 {
        # 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



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
118
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 87

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:



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

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