Skip to content

Commit 6524805

Browse files
committed
(PUP-9323) Allow agent and apply to lazily resolve deferred values
If `Puppet[:preprocess_deferrred]` is true (the default), then the `binary_file` deferred function will fail to read the file, since it hasn't been created yet. If the value is false, then the file is created before `binary_file` is called.
1 parent a76f498 commit 6524805

File tree

5 files changed

+94
-3
lines changed

5 files changed

+94
-3
lines changed

lib/puppet/application/apply.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def main
241241
end
242242

243243
# Resolve all deferred values and replace them / mutate the catalog
244-
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog, apply_environment)
244+
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog, apply_environment, Puppet[:preprocess_deferred])
245245

246246
# Translate it to a RAL catalog
247247
catalog = catalog.to_ral
@@ -350,7 +350,7 @@ def read_catalog(text)
350350
raise Puppet::Error, _("Could not deserialize catalog from %{format}: %{detail}") % { format: format, detail: detail }, detail.backtrace
351351
end
352352
# Resolve all deferred values and replace them / mutate the catalog
353-
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog, configured_environment)
353+
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog, configured_environment, Puppet[:preprocess_deferred])
354354

355355
catalog.to_ral
356356
end

lib/puppet/configurer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def convert_catalog(result, duration, facts, options = {})
112112
catalog_conversion_time = thinmark do
113113
# Will mutate the result and replace all Deferred values with resolved values
114114
if facts
115-
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(facts, result, Puppet.lookup(:current_environment))
115+
Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(facts, result, Puppet.lookup(:current_environment), Puppet[:preprocess_deferred])
116116
end
117117

118118
catalog = result.to_ral

lib/puppet/defaults.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,16 @@ def self.initialize_default_settings!(settings)
20212021
being evaluated. This allows you to interactively see exactly
20222022
what is being done.",
20232023
},
2024+
:preprocess_deferred => {
2025+
:default => true,
2026+
:type => :boolean,
2027+
:desc => "Whether puppet should call deferred functions before applying
2028+
the catalog. If set to `true`, then all prerequisites needed for the
2029+
deferred function must be satified prior to puppet running. If set to
2030+
`false`, then deferred functions will follow puppet relationships and
2031+
ordering. This allows puppet to install prerequisites needed for a
2032+
deferred function and call the deferred function in the same run."
2033+
},
20242034
:summarize => {
20252035
:default => false,
20262036
:type => :boolean,

spec/integration/application/agent_spec.rb

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,18 @@
9898
end
9999

100100
context 'rich data' do
101+
let(:deferred_file) { tmpfile('deferred') }
102+
let(:deferred_manifest) do <<~END
103+
file { '#{deferred_file}':
104+
ensure => file,
105+
content => '123',
106+
} ->
107+
notify { 'deferred':
108+
message => Deferred('binary_file', ['#{deferred_file}'])
109+
}
110+
END
111+
end
112+
101113
it "calls a deferred 4x function" do
102114
catalog_handler = -> (req, res) {
103115
catalog = compile_to_catalog(<<-MANIFEST, node)
@@ -142,6 +154,43 @@
142154
end
143155
end
144156

157+
it "fails to apply a deferred function with an unsatified prerequisite" do
158+
catalog_handler = -> (req, res) {
159+
catalog = compile_to_catalog(deferred_manifest, node)
160+
res.body = formatter.render(catalog)
161+
res['Content-Type'] = formatter.mime
162+
}
163+
164+
server.start_server(mounts: {catalog: catalog_handler}) do |port|
165+
Puppet[:serverport] = port
166+
expect {
167+
agent.command_line.args << '--test'
168+
agent.run
169+
}.to exit_with(1)
170+
.and output(%r{Using environment}).to_stdout
171+
.and output(%r{The given file '#{deferred_file}' does not exist}).to_stderr
172+
end
173+
end
174+
175+
it "applies a deferred function and its prerequisite in the same run" do
176+
Puppet[:preprocess_deferred] = false
177+
178+
catalog_handler = -> (req, res) {
179+
catalog = compile_to_catalog(deferred_manifest, node)
180+
res.body = formatter.render(catalog)
181+
res['Content-Type'] = formatter.mime
182+
}
183+
184+
server.start_server(mounts: {catalog: catalog_handler}) do |port|
185+
Puppet[:serverport] = port
186+
expect {
187+
agent.command_line.args << '--test'
188+
agent.run
189+
}.to exit_with(2)
190+
.and output(%r{defined 'message' as Binary\("MTIz"\)}).to_stdout
191+
end
192+
end
193+
145194
it "re-evaluates a deferred function in a cached catalog" do
146195
Puppet[:report] = false
147196
Puppet[:use_cached_catalog] = true

spec/integration/application/apply_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,18 @@ def bogus()
665665
end
666666

667667
context 'rich data' do
668+
let(:deferred_file) { tmpfile('deferred') }
669+
let(:deferred_manifest) do <<~END
670+
file { '#{deferred_file}':
671+
ensure => file,
672+
content => '123',
673+
} ->
674+
notify { 'deferred':
675+
message => Deferred('binary_file', ['#{deferred_file}'])
676+
}
677+
END
678+
end
679+
668680
it "calls a deferred 4x function" do
669681
apply.command_line.args = ['-e', 'notify { "deferred3x": message => Deferred("join", [[1,2,3], ":"]) }']
670682

@@ -681,5 +693,25 @@ def bogus()
681693
}.to exit_with(0) # for some reason apply returns 0 instead of 2
682694
.and output(%r{Notice: /Stage\[main\]/Main/Notify\[deferred4x\]/message: defined 'message' as 'I am deferred'}).to_stdout
683695
end
696+
697+
it "fails to apply a deferred function with an unsatified prerequisite" do
698+
apply.command_line.args = ['-e', deferred_manifest]
699+
expect {
700+
apply.run
701+
}.to exit_with(1) # for some reason apply returns 0 instead of 2
702+
.and output(/Compiled catalog/).to_stdout
703+
.and output(%r{The given file '#{deferred_file}' does not exist}).to_stderr
704+
end
705+
706+
it "applies a deferred function and its prerequisite in the same run" do
707+
Puppet[:preprocess_deferred] = false
708+
709+
apply.command_line.args = ['-e', deferred_manifest]
710+
expect {
711+
apply.run
712+
}.to exit_with(0) # for some reason apply returns 0 instead of 2
713+
.and output(%r{defined 'message' as Binary\("MTIz"\)}).to_stdout
714+
end
715+
684716
end
685717
end

0 commit comments

Comments
 (0)