puppet 7.16.0 → 7.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +66 -5
- data/ext/systemd/puppet.service +1 -1
- data/lib/puppet/agent.rb +20 -2
- data/lib/puppet/application/agent.rb +3 -13
- data/lib/puppet/application/apply.rb +2 -2
- data/lib/puppet/configurer.rb +1 -1
- data/lib/puppet/defaults.rb +11 -1
- data/lib/puppet/http/client.rb +22 -2
- data/lib/puppet/parameter.rb +19 -4
- data/lib/puppet/pops/evaluator/deferred_resolver.rb +46 -6
- data/lib/puppet/pops/functions/dispatcher.rb +10 -6
- data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +7 -6
- data/lib/puppet/pops/types/type_mismatch_describer.rb +22 -1
- data/lib/puppet/provider/package/puppetserver_gem.rb +7 -16
- data/lib/puppet/provider/package/yum.rb +8 -3
- data/lib/puppet/provider/user/directoryservice.rb +15 -8
- data/lib/puppet/ssl/ssl_provider.rb +65 -12
- data/lib/puppet/ssl/state_machine.rb +13 -17
- data/lib/puppet/transaction.rb +22 -0
- data/lib/puppet/type/user.rb +3 -0
- data/lib/puppet/type.rb +20 -3
- data/lib/puppet/version.rb +1 -1
- data/lib/puppet.rb +1 -14
- data/man/man5/puppet.conf.5 +11 -3
- data/man/man8/puppet-agent.8 +2 -2
- data/man/man8/puppet-apply.8 +1 -1
- data/man/man8/puppet-catalog.8 +1 -1
- data/man/man8/puppet-config.8 +1 -1
- data/man/man8/puppet-describe.8 +1 -1
- data/man/man8/puppet-device.8 +1 -1
- data/man/man8/puppet-doc.8 +1 -1
- data/man/man8/puppet-epp.8 +1 -1
- data/man/man8/puppet-facts.8 +1 -1
- data/man/man8/puppet-filebucket.8 +1 -1
- data/man/man8/puppet-generate.8 +1 -1
- data/man/man8/puppet-help.8 +1 -1
- data/man/man8/puppet-lookup.8 +1 -1
- data/man/man8/puppet-module.8 +1 -1
- data/man/man8/puppet-node.8 +1 -1
- data/man/man8/puppet-parser.8 +1 -1
- data/man/man8/puppet-plugin.8 +1 -1
- data/man/man8/puppet-report.8 +1 -1
- data/man/man8/puppet-resource.8 +1 -1
- data/man/man8/puppet-script.8 +1 -1
- data/man/man8/puppet-ssl.8 +1 -1
- data/man/man8/puppet.8 +2 -2
- data/spec/integration/application/agent_spec.rb +157 -0
- data/spec/integration/application/apply_spec.rb +74 -0
- data/spec/integration/http/client_spec.rb +27 -10
- data/spec/lib/puppet_spec/https.rb +1 -1
- data/spec/lib/puppet_spec/puppetserver.rb +39 -2
- data/spec/unit/agent_spec.rb +6 -2
- data/spec/unit/application/agent_spec.rb +26 -16
- data/spec/unit/daemon_spec.rb +2 -11
- data/spec/unit/http/client_spec.rb +18 -0
- data/spec/unit/pops/evaluator/deferred_resolver_spec.rb +26 -0
- data/spec/unit/pops/loaders/loaders_spec.rb +1 -1
- data/spec/unit/pops/types/type_mismatch_describer_spec.rb +167 -1
- data/spec/unit/provider/package/puppetserver_gem_spec.rb +2 -2
- data/spec/unit/provider/user/directoryservice_spec.rb +1 -1
- data/spec/unit/ssl/ssl_provider_spec.rb +75 -1
- data/spec/unit/ssl/state_machine_spec.rb +1 -0
- data/tasks/generate_cert_fixtures.rake +5 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f250db7b7e5579935f6491aebaff508c8e95caf29eabbabaa7eb325df7f1d33e
|
4
|
+
data.tar.gz: 7705591fc0fd2ed3559c29d7d90f803a6730ac835207e919e92195145aae0a8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ebee9543a560c31b3f582d494f9908ebcbc2ff3c5c71eb5a86558d1c6cf13021288ee109358354a612d580a72bc5d32ceeb6d07ad172e4b30b025096c9d01e7
|
7
|
+
data.tar.gz: cef70451f5c9c09e871807b61c04d4d38270878b13bbdebb107391f6c98cc87f77d789b81fb2399358c64e86f5d1764ee8b41fab004ee5465e3f6bdc17dc46b1
|
data/Gemfile.lock
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
GIT
|
2
2
|
remote: https://github.com/puppetlabs/packaging
|
3
|
-
revision:
|
3
|
+
revision: b791353d4f81dbb1df5ce3d79e95bd008b47beb6
|
4
4
|
branch: 1.0.x
|
5
5
|
specs:
|
6
|
-
packaging (0.106.
|
6
|
+
packaging (0.106.3.6.gb791353)
|
7
7
|
apt_stage_artifacts
|
8
8
|
artifactory (~> 3)
|
9
9
|
csv (= 3.1.5)
|
10
|
+
google-cloud-storage
|
11
|
+
googleauth
|
10
12
|
rake (>= 12.3)
|
11
13
|
release-metrics
|
12
14
|
|
13
15
|
PATH
|
14
16
|
remote: .
|
15
17
|
specs:
|
16
|
-
puppet (7.
|
18
|
+
puppet (7.17.0)
|
17
19
|
CFPropertyList (~> 2.2)
|
18
20
|
concurrent-ruby (~> 1.0)
|
19
21
|
deep_merge (~> 1.0)
|
@@ -40,12 +42,19 @@ GEM
|
|
40
42
|
crack (0.4.5)
|
41
43
|
rexml
|
42
44
|
csv (3.1.5)
|
45
|
+
declarative (0.0.20)
|
43
46
|
deep_merge (1.2.2)
|
44
47
|
diff-lcs (1.5.0)
|
48
|
+
digest-crc (0.6.4)
|
49
|
+
rake (>= 12.0.0, < 14.0.0)
|
45
50
|
docopt (0.6.1)
|
46
51
|
facter (4.2.9)
|
47
52
|
hocon (~> 1.3)
|
48
53
|
thor (>= 1.0.1, < 2.0)
|
54
|
+
faraday (2.3.0)
|
55
|
+
faraday-net_http (~> 2.0)
|
56
|
+
ruby2_keywords (>= 0.0.4)
|
57
|
+
faraday-net_http (2.0.3)
|
49
58
|
fast_gettext (1.1.2)
|
50
59
|
ffi (1.15.5)
|
51
60
|
gettext (3.2.9)
|
@@ -55,24 +64,63 @@ GEM
|
|
55
64
|
fast_gettext (~> 1.1.0)
|
56
65
|
gettext (>= 3.0.2, < 3.3.0)
|
57
66
|
locale
|
67
|
+
google-apis-core (0.5.0)
|
68
|
+
addressable (~> 2.5, >= 2.5.1)
|
69
|
+
googleauth (>= 0.16.2, < 2.a)
|
70
|
+
httpclient (>= 2.8.1, < 3.a)
|
71
|
+
mini_mime (~> 1.0)
|
72
|
+
representable (~> 3.0)
|
73
|
+
retriable (>= 2.0, < 4.a)
|
74
|
+
rexml
|
75
|
+
webrick
|
76
|
+
google-apis-iamcredentials_v1 (0.10.0)
|
77
|
+
google-apis-core (>= 0.4, < 2.a)
|
78
|
+
google-apis-storage_v1 (0.14.0)
|
79
|
+
google-apis-core (>= 0.4, < 2.a)
|
80
|
+
google-cloud-core (1.6.0)
|
81
|
+
google-cloud-env (~> 1.0)
|
82
|
+
google-cloud-errors (~> 1.0)
|
83
|
+
google-cloud-env (1.6.0)
|
84
|
+
faraday (>= 0.17.3, < 3.0)
|
85
|
+
google-cloud-errors (1.2.0)
|
86
|
+
google-cloud-storage (1.36.2)
|
87
|
+
addressable (~> 2.8)
|
88
|
+
digest-crc (~> 0.4)
|
89
|
+
google-apis-iamcredentials_v1 (~> 0.1)
|
90
|
+
google-apis-storage_v1 (~> 0.1)
|
91
|
+
google-cloud-core (~> 1.6)
|
92
|
+
googleauth (>= 0.16.2, < 2.a)
|
93
|
+
mini_mime (~> 1.0)
|
94
|
+
googleauth (1.1.3)
|
95
|
+
faraday (>= 0.17.3, < 3.a)
|
96
|
+
jwt (>= 1.4, < 3.0)
|
97
|
+
memoist (~> 0.16)
|
98
|
+
multi_json (~> 1.11)
|
99
|
+
os (>= 0.9, < 2.0)
|
100
|
+
signet (>= 0.16, < 2.a)
|
58
101
|
hashdiff (1.0.1)
|
59
|
-
hiera (3.
|
60
|
-
hiera-eyaml (3.
|
102
|
+
hiera (3.9.0)
|
103
|
+
hiera-eyaml (3.3.0)
|
61
104
|
highline
|
62
105
|
optimist
|
63
106
|
highline (2.0.3)
|
64
107
|
hocon (1.3.1)
|
65
108
|
hpricot (0.8.6)
|
109
|
+
httpclient (2.8.3)
|
66
110
|
json-schema (2.8.1)
|
67
111
|
addressable (>= 2.4)
|
112
|
+
jwt (2.3.0)
|
68
113
|
locale (2.1.3)
|
114
|
+
memoist (0.16.2)
|
69
115
|
memory_profiler (1.0.0)
|
70
116
|
method_source (1.0.0)
|
117
|
+
mini_mime (1.1.2)
|
71
118
|
minitar (0.9)
|
72
119
|
msgpack (1.5.1)
|
73
120
|
multi_json (1.15.0)
|
74
121
|
mustache (1.1.1)
|
75
122
|
optimist (3.0.1)
|
123
|
+
os (1.1.4)
|
76
124
|
parallel (1.22.1)
|
77
125
|
parser (2.7.2.0)
|
78
126
|
ast (~> 2.4.1)
|
@@ -94,6 +142,11 @@ GEM
|
|
94
142
|
release-metrics (1.1.0)
|
95
143
|
csv
|
96
144
|
docopt
|
145
|
+
representable (3.2.0)
|
146
|
+
declarative (< 0.1.0)
|
147
|
+
trailblazer-option (>= 0.1.1, < 0.2.0)
|
148
|
+
uber (< 0.2.0)
|
149
|
+
retriable (3.1.2)
|
97
150
|
rexml (3.2.5)
|
98
151
|
ronn (0.7.3)
|
99
152
|
hpricot (>= 0.8.2)
|
@@ -126,10 +179,18 @@ GEM
|
|
126
179
|
rubocop (~> 0.49.0)
|
127
180
|
ruby-prof (1.4.3)
|
128
181
|
ruby-progressbar (1.11.0)
|
182
|
+
ruby2_keywords (0.0.5)
|
129
183
|
scanf (1.0.0)
|
130
184
|
semantic_puppet (1.0.4)
|
185
|
+
signet (0.16.1)
|
186
|
+
addressable (~> 2.8)
|
187
|
+
faraday (>= 0.17.5, < 3.0)
|
188
|
+
jwt (>= 1.5, < 3.0)
|
189
|
+
multi_json (~> 1.10)
|
131
190
|
text (1.3.1)
|
132
191
|
thor (1.2.1)
|
192
|
+
trailblazer-option (0.1.2)
|
193
|
+
uber (0.1.0)
|
133
194
|
unicode-display_width (1.8.0)
|
134
195
|
vcr (5.1.0)
|
135
196
|
webmock (3.14.0)
|
data/ext/systemd/puppet.service
CHANGED
data/lib/puppet/agent.rb
CHANGED
@@ -45,11 +45,19 @@ class Puppet::Agent
|
|
45
45
|
result = nil
|
46
46
|
wait_for_lock_deadline = nil
|
47
47
|
block_run = Puppet::Application.controlled_run do
|
48
|
-
splay
|
48
|
+
# splay may sleep for awhile!
|
49
|
+
splay(client_options.fetch(:splay, Puppet[:splay]))
|
50
|
+
|
51
|
+
# waiting for certs may sleep for awhile depending on onetime, waitforcert and maxwaitforcert!
|
52
|
+
# this needs to happen before forking so that if we fail to obtain certs and try to exit, then
|
53
|
+
# we exit the main process and not the forked child.
|
54
|
+
ssl_context = wait_for_certificates(client_options)
|
55
|
+
|
49
56
|
result = run_in_fork(should_fork) do
|
50
57
|
with_client(client_options[:transaction_uuid], client_options[:job_id]) do |client|
|
51
58
|
client_args = client_options.merge(:pluginsync => Puppet::Configurer.should_pluginsync?)
|
52
59
|
begin
|
60
|
+
# lock may sleep for awhile depending on waitforlock and maxwaitforlock!
|
53
61
|
lock do
|
54
62
|
# NOTE: Timeout is pretty heinous as the location in which it
|
55
63
|
# throws an error is entirely unpredictable, which means that
|
@@ -57,7 +65,9 @@ class Puppet::Agent
|
|
57
65
|
# sanity. The only thing a Puppet agent should do after this
|
58
66
|
# error is thrown is die with as much dignity as possible.
|
59
67
|
Timeout.timeout(Puppet[:runtimeout], RunTimeoutError) do
|
60
|
-
|
68
|
+
Puppet.override(ssl_context: ssl_context) do
|
69
|
+
client.run(client_args)
|
70
|
+
end
|
61
71
|
end
|
62
72
|
end
|
63
73
|
rescue Puppet::LockError
|
@@ -84,6 +94,8 @@ class Puppet::Agent
|
|
84
94
|
rescue StandardError => detail
|
85
95
|
Puppet.log_exception(detail, _("Could not run %{client_class}: %{detail}") % { client_class: client_class, detail: detail })
|
86
96
|
nil
|
97
|
+
ensure
|
98
|
+
Puppet.runtime[:http].close
|
87
99
|
end
|
88
100
|
end
|
89
101
|
end
|
@@ -137,4 +149,10 @@ class Puppet::Agent
|
|
137
149
|
ensure
|
138
150
|
@client = nil
|
139
151
|
end
|
152
|
+
|
153
|
+
def wait_for_certificates(options)
|
154
|
+
waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : Puppet[:waitforcert])
|
155
|
+
sm = Puppet::SSL::StateMachine.new(waitforcert: waitforcert, onetime: Puppet[:onetime])
|
156
|
+
sm.ensure_client_certificate
|
157
|
+
end
|
140
158
|
end
|
@@ -158,7 +158,7 @@ applying the whole thing.
|
|
158
158
|
'--fingerprint' is a one-time flag. In this mode 'puppet agent' runs
|
159
159
|
once and displays on the console (and in the log) the current certificate
|
160
160
|
(or certificate request) fingerprint. Providing the '--digest' option
|
161
|
-
allows to use a different digest algorithm to generate the fingerprint.
|
161
|
+
allows you to use a different digest algorithm to generate the fingerprint.
|
162
162
|
The main use is to verify that before signing a certificate request on
|
163
163
|
the master, the certificate request the master received is the same as
|
164
164
|
the one the client sent (to prevent against man-in-the-middle attacks
|
@@ -383,15 +383,11 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
|
|
383
383
|
|
384
384
|
log_config if Puppet[:daemonize]
|
385
385
|
|
386
|
-
# run ssl state machine, waiting if needed
|
387
|
-
ssl_context = wait_for_certificates
|
388
|
-
|
389
386
|
# Each application is responsible for pushing loaders onto the context.
|
390
387
|
# Use the current environment that has already been established, though
|
391
388
|
# it may change later during the configurer run.
|
392
389
|
env = Puppet.lookup(:current_environment)
|
393
|
-
Puppet.override(
|
394
|
-
current_environment: env,
|
390
|
+
Puppet.override(current_environment: env,
|
395
391
|
loaders: Puppet::Pops::Loaders.new(env, true)) do
|
396
392
|
if Puppet[:onetime]
|
397
393
|
onetime(daemon)
|
@@ -434,7 +430,7 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
|
|
434
430
|
|
435
431
|
def onetime(daemon)
|
436
432
|
begin
|
437
|
-
exitstatus = daemon.agent.run({:job_id => options[:job_id], :start_time => options[:start_time]})
|
433
|
+
exitstatus = daemon.agent.run({:job_id => options[:job_id], :start_time => options[:start_time], :waitforcert => options[:waitforcert]})
|
438
434
|
rescue => detail
|
439
435
|
Puppet.log_exception(detail)
|
440
436
|
end
|
@@ -524,10 +520,4 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
|
|
524
520
|
|
525
521
|
daemon
|
526
522
|
end
|
527
|
-
|
528
|
-
def wait_for_certificates
|
529
|
-
waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : Puppet[:waitforcert])
|
530
|
-
sm = Puppet::SSL::StateMachine.new(waitforcert: waitforcert)
|
531
|
-
sm.ensure_client_certificate
|
532
|
-
end
|
533
523
|
end
|
@@ -241,7 +241,7 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
|
|
241
241
|
end
|
242
242
|
|
243
243
|
# 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])
|
245
245
|
|
246
246
|
# Translate it to a RAL catalog
|
247
247
|
catalog = catalog.to_ral
|
@@ -350,7 +350,7 @@ Copyright (c) 2011 Puppet Inc., LLC Licensed under the Apache 2.0 License
|
|
350
350
|
raise Puppet::Error, _("Could not deserialize catalog from %{format}: %{detail}") % { format: format, detail: detail }, detail.backtrace
|
351
351
|
end
|
352
352
|
# 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])
|
354
354
|
|
355
355
|
catalog.to_ral
|
356
356
|
end
|
data/lib/puppet/configurer.rb
CHANGED
@@ -112,7 +112,7 @@ class Puppet::Configurer
|
|
112
112
|
catalog_conversion_time = thinmark do
|
113
113
|
# Will mutate the result and replace all Deferred values with resolved values
|
114
114
|
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])
|
116
116
|
end
|
117
117
|
|
118
118
|
catalog = result.to_ral
|
data/lib/puppet/defaults.rb
CHANGED
@@ -1534,7 +1534,7 @@ EOT
|
|
1534
1534
|
:type => :file,
|
1535
1535
|
:mode => "0640",
|
1536
1536
|
:desc => "Transactional storage file for persisting data between
|
1537
|
-
transactions for the purposes of
|
1537
|
+
transactions for the purposes of inferring information (such as
|
1538
1538
|
corrective_change) on new data received."
|
1539
1539
|
},
|
1540
1540
|
:clientyamldir => {
|
@@ -2021,6 +2021,16 @@ EOT
|
|
2021
2021
|
being evaluated. This allows you to interactively see exactly
|
2022
2022
|
what is being done.",
|
2023
2023
|
},
|
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
|
+
},
|
2024
2034
|
:summarize => {
|
2025
2035
|
:default => false,
|
2026
2036
|
:type => :boolean,
|
data/lib/puppet/http/client.rb
CHANGED
@@ -98,7 +98,7 @@ class Puppet::HTTP::Client
|
|
98
98
|
# used if :include_system_store is set to true
|
99
99
|
# @param [Integer] redirect_limit default number of HTTP redirections to allow
|
100
100
|
# in a given request. Can also be specified per-request.
|
101
|
-
# @param [Integer] retry_limit number of HTTP
|
101
|
+
# @param [Integer] retry_limit number of HTTP retries allowed in a given
|
102
102
|
# request
|
103
103
|
#
|
104
104
|
def initialize(pool: Puppet::HTTP::Pool.new(Puppet[:http_keepalive_timeout]), ssl_context: nil, system_ssl_context: nil, redirect_limit: 10, retry_limit: 100)
|
@@ -300,6 +300,24 @@ class Puppet::HTTP::Client
|
|
300
300
|
# @api public
|
301
301
|
def close
|
302
302
|
@pool.close
|
303
|
+
@default_ssl_context = nil
|
304
|
+
@default_system_ssl_context = nil
|
305
|
+
end
|
306
|
+
|
307
|
+
def default_ssl_context
|
308
|
+
cert = Puppet::X509::CertProvider.new
|
309
|
+
password = cert.load_private_key_password
|
310
|
+
|
311
|
+
ssl = Puppet::SSL::SSLProvider.new
|
312
|
+
ctx = ssl.load_context(certname: Puppet[:certname], password: password)
|
313
|
+
ssl.print(ctx)
|
314
|
+
ctx
|
315
|
+
rescue => e
|
316
|
+
# TRANSLATORS: `message` is an already translated string of why SSL failed to initialize
|
317
|
+
Puppet.log_exception(e, _("Failed to initialize SSL: %{message}") % { message: e.message })
|
318
|
+
# TRANSLATORS: `puppet agent -t` is a command and should not be translated
|
319
|
+
Puppet.err(_("Run `puppet agent -t`"))
|
320
|
+
raise e
|
303
321
|
end
|
304
322
|
|
305
323
|
protected
|
@@ -458,7 +476,9 @@ class Puppet::HTTP::Client
|
|
458
476
|
cacerts = cert_provider.load_cacerts || []
|
459
477
|
|
460
478
|
ssl = Puppet::SSL::SSLProvider.new
|
461
|
-
@default_system_ssl_context = ssl.create_system_context(cacerts: cacerts)
|
479
|
+
@default_system_ssl_context = ssl.create_system_context(cacerts: cacerts, include_client_cert: true)
|
480
|
+
ssl.print(@default_system_ssl_context)
|
481
|
+
@default_system_ssl_context
|
462
482
|
end
|
463
483
|
|
464
484
|
def apply_auth(request, basic_auth)
|
data/lib/puppet/parameter.rb
CHANGED
@@ -177,15 +177,15 @@ class Puppet::Parameter
|
|
177
177
|
end
|
178
178
|
|
179
179
|
# @overload unmunge {|| ... }
|
180
|
-
# Defines an optional method used to convert the parameter value to DSL/string form
|
180
|
+
# Defines an optional method used to convert the parameter value from internal form to DSL/string form.
|
181
181
|
# If an `unmunge` method is not defined, the internal form is used.
|
182
182
|
# @see munge
|
183
|
-
# @note This adds a method with the name `
|
183
|
+
# @note This adds a method with the name `unsafe_unmunge` in the created parameter class.
|
184
184
|
# @dsl type
|
185
185
|
# @api public
|
186
186
|
#
|
187
187
|
def unmunge(&block)
|
188
|
-
define_method(:
|
188
|
+
define_method(:unsafe_unmunge, &block)
|
189
189
|
end
|
190
190
|
|
191
191
|
# Sets a marker indicating that this parameter is the _namevar_ (unique identifier) of the type
|
@@ -415,10 +415,21 @@ class Puppet::Parameter
|
|
415
415
|
# @return [Object] the unmunged value
|
416
416
|
#
|
417
417
|
def unmunge(value)
|
418
|
+
return value if value.is_a?(Puppet::Pops::Evaluator::DeferredValue)
|
419
|
+
|
420
|
+
unsafe_unmunge(value)
|
421
|
+
end
|
422
|
+
|
423
|
+
# This is the default implementation of `unmunge` that simply produces the value (if it is valid).
|
424
|
+
# The DSL method {unmunge} should be used to define an overriding method if unmunging is required.
|
425
|
+
#
|
426
|
+
# @api private
|
427
|
+
#
|
428
|
+
def unsafe_unmunge(value)
|
418
429
|
value
|
419
430
|
end
|
420
431
|
|
421
|
-
# Munges the value to internal form.
|
432
|
+
# Munges the value from DSL form to internal form.
|
422
433
|
# This implementation of `munge` provides exception handling around the specified munging of this parameter.
|
423
434
|
# @note This method should not be overridden. Use the DSL method {munge} to define a munging method
|
424
435
|
# if required.
|
@@ -426,6 +437,8 @@ class Puppet::Parameter
|
|
426
437
|
# @return [Object] the munged (internal) value
|
427
438
|
#
|
428
439
|
def munge(value)
|
440
|
+
return value if value.is_a?(Puppet::Pops::Evaluator::DeferredValue)
|
441
|
+
|
429
442
|
begin
|
430
443
|
ret = unsafe_munge(value)
|
431
444
|
rescue Puppet::Error => detail
|
@@ -459,6 +472,8 @@ class Puppet::Parameter
|
|
459
472
|
# @api public
|
460
473
|
#
|
461
474
|
def validate(value)
|
475
|
+
return if value.is_a?(Puppet::Pops::Evaluator::DeferredValue)
|
476
|
+
|
462
477
|
begin
|
463
478
|
unsafe_validate(value)
|
464
479
|
rescue ArgumentError => detail
|
@@ -3,6 +3,16 @@ require_relative '../../../puppet/parser/script_compiler'
|
|
3
3
|
module Puppet::Pops
|
4
4
|
module Evaluator
|
5
5
|
|
6
|
+
class DeferredValue
|
7
|
+
def initialize(proc)
|
8
|
+
@proc = proc
|
9
|
+
end
|
10
|
+
|
11
|
+
def resolve
|
12
|
+
@proc.call
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
6
16
|
# Utility class to help resolve instances of Puppet::Pops::Types::PDeferredType::Deferred
|
7
17
|
#
|
8
18
|
class DeferredResolver
|
@@ -20,9 +30,9 @@ class DeferredResolver
|
|
20
30
|
# are to be mixed into the scope
|
21
31
|
# @return [nil] does not return anything - the catalog is modified as a side effect
|
22
32
|
#
|
23
|
-
def self.resolve_and_replace(facts, catalog, environment = catalog.environment_instance)
|
24
|
-
compiler = Puppet::Parser::ScriptCompiler.new(environment, catalog.name,
|
25
|
-
resolver = new(compiler)
|
33
|
+
def self.resolve_and_replace(facts, catalog, environment = catalog.environment_instance, preprocess_deferred = true)
|
34
|
+
compiler = Puppet::Parser::ScriptCompiler.new(environment, catalog.name, preprocess_deferred)
|
35
|
+
resolver = new(compiler, preprocess_deferred)
|
26
36
|
resolver.set_facts_variable(facts)
|
27
37
|
# TODO:
|
28
38
|
# # When scripting the trusted data are always local, but set them anyway
|
@@ -53,11 +63,12 @@ class DeferredResolver
|
|
53
63
|
resolver.resolve(value)
|
54
64
|
end
|
55
65
|
|
56
|
-
def initialize(compiler)
|
66
|
+
def initialize(compiler, preprocess_deferred = true)
|
57
67
|
@compiler = compiler
|
58
68
|
# Always resolve in top scope
|
59
69
|
@scope = @compiler.topscope
|
60
70
|
@deferred_class = Puppet::Pops::Types::TypeFactory.deferred.implementation_class
|
71
|
+
@preprocess_deferred = preprocess_deferred
|
61
72
|
end
|
62
73
|
|
63
74
|
# @param facts [Puppet::Node::Facts] the facts to set in $facts in the compiler's topscope
|
@@ -106,6 +117,24 @@ class DeferredResolver
|
|
106
117
|
end
|
107
118
|
end
|
108
119
|
|
120
|
+
def resolve_lazy_args(x)
|
121
|
+
if x.is_a?(DeferredValue)
|
122
|
+
x.resolve
|
123
|
+
elsif x.is_a?(Array)
|
124
|
+
x.map {|v| resolve_lazy_args(v) }
|
125
|
+
elsif x.is_a?(Hash)
|
126
|
+
result = {}
|
127
|
+
x.each_pair {|k,v| result[k] = resolve_lazy_args(v) }
|
128
|
+
result
|
129
|
+
elsif x.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive)
|
130
|
+
# rewrap in a new Sensitive after resolving any nested deferred values
|
131
|
+
Puppet::Pops::Types::PSensitiveType::Sensitive.new(resolve_lazy_args(x.unwrap))
|
132
|
+
else
|
133
|
+
x
|
134
|
+
end
|
135
|
+
end
|
136
|
+
private :resolve_lazy_args
|
137
|
+
|
109
138
|
def resolve_future(f)
|
110
139
|
# If any of the arguments to a future is a future it needs to be resolved first
|
111
140
|
func_name = f.name
|
@@ -117,8 +146,19 @@ class DeferredResolver
|
|
117
146
|
mapped_arguments.insert(0, @scope[var_name])
|
118
147
|
end
|
119
148
|
|
120
|
-
|
121
|
-
|
149
|
+
if @preprocess_deferred
|
150
|
+
# call the function (name in deferred, or 'dig' for a variable)
|
151
|
+
@scope.call_function(func_name, mapped_arguments)
|
152
|
+
else
|
153
|
+
# call the function later
|
154
|
+
DeferredValue.new(
|
155
|
+
Proc.new {
|
156
|
+
# deferred functions can have nested deferred arguments
|
157
|
+
resolved_arguments = mapped_arguments.map { |arg| resolve_lazy_args(arg) }
|
158
|
+
@scope.call_function(func_name, resolved_arguments)
|
159
|
+
}
|
160
|
+
)
|
161
|
+
end
|
122
162
|
end
|
123
163
|
|
124
164
|
def map_arguments(args)
|
@@ -19,6 +19,10 @@ class Puppet::Pops::Functions::Dispatcher
|
|
19
19
|
@dispatchers.empty?
|
20
20
|
end
|
21
21
|
|
22
|
+
def find_matching_dispatcher(args, &block)
|
23
|
+
@dispatchers.find { |d| d.type.callable_with?(args, block) }
|
24
|
+
end
|
25
|
+
|
22
26
|
# Dispatches the call to the first found signature (entry with matching type).
|
23
27
|
#
|
24
28
|
# @param instance [Puppet::Functions::Function] - the function to call
|
@@ -28,19 +32,19 @@ class Puppet::Pops::Functions::Dispatcher
|
|
28
32
|
#
|
29
33
|
# @api private
|
30
34
|
def dispatch(instance, calling_scope, args, &block)
|
31
|
-
|
32
|
-
|
35
|
+
|
36
|
+
dispatcher = find_matching_dispatcher(args, &block)
|
37
|
+
unless dispatcher
|
33
38
|
args_type = Puppet::Pops::Types::TypeCalculator.singleton.infer_set(block_given? ? args + [block] : args)
|
34
39
|
raise ArgumentError, Puppet::Pops::Types::TypeMismatchDescriber.describe_signatures(instance.class.name, signatures, args_type)
|
35
40
|
end
|
36
|
-
|
37
|
-
|
38
|
-
msg = found.invoke(instance, calling_scope, args)
|
41
|
+
if dispatcher.argument_mismatch_handler?
|
42
|
+
msg = dispatcher.invoke(instance, calling_scope, args)
|
39
43
|
raise ArgumentError, "'#{instance.class.name}' #{msg}"
|
40
44
|
end
|
41
45
|
|
42
46
|
catch(:next) do
|
43
|
-
|
47
|
+
dispatcher.invoke(instance, calling_scope, args, &block)
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -18,7 +18,7 @@ class Puppet::Pops::Loader::RubyLegacyFunctionInstantiator
|
|
18
18
|
def self.create(loader, typed_name, source_ref, ruby_code_string)
|
19
19
|
# Assert content of 3x function by parsing
|
20
20
|
assertion_result = []
|
21
|
-
if assert_code(ruby_code_string, assertion_result)
|
21
|
+
if assert_code(ruby_code_string, source_ref, assertion_result)
|
22
22
|
unless ruby_code_string.is_a?(String) && assertion_result.include?(:found_newfunction)
|
23
23
|
raise ArgumentError, _("The code loaded from %{source_ref} does not seem to be a Puppet 3x API function - no 'newfunction' call.") % { source_ref: source_ref }
|
24
24
|
end
|
@@ -69,15 +69,15 @@ class Puppet::Pops::Loader::RubyLegacyFunctionInstantiator
|
|
69
69
|
end
|
70
70
|
private_class_method :get_binding
|
71
71
|
|
72
|
-
def self.assert_code(code_string, result)
|
72
|
+
def self.assert_code(code_string, source_ref, result)
|
73
73
|
ripped = Ripper.sexp(code_string)
|
74
74
|
return false if ripped.nil? # Let the next real parse crash and tell where and what is wrong
|
75
|
-
ripped.each {|x| walk(x, result) }
|
75
|
+
ripped.each {|x| walk(x, source_ref, result) }
|
76
76
|
true
|
77
77
|
end
|
78
78
|
private_class_method :assert_code
|
79
79
|
|
80
|
-
def self.walk(x, result)
|
80
|
+
def self.walk(x, source_ref, result)
|
81
81
|
return unless x.is_a?(Array)
|
82
82
|
first = x[0]
|
83
83
|
case first
|
@@ -89,13 +89,14 @@ class Puppet::Pops::Loader::RubyLegacyFunctionInstantiator
|
|
89
89
|
when :def, :defs
|
90
90
|
# There should not be any calls to def in a 3x function
|
91
91
|
mname, mline = extract_name_line(find_identity(x))
|
92
|
-
raise SecurityError, _("Illegal method definition of method '%{method_name}' on line %{line} in legacy function. See %{url} for more information") % {
|
92
|
+
raise SecurityError, _("Illegal method definition of method '%{method_name}' in source %{source_ref} on line %{line} in legacy function. See %{url} for more information") % {
|
93
93
|
method_name: mname,
|
94
|
+
source_ref: source_ref,
|
94
95
|
line: mline,
|
95
96
|
url: "https://puppet.com/docs/puppet/latest/functions_refactor_legacy.html"
|
96
97
|
}
|
97
98
|
end
|
98
|
-
x.each {|v| walk(v, result) }
|
99
|
+
x.each {|v| walk(v, source_ref, result) }
|
99
100
|
end
|
100
101
|
private_class_method :walk
|
101
102
|
|
@@ -581,6 +581,15 @@ module Types
|
|
581
581
|
end
|
582
582
|
end
|
583
583
|
|
584
|
+
def get_deferred_function_return_type(value)
|
585
|
+
func = Puppet.lookup(:loaders).private_environment_loader.
|
586
|
+
load(:function, value.name)
|
587
|
+
dispatcher = func.class.dispatcher.find_matching_dispatcher(value.arguments)
|
588
|
+
raise ArgumentError, "No matching arity found for #{func.class.name} with arguments #{value.arguments}" unless dispatcher
|
589
|
+
dispatcher.type.return_type
|
590
|
+
end
|
591
|
+
private :get_deferred_function_return_type
|
592
|
+
|
584
593
|
# Validates that all entries in the _param_hash_ exists in the given param_struct, that their type conforms
|
585
594
|
# with the corresponding param_struct element and that all required values are provided.
|
586
595
|
# An error message is created for each problem found.
|
@@ -598,7 +607,19 @@ module Types
|
|
598
607
|
value = param_hash[name]
|
599
608
|
value_type = elem.value_type
|
600
609
|
if param_hash.include?(name)
|
601
|
-
|
610
|
+
if Puppet::Pops::Types::TypeFactory.deferred.implementation_class == value.class
|
611
|
+
if (df_return_type = get_deferred_function_return_type(value))
|
612
|
+
result << describe(value_type, df_return_type, [ParameterPathElement.new(name)]) unless value_type.generalize.assignable?(df_return_type.generalize)
|
613
|
+
else
|
614
|
+
warning_text = _("Deferred function %{function_name} has no return_type, unable to guarantee value type during compilation.") %
|
615
|
+
{function_name: value.name }
|
616
|
+
Puppet.warn_once('deprecations',
|
617
|
+
"#{value.name}_deferred_warning",
|
618
|
+
warning_text)
|
619
|
+
end
|
620
|
+
else
|
621
|
+
result << describe(value_type, TypeCalculator.singleton.infer_set(value), [ParameterPathElement.new(name)]) unless value_type.instance?(value)
|
622
|
+
end
|
602
623
|
else
|
603
624
|
result << MissingParameter.new(nil, name) unless missing_ok || elem.key_type.is_a?(POptionalType)
|
604
625
|
end
|