Skip to content

Commit 4890b91

Browse files
committed
new method patch
1 parent bbf9aae commit 4890b91

File tree

2 files changed

+109
-33
lines changed

2 files changed

+109
-33
lines changed

lib/puppet/provider/base_dsc_lite/powershell.rb

Lines changed: 104 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,106 @@ def self.redact_content(content)
6767
end
6868

6969
# ---------------------------
70-
# Agent-side resolution helpers (Option 2)
70+
# Deferred value resolution - NEW APPROACH
71+
# ---------------------------
72+
73+
# Resolve deferred values in properties right before PowerShell script generation
74+
# This is the correct timing - after catalog application starts but before template rendering
75+
def resolve_deferred_values!
76+
return unless resource.parameters.key?(:properties)
77+
78+
current_properties = resource.parameters[:properties].value
79+
return unless contains_deferred_values?(current_properties)
80+
81+
Puppet.notice('DSC PROVIDER → Resolving deferred values in properties')
82+
83+
begin
84+
# Get the facts that are available on the agent
85+
facts = Puppet.lookup(:facts) { nil }
86+
87+
# Create a minimal evaluation context for deferred resolution
88+
# This approach uses Puppet's built-in deferred resolution mechanism
89+
resolved_properties = resolve_deferred_recursively(current_properties, facts)
90+
91+
# Update the parameter value with the resolved version
92+
resource.parameters[:properties].value = resolved_properties
93+
94+
# Verify resolution worked
95+
if contains_deferred_values?(resolved_properties)
96+
Puppet.warning('DSC PROVIDER → Some deferred values could not be resolved')
97+
else
98+
Puppet.notice('DSC PROVIDER → All deferred values resolved successfully')
99+
end
100+
rescue => e
101+
Puppet.warning("DSC PROVIDER → Error resolving deferred values: #{e.class}: #{e.message}")
102+
# Continue with unresolved values - they will be stringified but at least won't crash
103+
end
104+
end
105+
106+
# Check if a value contains any deferred values (recursively)
107+
def contains_deferred_values?(value)
108+
case value
109+
when Hash
110+
value.any? { |k, v| contains_deferred_values?(k) || contains_deferred_values?(v) }
111+
when Array
112+
value.any? { |v| contains_deferred_values?(v) }
113+
else
114+
# Check if this is a Deferred object
115+
value && value.class.name.include?('Deferred')
116+
end
117+
end
118+
119+
# Recursively resolve deferred values using Puppet's deferred function mechanism
120+
def resolve_deferred_recursively(value, facts)
121+
case value
122+
when Hash
123+
result = {}
124+
value.each do |k, v|
125+
result[resolve_deferred_recursively(k, facts)] = resolve_deferred_recursively(v, facts)
126+
end
127+
result
128+
when Array
129+
value.map { |v| resolve_deferred_recursively(v, facts) }
130+
else
131+
# If this is a Deferred object, resolve it
132+
if value && value.class.name.include?('Deferred')
133+
resolve_single_deferred(value, facts)
134+
else
135+
value
136+
end
137+
end
138+
end
139+
140+
# Resolve a single Deferred object
141+
def resolve_single_deferred(deferred_value, _facts)
142+
# For Deferred objects, we need to call the actual function with the parameters
143+
# This mimics what Puppet does during normal deferred resolution
144+
145+
function_name = deferred_value.name
146+
arguments = deferred_value.arguments
147+
148+
# Call the function with the provided arguments
149+
# This uses Puppet's function loading mechanism
150+
loaders = Puppet.lookup(:loaders)
151+
function_loader = loaders.private_environment_loader || loaders.static_loader
152+
function = function_loader.load(:function, function_name)
153+
154+
if function
155+
# Execute the function with the arguments
156+
result = function.call({}, *arguments)
157+
Puppet.debug("DSC PROVIDER → Resolved Deferred('#{function_name}', #{arguments.inspect}) → #{result.inspect}")
158+
result
159+
else
160+
Puppet.warning("DSC PROVIDER → Could not load function '#{function_name}' for deferred resolution")
161+
deferred_value
162+
end
163+
rescue => e
164+
Puppet.warning("DSC PROVIDER → Error resolving Deferred('#{function_name}'): #{e.message}")
165+
deferred_value
166+
end
167+
168+
# ---------------------------
169+
# Legacy deferred resolution methods (keeping for reference but not using)
71170
# ---------------------------
72171

73172
# 1) Catalog-wide resolve: replace all Deferreds/futures in the catalog
@@ -185,9 +284,8 @@ def format_for_ps(value)
185284
def exists?
186285
Puppet.notice("DSC PROVIDER SENTINEL → #{__FILE__}")
187286

188-
# Two-stage resolve before rendering
189-
force_resolve_catalog_deferred!
190-
force_resolve_properties!
287+
# Resolve deferred values right before we start processing
288+
resolve_deferred_values!
191289

192290
timeout = set_timeout
193291
Puppet.debug "Dsc Timeout: #{timeout} milliseconds"
@@ -220,9 +318,8 @@ def exists?
220318
def create
221319
Puppet.notice("DSC PROVIDER SENTINEL → #{__FILE__}")
222320

223-
# Two-stage resolve before rendering
224-
force_resolve_catalog_deferred!
225-
force_resolve_properties!
321+
# Resolve deferred values right before we start processing
322+
resolve_deferred_values!
226323

227324
timeout = set_timeout
228325
Puppet.debug "Dsc Timeout: #{timeout} milliseconds"

lib/puppet/type/dsc.rb

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -107,33 +107,12 @@ def change_to_s(currentvalue, newvalue)
107107
end
108108

109109
munge do |value|
110-
Puppet.notice("DSC TYPE SENTINEL → #{__FILE__}")
111-
compiler = Puppet.lookup(:compiler) { nil }
112-
if compiler
113-
begin
114-
resolved = Puppet::Pops::Evaluator::DeferredResolver.resolve(value, compiler)
115-
rescue => e
116-
Puppet.notice("DSC TYPE resolve() error: #{e.class}: #{e.message}")
117-
resolved = value
118-
end
119-
else
120-
Puppet.notice('DSC TYPE SENTINEL → no compiler available during munge')
121-
resolved = value
122-
end
123-
124-
# Quick check: did any Deferred remain?
125-
def contains_deferred?(x)
126-
case x
127-
when Hash then x.any? { |k, v| contains_deferred?(k) || contains_deferred?(v) }
128-
when Array then x.any? { |v| contains_deferred?(v) }
129-
else x && x.class.name.to_s.include?('Deferred')
130-
end
131-
end
132-
if contains_deferred?(resolved)
133-
Puppet.notice('DSC TYPE SENTINEL → properties still contains Deferred AFTER resolve()')
134-
end
110+
# Don't try to resolve deferred values during munge - they should be resolved
111+
# on the agent during catalog application, not during catalog compilation.
112+
# Just pass them through to the provider for proper resolution timing.
113+
Puppet.notice("DSC TYPE SENTINEL → #{__FILE__} - letting deferred values pass through")
135114

136-
PuppetX::DscLite::TypeHelpers.munge_sensitive_hash(resolved)
115+
PuppetX::DscLite::TypeHelpers.munge_sensitive_hash(value)
137116
end
138117
end
139118

0 commit comments

Comments
 (0)