@@ -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"
0 commit comments