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



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 119

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



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/puppet/pops/evaluator/deferred_resolver.rb', line 158

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
# 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)
      # If the value is instance of Sensitive - assign the unwrapped value
      # and mark it as sensitive if not already marked
      #
      case resolved
      when Puppet::Pops::Types::PSensitiveType::Sensitive
        resolved = resolved.unwrap
        mark_sensitive_parameters(r, k)
      # If the value is a DeferredValue and it has an argument of type PSensitiveType, mark it as sensitive
      # The DeferredValue.resolve method will unwrap it during catalog application
      when Puppet::Pops::Evaluator::DeferredValue
        if v.arguments.any? { |arg| arg.is_a?(Puppet::Pops::Types::PSensitiveType) }
          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