puppet 6.19.1 → 6.20.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +2 -16
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +30 -25
  5. data/lib/puppet/application.rb +10 -6
  6. data/lib/puppet/application/agent.rb +1 -0
  7. data/lib/puppet/application/apply.rb +3 -2
  8. data/lib/puppet/application/device.rb +1 -0
  9. data/lib/puppet/application/filebucket.rb +2 -2
  10. data/lib/puppet/application/script.rb +1 -0
  11. data/lib/puppet/application_support.rb +7 -0
  12. data/lib/puppet/configurer.rb +28 -18
  13. data/lib/puppet/defaults.rb +24 -18
  14. data/lib/puppet/environments.rb +38 -54
  15. data/lib/puppet/face/config.rb +10 -0
  16. data/lib/puppet/face/epp.rb +12 -2
  17. data/lib/puppet/face/facts.rb +60 -0
  18. data/lib/puppet/ffi/posix.rb +10 -0
  19. data/lib/puppet/ffi/posix/constants.rb +14 -0
  20. data/lib/puppet/ffi/posix/functions.rb +24 -0
  21. data/lib/puppet/functions/epp.rb +1 -0
  22. data/lib/puppet/functions/inline_epp.rb +1 -0
  23. data/lib/puppet/indirector/fact_search.rb +60 -0
  24. data/lib/puppet/indirector/facts/json.rb +27 -0
  25. data/lib/puppet/indirector/facts/yaml.rb +3 -58
  26. data/lib/puppet/indirector/json.rb +5 -1
  27. data/lib/puppet/indirector/node/json.rb +8 -0
  28. data/lib/puppet/indirector/report/json.rb +34 -0
  29. data/lib/puppet/module_tool/applications/installer.rb +48 -2
  30. data/lib/puppet/module_tool/errors/shared.rb +17 -2
  31. data/lib/puppet/network/formats.rb +2 -1
  32. data/lib/puppet/pal/pal_impl.rb +70 -17
  33. data/lib/puppet/parser/ast/leaf.rb +3 -2
  34. data/lib/puppet/parser/templatewrapper.rb +1 -1
  35. data/lib/puppet/pops/evaluator/deferred_resolver.rb +5 -3
  36. data/lib/puppet/pops/evaluator/evaluator_impl.rb +22 -3
  37. data/lib/puppet/pops/model/ast_transformer.rb +1 -1
  38. data/lib/puppet/provider/package/apt.rb +4 -0
  39. data/lib/puppet/provider/user/aix.rb +2 -2
  40. data/lib/puppet/reference/configuration.rb +6 -5
  41. data/lib/puppet/settings.rb +33 -28
  42. data/lib/puppet/settings/alias_setting.rb +37 -0
  43. data/lib/puppet/settings/base_setting.rb +26 -2
  44. data/lib/puppet/util/autoload.rb +1 -8
  45. data/lib/puppet/util/fact_dif.rb +62 -0
  46. data/lib/puppet/util/posix.rb +54 -5
  47. data/lib/puppet/util/rubygems.rb +5 -1
  48. data/lib/puppet/version.rb +1 -1
  49. data/locales/puppet.pot +188 -164
  50. data/man/man5/puppet.conf.5 +6 -6
  51. data/man/man8/puppet-agent.8 +2 -2
  52. data/man/man8/puppet-apply.8 +2 -2
  53. data/man/man8/puppet-catalog.8 +1 -1
  54. data/man/man8/puppet-config.8 +1 -1
  55. data/man/man8/puppet-describe.8 +1 -1
  56. data/man/man8/puppet-device.8 +2 -2
  57. data/man/man8/puppet-doc.8 +1 -1
  58. data/man/man8/puppet-epp.8 +1 -1
  59. data/man/man8/puppet-facts.8 +32 -1
  60. data/man/man8/puppet-filebucket.8 +3 -3
  61. data/man/man8/puppet-generate.8 +1 -1
  62. data/man/man8/puppet-help.8 +1 -1
  63. data/man/man8/puppet-key.8 +1 -1
  64. data/man/man8/puppet-lookup.8 +1 -1
  65. data/man/man8/puppet-man.8 +1 -1
  66. data/man/man8/puppet-module.8 +1 -1
  67. data/man/man8/puppet-node.8 +4 -1
  68. data/man/man8/puppet-parser.8 +1 -1
  69. data/man/man8/puppet-plugin.8 +1 -1
  70. data/man/man8/puppet-report.8 +4 -1
  71. data/man/man8/puppet-resource.8 +1 -1
  72. data/man/man8/puppet-script.8 +2 -2
  73. data/man/man8/puppet-ssl.8 +1 -1
  74. data/man/man8/puppet-status.8 +1 -1
  75. data/man/man8/puppet.8 +2 -2
  76. data/spec/fixtures/integration/application/agent/cached_deferred_catalog.json +91 -0
  77. data/spec/fixtures/unit/provider/user/aix/aix_passwd_file.out +4 -0
  78. data/spec/integration/application/agent_spec.rb +127 -3
  79. data/spec/integration/application/apply_spec.rb +19 -0
  80. data/spec/integration/defaults_spec.rb +0 -7
  81. data/spec/integration/environments/setting_hooks_spec.rb +1 -1
  82. data/spec/integration/resource/type_collection_spec.rb +2 -6
  83. data/spec/integration/transaction_spec.rb +4 -9
  84. data/spec/integration/util/windows/adsi_spec.rb +3 -1
  85. data/spec/integration/util/windows/registry_spec.rb +0 -10
  86. data/spec/lib/puppet_spec/settings.rb +6 -1
  87. data/spec/spec_helper.rb +1 -4
  88. data/spec/unit/agent_spec.rb +8 -6
  89. data/spec/unit/application/agent_spec.rb +0 -1
  90. data/spec/unit/application/config_spec.rb +224 -4
  91. data/spec/unit/application/filebucket_spec.rb +0 -2
  92. data/spec/unit/application_spec.rb +51 -9
  93. data/spec/unit/confine/feature_spec.rb +1 -1
  94. data/spec/unit/confine_spec.rb +8 -2
  95. data/spec/unit/defaults_spec.rb +20 -1
  96. data/spec/unit/environments_spec.rb +96 -19
  97. data/spec/unit/face/config_spec.rb +27 -32
  98. data/spec/unit/face/node_spec.rb +0 -11
  99. data/spec/unit/file_serving/configuration/parser_spec.rb +0 -1
  100. data/spec/unit/file_serving/metadata_spec.rb +3 -3
  101. data/spec/unit/file_serving/terminus_helper_spec.rb +11 -4
  102. data/spec/unit/forge/module_release_spec.rb +2 -7
  103. data/spec/unit/functions/inline_epp_spec.rb +26 -1
  104. data/spec/unit/http/service/compiler_spec.rb +49 -0
  105. data/spec/unit/http/service_spec.rb +1 -1
  106. data/spec/unit/indirector/face_spec.rb +0 -1
  107. data/spec/unit/indirector/facts/facter_spec.rb +0 -1
  108. data/spec/unit/indirector/facts/json_spec.rb +255 -0
  109. data/spec/unit/indirector/file_bucket_file/selector_spec.rb +26 -8
  110. data/spec/unit/indirector/indirection_spec.rb +8 -12
  111. data/spec/unit/indirector/key/file_spec.rb +0 -1
  112. data/spec/unit/indirector/node/json_spec.rb +33 -0
  113. data/spec/{integration/indirector/report/yaml.rb → unit/indirector/report/json_spec.rb} +13 -24
  114. data/spec/unit/indirector/report/yaml_spec.rb +72 -8
  115. data/spec/unit/indirector_spec.rb +2 -2
  116. data/spec/unit/module_tool/applications/installer_spec.rb +66 -0
  117. data/spec/unit/network/authconfig_spec.rb +0 -3
  118. data/spec/unit/network/http/api/indirected_routes_spec.rb +0 -9
  119. data/spec/unit/network/http/handler_spec.rb +0 -5
  120. data/spec/unit/parser/compiler_spec.rb +3 -19
  121. data/spec/unit/parser/resource_spec.rb +14 -8
  122. data/spec/unit/parser/templatewrapper_spec.rb +4 -3
  123. data/spec/unit/pops/evaluator/deferred_resolver_spec.rb +20 -0
  124. data/spec/unit/property_spec.rb +1 -0
  125. data/spec/unit/provider/nameservice_spec.rb +66 -65
  126. data/spec/unit/provider/package/apt_spec.rb +4 -8
  127. data/spec/unit/provider/package/base_spec.rb +6 -5
  128. data/spec/unit/provider/package/pacman_spec.rb +18 -12
  129. data/spec/unit/provider/package/pip_spec.rb +6 -11
  130. data/spec/unit/provider/package/pkgdmg_spec.rb +0 -4
  131. data/spec/unit/provider/user/aix_spec.rb +5 -0
  132. data/spec/unit/provider/user/hpux_spec.rb +1 -1
  133. data/spec/unit/provider/user/pw_spec.rb +2 -0
  134. data/spec/unit/provider/user/useradd_spec.rb +1 -0
  135. data/spec/unit/provider_spec.rb +8 -10
  136. data/spec/unit/puppet_pal_catalog_spec.rb +45 -0
  137. data/spec/unit/resource/capability_finder_spec.rb +6 -1
  138. data/spec/unit/resource/type_spec.rb +1 -1
  139. data/spec/unit/resource_spec.rb +11 -10
  140. data/spec/unit/settings_spec.rb +419 -242
  141. data/spec/unit/ssl/base_spec.rb +0 -1
  142. data/spec/unit/ssl/host_spec.rb +0 -5
  143. data/spec/unit/ssl/ssl_provider_spec.rb +14 -8
  144. data/spec/unit/transaction/additional_resource_generator_spec.rb +3 -7
  145. data/spec/unit/transaction/event_manager_spec.rb +14 -11
  146. data/spec/unit/transaction_spec.rb +13 -4
  147. data/spec/unit/type/file/content_spec.rb +0 -1
  148. data/spec/unit/type/file/selinux_spec.rb +0 -2
  149. data/spec/unit/type/file_spec.rb +0 -6
  150. data/spec/unit/type/group_spec.rb +13 -6
  151. data/spec/unit/type/resources_spec.rb +7 -7
  152. data/spec/unit/type/service_spec.rb +1 -1
  153. data/spec/unit/type/tidy_spec.rb +0 -1
  154. data/spec/unit/type_spec.rb +2 -2
  155. data/spec/unit/util/at_fork_spec.rb +2 -2
  156. data/spec/unit/util/autoload_spec.rb +5 -1
  157. data/spec/unit/util/backups_spec.rb +1 -2
  158. data/spec/unit/util/execution_spec.rb +15 -11
  159. data/spec/unit/util/inifile_spec.rb +6 -14
  160. data/spec/unit/util/log_spec.rb +8 -7
  161. data/spec/unit/util/logging_spec.rb +3 -3
  162. data/spec/unit/util/posix_spec.rb +363 -15
  163. data/spec/unit/util/rubygems_spec.rb +2 -2
  164. data/spec/unit/util/selinux_spec.rb +76 -52
  165. data/spec/unit/util/storage_spec.rb +3 -1
  166. data/spec/unit/util/suidmanager_spec.rb +44 -41
  167. data/spec/unit/util_spec.rb +13 -6
  168. metadata +21 -10
  169. data/spec/integration/application/config_spec.rb +0 -74
  170. data/spec/unit/face/catalog_spec.rb +0 -6
  171. data/spec/unit/face/module_spec.rb +0 -3
@@ -1,10 +1,13 @@
1
1
  require 'puppet/node/facts'
2
2
  require 'puppet/indirector/yaml'
3
+ require 'puppet/indirector/fact_search'
3
4
 
4
5
  class Puppet::Node::Facts::Yaml < Puppet::Indirector::Yaml
5
6
  desc "Store client facts as flat files, serialized using YAML, or
6
7
  return deserialized facts from disk."
7
8
 
9
+ include Puppet::Indirector::FactSearch
10
+
8
11
  def search(request)
9
12
  node_names = []
10
13
  Dir.glob(yaml_dir_path).each do |file|
@@ -23,62 +26,4 @@ class Puppet::Node::Facts::Yaml < Puppet::Indirector::Yaml
23
26
  base = Puppet.run_mode.server? ? Puppet[:yamldir] : Puppet[:clientyamldir]
24
27
  File.join(base, 'facts', '*.yaml')
25
28
  end
26
-
27
- def node_matches?(facts, options)
28
- options.each do |key, value|
29
- type, name, operator = key.to_s.split(".")
30
- operator ||= 'eq'
31
-
32
- return false unless node_matches_option?(type, name, operator, value, facts)
33
- end
34
- return true
35
- end
36
-
37
- def node_matches_option?(type, name, operator, value, facts)
38
- case type
39
- when "meta"
40
- case name
41
- when "timestamp"
42
- compare_timestamp(operator, facts.timestamp, Time.parse(value))
43
- end
44
- when "facts"
45
- compare_facts(operator, facts.values[name], value)
46
- end
47
- end
48
-
49
- def compare_facts(operator, value1, value2)
50
- return false unless value1
51
-
52
- case operator
53
- when "eq"
54
- value1.to_s == value2.to_s
55
- when "le"
56
- value1.to_f <= value2.to_f
57
- when "ge"
58
- value1.to_f >= value2.to_f
59
- when "lt"
60
- value1.to_f < value2.to_f
61
- when "gt"
62
- value1.to_f > value2.to_f
63
- when "ne"
64
- value1.to_s != value2.to_s
65
- end
66
- end
67
-
68
- def compare_timestamp(operator, value1, value2)
69
- case operator
70
- when "eq"
71
- value1 == value2
72
- when "le"
73
- value1 <= value2
74
- when "ge"
75
- value1 >= value2
76
- when "lt"
77
- value1 < value2
78
- when "gt"
79
- value1 > value2
80
- when "ne"
81
- value1 != value2
82
- end
83
- end
84
29
  end
@@ -41,12 +41,16 @@ class Puppet::Indirector::JSON < Puppet::Indirector::Terminus
41
41
  raise ArgumentError, _("invalid key")
42
42
  end
43
43
 
44
- base = Puppet.run_mode.server? ? Puppet[:server_datadir] : Puppet[:client_datadir]
44
+ base = data_dir
45
45
  File.join(base, self.class.indirection_name.to_s, name.to_s + ext)
46
46
  end
47
47
 
48
48
  private
49
49
 
50
+ def data_dir()
51
+ Puppet.run_mode.server? ? Puppet[:server_datadir] : Puppet[:client_datadir]
52
+ end
53
+
50
54
  def load_json_from_file(file, key)
51
55
  json = nil
52
56
 
@@ -0,0 +1,8 @@
1
+ require 'puppet/node'
2
+ require 'puppet/indirector/json'
3
+
4
+ class Puppet::Node::Json < Puppet::Indirector::JSON
5
+ desc "Store node information as flat files, serialized using JSON,
6
+ or deserialize stored JSON nodes."
7
+
8
+ end
@@ -0,0 +1,34 @@
1
+ require 'puppet/transaction/report'
2
+ require 'puppet/indirector/json'
3
+
4
+ class Puppet::Transaction::Report::Json < Puppet::Indirector::JSON
5
+ include Puppet::Util::SymbolicFileMode
6
+
7
+ desc "Store last report as a flat file, serialized using JSON."
8
+
9
+ # Force report to be saved there
10
+ def path(name,ext='.json')
11
+ Puppet[:lastrunreport]
12
+ end
13
+
14
+ def save(request)
15
+ filename = path(request.key)
16
+ mode = Puppet.settings.setting(:lastrunreport).mode
17
+
18
+ unless valid_symbolic_mode?(mode)
19
+ raise Puppet::DevError, _("replace_file mode: %{mode} is invalid") % { mode: mode }
20
+ end
21
+
22
+ mode = symbolic_mode_to_int(normalize_symbolic_mode(mode))
23
+
24
+ FileUtils.mkdir_p(File.dirname(filename))
25
+
26
+ begin
27
+ Puppet::FileSystem.replace_file(filename, mode) do |fh|
28
+ fh.print JSON.dump(request.instance)
29
+ end
30
+ rescue TypeError => detail
31
+ Puppet.err _("Could not save %{indirection} %{request}: %{detail}") % { indirection: self.name, request: request.key, detail: detail }
32
+ end
33
+ end
34
+ end
@@ -131,8 +131,54 @@ module Puppet::ModuleTool
131
131
  begin
132
132
  Puppet.info _("Resolving dependencies ...")
133
133
  releases = SemanticPuppet::Dependency.resolve(graph)
134
- rescue SemanticPuppet::Dependency::UnsatisfiableGraph
135
- raise NoVersionsSatisfyError, results.merge(:requested_name => name)
134
+ rescue SemanticPuppet::Dependency::UnsatisfiableGraph => e
135
+ unsatisfied = nil
136
+
137
+ if e.respond_to?(:unsatisfied)
138
+ constraints = {}
139
+ # If the module we're installing satisfies all its
140
+ # dependencies, but would break an already installed
141
+ # module that depends on it, show what would break.
142
+ if name == e.unsatisfied
143
+ graph.constraints[name].each do |mod, range, _|
144
+ next unless mod.split.include?('constraint')
145
+
146
+ # If the user requested a specific version or range,
147
+ # only show the modules with non-intersecting ranges
148
+ if options[:version]
149
+ requested_range = SemanticPuppet::VersionRange.parse(options[:version])
150
+ constraint_range = SemanticPuppet::VersionRange.parse(range)
151
+
152
+ if requested_range.intersection(constraint_range) == SemanticPuppet::VersionRange::EMPTY_RANGE
153
+ constraints[mod.split.first] = range
154
+ end
155
+ else
156
+ constraints[mod.split.first] = range
157
+ end
158
+ end
159
+
160
+ # If the module fails to satisfy one of its
161
+ # dependencies, show the unsatisfiable module
162
+ else
163
+ unsatisfied_range = graph.dependencies[name].max.constraints[e.unsatisfied].first[1]
164
+ constraints[e.unsatisfied] = unsatisfied_range
165
+ end
166
+
167
+ installed_module = @environment.module_by_forge_name(e.unsatisfied.tr('-', '/'))
168
+ current_version = installed_module.version if installed_module
169
+
170
+ unsatisfied = {
171
+ :name => e.unsatisfied,
172
+ :constraints => constraints,
173
+ :current_version => current_version
174
+ }
175
+ end
176
+
177
+ raise NoVersionsSatisfyError, results.merge(
178
+ :requested_name => name,
179
+ :requested_version => options[:version] || graph.dependencies[name].max.version.to_s,
180
+ :unsatisfied => unsatisfied
181
+ )
136
182
  end
137
183
 
138
184
  unless forced?
@@ -7,6 +7,7 @@ module Puppet::ModuleTool::Errors
7
7
  @installed_version = options[:installed_version]
8
8
  @conditions = options[:conditions]
9
9
  @action = options[:action]
10
+ @unsatisfied = options[:unsatisfied]
10
11
 
11
12
  super _("Could not %{action} '%{module_name}' (%{version}); no version satisfies all dependencies") % { action: @action, module_name: @requested_name, version: vstring }
12
13
  end
@@ -14,9 +15,23 @@ module Puppet::ModuleTool::Errors
14
15
  def multiline
15
16
  message = []
16
17
  message << _("Could not %{action} module '%{module_name}' (%{version})") % { action: @action, module_name: @requested_name, version: vstring }
17
- message << _(" No version of '%{module_name}' can satisfy all dependencies") % { module_name: @requested_name }
18
+
19
+ if @unsatisfied
20
+ message << _(" The requested version cannot satisfy one or more of the following installed modules:")
21
+ if @unsatisfied[:current_version]
22
+ message << _(" %{name}, installed: %{current_version}, expected: %{constraints}") % { name: @unsatisfied[:name], current_version: @unsatisfied[:current_version], constraints: @unsatisfied[:constraints][@unsatisfied[:name]] }
23
+ else
24
+ @unsatisfied[:constraints].each do |mod, range|
25
+ message << _(" %{mod}, expects '%{name}': %{range}") % { mod: mod, name: @requested_name, range: range }
26
+ end
27
+ end
28
+ message << _("")
29
+ else
30
+ message << _(" The requested version cannot satisfy all dependencies")
31
+ end
32
+
18
33
  #TRANSLATORS `puppet module %{action} --ignore-dependencies` is a command line and should not be translated
19
- message << _(" Use `puppet module %{action} --ignore-dependencies` to %{action} only this module") % { action: @action }
34
+ message << _(" Use `puppet module %{action} '%{module_name}' --ignore-dependencies` to %{action} only this module") % { action: @action, module_name: @requested_name }
20
35
  message.join("\n")
21
36
  end
22
37
  end
@@ -255,7 +255,8 @@ Puppet::Network::FormatHandler.create_serialized_formats(:rich_data_msgpack, mim
255
255
  end
256
256
 
257
257
  def supported?(klass)
258
- klass == Puppet::Resource::Catalog &&
258
+ suitable? &&
259
+ klass == Puppet::Resource::Catalog &&
259
260
  Puppet.lookup(:current_environment).rich_data?
260
261
  end
261
262
  end
@@ -58,8 +58,8 @@ module Pal
58
58
  configured_by_env: false,
59
59
  manifest_file: nil,
60
60
  code_string: nil,
61
- facts: nil,
62
- variables: nil,
61
+ facts: {},
62
+ variables: {},
63
63
  set_local_facts: true,
64
64
  &block
65
65
  )
@@ -93,7 +93,14 @@ module Pal
93
93
 
94
94
  # If manifest_file is nil, the #main method will use the env configured manifest
95
95
  # to do things in the block while a Script Compiler is in effect
96
- main(manifest_file, facts, variables, :script, set_local_facts, &block)
96
+ main(
97
+ manifest: manifest_file,
98
+ facts: facts,
99
+ variables: variables,
100
+ internal_compiler_class: :script,
101
+ set_local_facts: set_local_facts,
102
+ &block
103
+ )
97
104
  ensure
98
105
  Puppet[:tasks] = previous_tasks_value
99
106
  Puppet[:code] = previous_code_value
@@ -157,8 +164,9 @@ module Pal
157
164
  configured_by_env: false,
158
165
  manifest_file: nil,
159
166
  code_string: nil,
160
- facts: nil,
161
- variables: nil,
167
+ facts: {},
168
+ variables: {},
169
+ target_variables: {},
162
170
  &block
163
171
  )
164
172
  # TRANSLATORS: do not translate variable name strings in these assertions
@@ -193,7 +201,15 @@ module Pal
193
201
 
194
202
  # If manifest_file is nil, the #main method will use the env configured manifest
195
203
  # to do things in the block while a Script Compiler is in effect
196
- main(manifest_file, facts, variables, :catalog, false, &block)
204
+ main(
205
+ manifest: manifest_file,
206
+ facts: facts,
207
+ variables: variables,
208
+ target_variables: target_variables,
209
+ internal_compiler_class: :catalog,
210
+ set_local_facts: false,
211
+ &block
212
+ )
197
213
  ensure
198
214
  # Clean up after ourselves
199
215
  Puppet[:tasks] = previous_tasks_value
@@ -382,11 +398,12 @@ module Pal
382
398
  # the provided block
383
399
  #
384
400
  def self.main(
385
- manifest,
386
- facts,
387
- variables,
388
- internal_compiler_class,
389
- set_local_facts
401
+ manifest: nil,
402
+ facts: {},
403
+ variables: {},
404
+ target_variables: {},
405
+ internal_compiler_class: nil,
406
+ set_local_facts: true
390
407
  )
391
408
  # Configure the load path
392
409
  env = Puppet.lookup(:pal_env)
@@ -403,14 +420,11 @@ module Pal
403
420
  pal_variables = Puppet.lookup(:pal_variables)
404
421
 
405
422
  overrides = {}
423
+
406
424
  unless facts.nil? || facts.empty?
407
425
  pal_facts = pal_facts.merge(facts)
408
426
  overrides[:pal_facts] = pal_facts
409
427
  end
410
- unless variables.nil? || variables.empty?
411
- pal_variables = pal_variables.merge(variables)
412
- overrides[:pal_variables] = pal_variables
413
- end
414
428
 
415
429
  prepare_node_facts(node, pal_facts)
416
430
 
@@ -463,10 +477,17 @@ module Pal
463
477
  # TRANSLATORS: Do not translate, symbolic name
464
478
  Puppet.override(overrides, "PAL::with_#{internal_compiler_class}_compiler") do
465
479
  compiler.compile do | compiler_yield |
466
- # In case the varaibles passed to the compiler are PCore types defined in modules, they
480
+ # In case the variables passed to the compiler are PCore types defined in modules, they
467
481
  # need to be deserialized and added from within the this scope, so that loaders are
468
482
  # available during deserizlization.
469
- add_variables(compiler.topscope, Puppet::Pops::Serialization::FromDataConverter.convert(pal_variables))
483
+ pal_variables = Puppet::Pops::Serialization::FromDataConverter.convert(pal_variables)
484
+ variables = Puppet::Pops::Serialization::FromDataConverter.convert(variables)
485
+
486
+ # Merge together target variables and plan variables. This will also shadow any
487
+ # collisions with facts and emit a warning.
488
+ topscope_vars = pal_variables.merge(merge_vars(target_variables, variables, node.facts.values))
489
+
490
+ add_variables(compiler.topscope, topscope_vars)
470
491
  # wrap the internal compiler to prevent it from leaking in the PAL API
471
492
  if block_given?
472
493
  yield(pal_compiler)
@@ -486,6 +507,38 @@ module Pal
486
507
  end
487
508
  private_class_method :main
488
509
 
510
+ # Warn and remove variables that will be shadowed by facts of the same
511
+ # name, which are set in scope earlier.
512
+ def self.merge_vars(target_vars, vars, facts)
513
+ # First, shadow plan and target variables by facts of the same name
514
+ vars = shadow_vars(facts || {}, vars, 'fact', 'plan variable')
515
+ target_vars = shadow_vars(facts || {}, target_vars, 'fact', 'target variable')
516
+ # Then, shadow target variables by plan variables of the same name
517
+ target_vars = shadow_vars(vars, target_vars, 'plan variable', 'target variable')
518
+
519
+ target_vars.merge(vars)
520
+ end
521
+ private_class_method :merge_vars
522
+
523
+ def self.shadow_vars(vars, other_vars, vars_type, other_vars_type)
524
+ collisions, valid = other_vars.partition do |k, _|
525
+ vars.include?(k)
526
+ end
527
+
528
+ if collisions.any?
529
+ names = collisions.map { |k, _| "$#{k}" }.join(', ')
530
+ plural = collisions.length == 1 ? '' : 's'
531
+
532
+ Puppet.warning(
533
+ "#{other_vars_type.capitalize}#{plural} #{names} will be overridden by "\
534
+ "#{vars_type}#{plural} of the same name in the apply block"
535
+ )
536
+ end
537
+
538
+ valid.to_h
539
+ end
540
+ private_class_method :shadow_vars
541
+
489
542
  def self.create_internal_compiler(compiler_class_reference, node)
490
543
  case compiler_class_reference
491
544
  when :script
@@ -50,8 +50,9 @@ class Puppet::Parser::AST::HostName < Puppet::Parser::AST::Leaf
50
50
  end
51
51
 
52
52
  class Puppet::Parser::AST::Regex < Puppet::Parser::AST::Leaf
53
- def initialize(hash)
54
- super(**hash)
53
+ def initialize(value: nil, file: nil, line: nil, pos: nil)
54
+ super(value: value, file: file, line: line, pos: pos)
55
+
55
56
  # transform value from hash options unless it is already a regular expression
56
57
  @value = Regexp.new(@value) unless @value.is_a?(Regexp)
57
58
  end
@@ -50,7 +50,7 @@ class Puppet::Parser::TemplateWrapper
50
50
  # @return [Array<String>] The tags defined in the current scope
51
51
  # @api public
52
52
  def tags
53
- scope.tags
53
+ raise NotImplementedError, "Call 'all_tags' instead."
54
54
  end
55
55
 
56
56
  # @return [Array<String>] All the defined tags
@@ -16,10 +16,12 @@ class DeferredResolver
16
16
  #
17
17
  # @param facts [Puppet::Node::Facts] the facts object for the node
18
18
  # @param catalog [Puppet::Resource::Catalog] the catalog where all deferred values should be replaced
19
+ # @param environment [Puppet::Node::Environment] the environment whose anonymous module methods
20
+ # are to be mixed into the scope
19
21
  # @return [nil] does not return anything - the catalog is modified as a side effect
20
22
  #
21
- def self.resolve_and_replace(facts, catalog)
22
- compiler = Puppet::Parser::ScriptCompiler.new(catalog.environment_instance, catalog.name, true)
23
+ def self.resolve_and_replace(facts, catalog, environment = catalog.environment_instance)
24
+ compiler = Puppet::Parser::ScriptCompiler.new(environment, catalog.name, true)
23
25
  resolver = new(compiler)
24
26
  resolver.set_facts_variable(facts)
25
27
  # TODO:
@@ -108,7 +110,7 @@ class DeferredResolver
108
110
  # If any of the arguments to a future is a future it needs to be resolved first
109
111
  func_name = f.name
110
112
  mapped_arguments = map_arguments(f.arguments)
111
- # if name starts with $ then this is a call to dig
113
+ # if name starts with $ then this is a call to dig
112
114
  if func_name[0] == DOLLAR
113
115
  var_name = func_name[1..-1]
114
116
  func_name = DIG
@@ -462,10 +462,24 @@ class EvaluatorImpl
462
462
  end
463
463
 
464
464
  def eval_EppExpression(o, scope)
465
+ contains_sensitive = false
466
+
465
467
  scope["@epp"] = []
466
468
  evaluate(o.body, scope)
467
- result = scope["@epp"].join
468
- result
469
+ result = scope["@epp"].map do |r|
470
+ if r.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive)
471
+ contains_sensitive = true
472
+ string(r.unwrap, scope)
473
+ else
474
+ r
475
+ end
476
+ end.join
477
+
478
+ if contains_sensitive
479
+ Puppet::Pops::Types::PSensitiveType::Sensitive.new(result)
480
+ else
481
+ result
482
+ end
469
483
  end
470
484
 
471
485
  def eval_RenderStringExpression(o, scope)
@@ -474,7 +488,12 @@ class EvaluatorImpl
474
488
  end
475
489
 
476
490
  def eval_RenderExpression(o, scope)
477
- scope["@epp"] << string(evaluate(o.expr, scope), scope)
491
+ result = evaluate(o.expr, scope)
492
+ if result.instance_of?(Puppet::Pops::Types::PSensitiveType::Sensitive)
493
+ scope["@epp"] << result
494
+ else
495
+ scope["@epp"] << string(result, scope)
496
+ end
478
497
  nil
479
498
  end
480
499