Skip to content

Commit d211b30

Browse files
committed
patch
1 parent bc213d2 commit d211b30

File tree

2 files changed

+44
-73
lines changed

2 files changed

+44
-73
lines changed

lib/puppet/provider/base_dsc_lite/powershell.rb

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@ def ps_manager
6767
Pwsh::Manager.instance(command(:powershell), Pwsh::Manager.powershell_args, debug: debug_output)
6868
end
6969

70-
# ===== Deferred helpers (instance methods) =====
70+
# ============================================================================
71+
# Deferred helpers (instance methods)
72+
# ============================================================================
7173

72-
# Detects if a value (or nested) contains a DeferredValue
74+
# Returns true if obj (or any nested member) is a DeferredValue
7375
def deep_contains_deferred?(obj)
7476
case obj
7577
when Puppet::Pops::Evaluator::DeferredValue
@@ -89,25 +91,18 @@ def deep_contains_deferred?(obj)
8991
end
9092
end
9193

92-
# Force resolution of Deferreds across the catalog before script generation.
93-
# This mirrors Puppet's own preprocessing when preprocess_deferred=true.
94-
def ensure_deferreds_resolved!
95-
# (A) Prefer compiler-based resolution for properties when available
96-
props_param = resource.parameters[:properties]
97-
compiler = Puppet.lookup(:compiler) { nil }
98-
99-
if props_param
100-
pv = props_param.value
101-
if deep_contains_deferred?(pv)
102-
Puppet.debug('DSC_lite: Deferred detected in properties; resolving via compiler') if compiler
103-
if compiler
104-
resolved = Puppet::Pops::Evaluator::DeferredResolver.resolve(pv, compiler)
105-
resource[:properties] = resolved
106-
end
107-
end
108-
end
94+
# Resolves a value with the current compiler if available; otherwise returns it unchanged
95+
def resolve_value_with_compiler(value)
96+
compiler = Puppet.lookup(:compiler) { nil }
97+
return value unless compiler
98+
Puppet::Pops::Evaluator::DeferredResolver.resolve(value, compiler)
99+
end
109100

110-
# (B) Always run a full catalog resolution pass as a safety net.
101+
# Resolve any lingering Deferreds before script generation:
102+
# A) catalog-wide pass (resolve_and_replace), then
103+
# B) per-parameter pass using compiler resolution for any stragglers
104+
def ensure_deferreds_resolved!
105+
# (A) Catalog-wide resolution (mirrors preprocess_deferred=true behavior)
111106
facts = Puppet::Node::Facts.new(
112107
(resource.catalog.respond_to?(:host) && resource.catalog.host) ||
113108
Facter.value(:fqdn) || Facter.value(:hostname) || 'localhost',
@@ -118,19 +113,32 @@ def ensure_deferreds_resolved!
118113
Puppet.debug('DSC_lite: invoking DeferredResolver.resolve_and_replace on catalog')
119114
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(facts, resource.catalog, env, true)
120115

121-
# Post-check for diagnostics
122-
pp = resource.parameters[:properties]
123-
if pp && deep_contains_deferred?(pp.value)
124-
Puppet.debug('DSC_lite: WARNING — Deferred still present in properties after resolution pass')
116+
# (B) Per-parameter scan & fix-up
117+
resource.parameters_with_value.each do |param|
118+
val = param.value
119+
next unless deep_contains_deferred?(val)
120+
121+
Puppet.debug("DSC_lite: Deferred detected in parameter `#{param.name}`; attempting compiler-based resolution")
122+
begin
123+
resolved = resolve_value_with_compiler(val)
124+
resource[param.name] = resolved unless resolved.equal?(val)
125+
rescue => e
126+
raise Puppet::Error, "DSC_lite: failed to resolve Deferred in parameter `#{param.name}`: #{e.class}: #{e.message}"
127+
end
128+
end
129+
130+
# Post-check diagnostics for the critical :properties blob
131+
props_param = resource.parameters[:properties]
132+
if props_param && deep_contains_deferred?(props_param.value)
133+
Puppet.debug('DSC_lite: WARNING — Deferred still present in `properties` after resolution passes')
125134
else
126-
Puppet.debug('DSC_lite: no Deferred values remain in properties after resolution')
135+
Puppet.debug('DSC_lite: no Deferred values remain in `properties` after resolution')
127136
end
128-
rescue => e
129-
# Raise a targeted error; this is better than failing later with "unsupported type DeferredValue"
130-
raise Puppet::Error, "DSC_lite: failed while resolving Deferred values: #{e.class}: #{e.message}"
131137
end
132138

133-
# ===== END Deferred helpers =====
139+
# ============================================================================
140+
# Provider lifecycle
141+
# ============================================================================
134142

135143
def exists?
136144
timeout = set_timeout
@@ -213,20 +221,10 @@ def notify_reboot_pending
213221
end
214222
end
215223

216-
# ---- CHANGED: resolve Deferreds right before formatting the hash ----
224+
# Keep formatter behavior identical to main; resolution happens in provider
217225
def self.format_dsc_lite(dsc_value)
218-
# Resolve any direct/nested Deferred values using the current compiler scope if available.
219-
compiler = Puppet.lookup(:compiler) { nil }
220-
value_for_format =
221-
if compiler
222-
Puppet::Pops::Evaluator::DeferredResolver.resolve(dsc_value, compiler)
223-
else
224-
dsc_value
225-
end
226-
227-
PuppetX::PuppetLabs::DscLite::PowerShellHashFormatter.format(value_for_format)
226+
PuppetX::PuppetLabs::DscLite::PowerShellHashFormatter.format(dsc_value)
228227
end
229-
# --------------------------------------------------------------------
230228

231229
def self.escape_quotes(text)
232230
text.gsub("'", "''")

lib/puppet_x/puppetlabs/dsc_lite/powershell_hash_formatter.rb

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# frozen_string_literal: true
22

33
require 'ruby-pwsh'
4-
require 'puppet'
5-
require 'puppet/pops/evaluator/deferred_resolver'
64

75
# rubocop:disable Style/ClassAndModuleChildren
86
module PuppetX
@@ -14,39 +12,14 @@ class PowerShellHashFormatter
1412
#
1513
# @return [Object] Formatted value.
1614
def self.format(dsc_value)
17-
resolved = resolve_deferred_deep(dsc_value)
18-
19-
if resolved.instance_of?(::Hash)
20-
format_hash(resolved)
21-
elsif resolved.instance_of?(::Puppet::Pops::Types::PSensitiveType::Sensitive)
22-
"'#{escape_quotes(resolved.unwrap)}' # PuppetSensitive"
23-
else
24-
Pwsh::Util.format_powershell_value(resolved)
25-
end
26-
end
27-
28-
# --- Resolve any DeferredValue recursively before formatting ---
29-
def self.resolve_deferred_deep(obj)
30-
case obj
31-
when Puppet::Pops::Evaluator::DeferredValue
32-
compiler = Puppet.lookup(:compiler) { nil }
33-
raise Puppet::Error, 'DSC_lite: DeferredValue encountered but no compiler is available to resolve it' unless compiler
34-
35-
Puppet::Pops::Evaluator::DeferredResolver.resolve(obj, compiler)
36-
when Puppet::Pops::Types::PSensitiveType::Sensitive
37-
inner = resolve_deferred_deep(obj.unwrap)
38-
Puppet::Pops::Types::PSensitiveType::Sensitive.new(inner)
39-
when Hash
40-
obj.each_with_object({}) do |(k, v), h|
41-
h[resolve_deferred_deep(k)] = resolve_deferred_deep(v)
42-
end
43-
when Array
44-
obj.map { |v| resolve_deferred_deep(v) }
15+
if dsc_value.instance_of?(::Hash)
16+
format_hash(dsc_value)
17+
elsif dsc_value.instance_of?(::Puppet::Pops::Types::PSensitiveType::Sensitive)
18+
"'#{escape_quotes(dsc_value.unwrap)}' # PuppetSensitive"
4519
else
46-
obj
20+
Pwsh::Util.format_powershell_value(dsc_value)
4721
end
4822
end
49-
# ----------------------------------------------------------------
5023

5124
private_class_method def self.format_hash(value)
5225
if value.key?('dsc_type')

0 commit comments

Comments
 (0)