puppet 4.9.4 → 4.10.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 (124) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +6 -0
  3. data/ext/project_data.yaml +2 -2
  4. data/lib/hiera/puppet_function.rb +1 -1
  5. data/lib/puppet.rb +1 -0
  6. data/lib/puppet/application.rb +14 -0
  7. data/lib/puppet/application/inspect.rb +3 -0
  8. data/lib/puppet/defaults.rb +12 -2
  9. data/lib/puppet/etc.rb +125 -0
  10. data/lib/puppet/face/help.rb +1 -1
  11. data/lib/puppet/functions.rb +49 -4
  12. data/lib/puppet/functions/eyaml_lookup_key.rb +12 -3
  13. data/lib/puppet/functions/hocon_data.rb +9 -0
  14. data/lib/puppet/functions/json_data.rb +9 -0
  15. data/lib/puppet/functions/yaml_data.rb +9 -0
  16. data/lib/puppet/indirector/file_bucket_file/file.rb +69 -22
  17. data/lib/puppet/indirector/key/file.rb +2 -1
  18. data/lib/puppet/indirector/ssl_file.rb +24 -3
  19. data/lib/puppet/module.rb +28 -22
  20. data/lib/puppet/network/http/compression.rb +2 -1
  21. data/lib/puppet/parser/compiler.rb +15 -38
  22. data/lib/puppet/parser/functions/hiera.rb +1 -1
  23. data/lib/puppet/parser/functions/hiera_array.rb +1 -1
  24. data/lib/puppet/parser/functions/hiera_hash.rb +1 -1
  25. data/lib/puppet/parser/functions/hiera_include.rb +1 -1
  26. data/lib/puppet/parser/scope.rb +59 -17
  27. data/lib/puppet/pops/evaluator/callable_signature.rb +7 -0
  28. data/lib/puppet/pops/functions/dispatch.rb +18 -5
  29. data/lib/puppet/pops/functions/dispatcher.rb +7 -13
  30. data/lib/puppet/pops/issue_reporter.rb +1 -1
  31. data/lib/puppet/pops/issues.rb +84 -0
  32. data/lib/puppet/pops/loader/base_loader.rb +13 -5
  33. data/lib/puppet/pops/lookup/configured_data_provider.rb +8 -2
  34. data/lib/puppet/pops/lookup/data_dig_function_provider.rb +109 -19
  35. data/lib/puppet/pops/lookup/data_hash_function_provider.rb +19 -4
  36. data/lib/puppet/pops/lookup/data_provider.rb +43 -29
  37. data/lib/puppet/pops/lookup/environment_data_provider.rb +1 -1
  38. data/lib/puppet/pops/lookup/explainer.rb +1 -0
  39. data/lib/puppet/pops/lookup/function_provider.rb +36 -11
  40. data/lib/puppet/pops/lookup/global_data_provider.rb +18 -5
  41. data/lib/puppet/pops/lookup/hiera_config.rb +203 -84
  42. data/lib/puppet/pops/lookup/interpolation.rb +21 -6
  43. data/lib/puppet/pops/lookup/invocation.rb +14 -9
  44. data/lib/puppet/pops/lookup/location_resolver.rb +27 -0
  45. data/lib/puppet/pops/lookup/lookup_adapter.rb +59 -6
  46. data/lib/puppet/pops/lookup/lookup_key_function_provider.rb +9 -77
  47. data/lib/puppet/pops/lookup/module_data_provider.rb +27 -4
  48. data/lib/puppet/pops/parser/lexer2.rb +1 -1
  49. data/lib/puppet/pops/pcore.rb +3 -3
  50. data/lib/puppet/pops/types/p_object_type.rb +4 -6
  51. data/lib/puppet/pops/types/ruby_generator.rb +2 -2
  52. data/lib/puppet/pops/types/type_asserter.rb +3 -3
  53. data/lib/puppet/pops/types/type_mismatch_describer.rb +25 -7
  54. data/lib/puppet/pops/types/types.rb +20 -29
  55. data/lib/puppet/provider/exec.rb +4 -2
  56. data/lib/puppet/provider/nameservice.rb +8 -8
  57. data/lib/puppet/provider/selmodule/semodule.rb +20 -16
  58. data/lib/puppet/provider/service/src.rb +39 -39
  59. data/lib/puppet/provider/service/systemd.rb +1 -1
  60. data/lib/puppet/provider/user/aix.rb +7 -2
  61. data/lib/puppet/settings.rb +30 -17
  62. data/lib/puppet/ssl/base.rb +14 -1
  63. data/lib/puppet/ssl/certificate_authority.rb +4 -2
  64. data/lib/puppet/ssl/configuration.rb +4 -1
  65. data/lib/puppet/ssl/inventory.rb +10 -3
  66. data/lib/puppet/ssl/key.rb +7 -3
  67. data/lib/puppet/test/test_helper.rb +3 -0
  68. data/lib/puppet/type.rb +13 -1
  69. data/lib/puppet/type/exec.rb +16 -1
  70. data/lib/puppet/type/group.rb +17 -11
  71. data/lib/puppet/type/user.rb +3 -1
  72. data/lib/puppet/util.rb +1 -0
  73. data/lib/puppet/util/character_encoding.rb +95 -0
  74. data/lib/puppet/util/execution.rb +9 -6
  75. data/lib/puppet/util/reference.rb +4 -2
  76. data/lib/puppet/util/windows/file.rb +5 -1
  77. data/lib/puppet/version.rb +6 -2
  78. data/locales/config.yaml +1 -1
  79. data/locales/puppet.pot +18 -4
  80. data/spec/integration/ssl/autosign_spec.rb +18 -3
  81. data/spec/integration/ssl/key_spec.rb +104 -0
  82. data/spec/integration/type/user_spec.rb +13 -6
  83. data/spec/spec_helper.rb +7 -0
  84. data/spec/unit/application/inspect_spec.rb +9 -2
  85. data/spec/unit/data_providers/function_data_provider_spec.rb +2 -2
  86. data/spec/unit/etc_spec.rb +234 -0
  87. data/spec/unit/face/certificate_spec.rb +10 -2
  88. data/spec/unit/functions/dig_spec.rb +1 -1
  89. data/spec/unit/functions/hiera_spec.rb +40 -1
  90. data/spec/unit/functions/lookup_fixture_spec.rb +10 -10
  91. data/spec/unit/functions/lookup_spec.rb +1217 -357
  92. data/spec/unit/functions4_spec.rb +37 -1
  93. data/spec/unit/indirector/file_bucket_file/file_spec.rb +33 -2
  94. data/spec/unit/indirector/key/file_spec.rb +1 -1
  95. data/spec/unit/indirector/ssl_file_spec.rb +3 -3
  96. data/spec/unit/module_spec.rb +52 -59
  97. data/spec/unit/network/http/compression_spec.rb +39 -8
  98. data/spec/unit/parser/compiler_spec.rb +14 -0
  99. data/spec/unit/pops/loaders/loaders_spec.rb +21 -3
  100. data/spec/unit/pops/loaders/module_loaders_spec.rb +61 -0
  101. data/spec/unit/pops/lookup/context_spec.rb +56 -8
  102. data/spec/unit/pops/lookup/lookup_spec.rb +32 -1
  103. data/spec/unit/pops/parser/lexer2_spec.rb +8 -0
  104. data/spec/unit/pops/types/ruby_generator_spec.rb +48 -0
  105. data/spec/unit/pops/types/type_mismatch_describer_spec.rb +12 -3
  106. data/spec/unit/pops/types/types_spec.rb +6 -7
  107. data/spec/unit/provider/nameservice_spec.rb +12 -12
  108. data/spec/unit/provider/package/pkg_spec.rb +2 -0
  109. data/spec/unit/provider/service/src_spec.rb +5 -0
  110. data/spec/unit/ssl/base_spec.rb +9 -0
  111. data/spec/unit/ssl/certificate_authority_spec.rb +2 -2
  112. data/spec/unit/ssl/certificate_request_attributes_spec.rb +6 -0
  113. data/spec/unit/ssl/certificate_request_spec.rb +1 -1
  114. data/spec/unit/ssl/certificate_spec.rb +1 -1
  115. data/spec/unit/ssl/configuration_spec.rb +11 -2
  116. data/spec/unit/ssl/inventory_spec.rb +27 -3
  117. data/spec/unit/ssl/key_spec.rb +7 -7
  118. data/spec/unit/type/exec_spec.rb +41 -4
  119. data/spec/unit/type/file_spec.rb +4 -1
  120. data/spec/unit/util/character_encoding_spec.rb +88 -0
  121. data/spec/unit/util/execution_spec.rb +12 -0
  122. data/spec/unit/version_spec.rb +4 -0
  123. metadata +3803 -3808
  124. data/tasks/i18n.rake +0 -20
@@ -133,9 +133,17 @@ module Puppet::FileBucketFile
133
133
  return false
134
134
  end
135
135
 
136
- # @param contents_file [Object] Opaque file path
137
- # @param paths_file [Object] Opaque file path
138
- #
136
+ # @param bucket_file [Puppet::FileBucket::File] IO object representing
137
+ # content to back up
138
+ # @param files_original_path [String] Path to original source file on disk
139
+ # @param contents_file [Pathname] Opaque file path to intended backup
140
+ # location
141
+ # @param paths_file [Pathname] Opaque file path to file containing source
142
+ # file paths on disk
143
+ # @return [void]
144
+ # @raise [Puppet::FileBucket::BucketError] on possible sum collision between
145
+ # existing and new backup
146
+ # @api private
139
147
  def save_to_disk(bucket_file, files_original_path, contents_file, paths_file)
140
148
  Puppet::Util.withumask(0007) do
141
149
  unless Puppet::FileSystem.dir_exist?(paths_file)
@@ -148,15 +156,28 @@ module Puppet::FileBucketFile
148
156
  # same way when the bytes are decoded as UTF-8, continue using system encoding
149
157
  Puppet::FileSystem.exclusive_open(paths_file, 0640, 'a+:external') do |f|
150
158
  if Puppet::FileSystem.exist?(contents_file)
151
- verify_identical_file!(contents_file, bucket_file)
152
- Puppet::FileSystem.touch(contents_file)
153
- else
154
- Puppet::FileSystem.open(contents_file, 0440, 'wb') do |of|
155
- # PUP-1044 writes all of the contents
156
- bucket_file.stream() do |src|
157
- FileUtils.copy_stream(src, of)
158
- end
159
+ if verify_identical_file(contents_file, bucket_file)
160
+ Puppet.info "FileBucket got a duplicate file #{bucket_file.checksum}"
161
+ Puppet::FileSystem.touch(contents_file)
162
+ elsif contents_file_matches_checksum?(contents_file, bucket_file.checksum_data, bucket_file.checksum_type)
163
+ # If the contents or sizes don't match, but the checksum does,
164
+ # then we've found a conflict (potential hash collision).
165
+ # Unlikely, but quite bad. Don't remove the file in case it's
166
+ # needed, but ask the user to validate.
167
+ # Note: Don't print the full path to the bucket file in the
168
+ # exception to avoid disclosing file system layout on server.
169
+ Puppet.err(_("Unable to verify existing FileBucket backup at '%{path}'.") % { path: contents_file.to_path })
170
+ raise Puppet::FileBucket::BucketError, _("Existing backup and new file have different content but same checksum, %{value}. Verify existing backup and remove if incorrect.") %
171
+ { value: bucket_file.checksum }
172
+ else
173
+ # PUP-1334 If the contents_file exists but does not match its
174
+ # checksum, our backup has been corrupted. Warn about overwriting
175
+ # it, and proceed with new backup.
176
+ Puppet.warning(_("Existing backup does not match its expected sum, %{sum}. Overwriting corrupted backup.") % { sum: bucket_file.checksum })
177
+ copy_bucket_file_to_contents_file(contents_file, bucket_file)
159
178
  end
179
+ else
180
+ copy_bucket_file_to_contents_file(contents_file, bucket_file)
160
181
  end
161
182
 
162
183
  unless path_match(f, files_original_path)
@@ -189,19 +210,45 @@ module Puppet::FileBucketFile
189
210
  Puppet::FileSystem.pathname(subfile ? ::File.join(basedir, subfile) : basedir)
190
211
  end
191
212
 
192
- # @param contents_file [Object] Opaque file path
193
- # @param bucket_file [IO]
194
- def verify_identical_file!(contents_file, bucket_file)
195
- if bucket_file.size == Puppet::FileSystem.size(contents_file)
196
- if bucket_file.stream() {|s| Puppet::FileSystem.compare_stream(contents_file, s) }
197
- Puppet.info "FileBucket got a duplicate file #{bucket_file.checksum}"
198
- return
213
+ # @param contents_file [Pathname] Opaque file path to intended backup
214
+ # location
215
+ # @param bucket_file [Puppet::FileBucket::File] IO object representing
216
+ # content to back up
217
+ # @return [Boolean] whether the data in contents_file is of the same size
218
+ # and content as that in the bucket_file
219
+ # @api private
220
+ def verify_identical_file(contents_file, bucket_file)
221
+ (bucket_file.size == Puppet::FileSystem.size(contents_file)) &&
222
+ (bucket_file.stream() {|s| Puppet::FileSystem.compare_stream(contents_file, s) })
223
+ end
224
+
225
+ # @param contents_file [Pathname] Opaque file path to intended backup
226
+ # location
227
+ # @param expected_checksum_data [String] expected value of checksum of type
228
+ # checksum_type
229
+ # @param checksum_type [String] type of check sum of checksum_data, ie "md5"
230
+ # @return [Boolean] whether the checksum of the contents_file matches the
231
+ # supplied checksum
232
+ # @api private
233
+ def contents_file_matches_checksum?(contents_file, expected_checksum_data, checksum_type)
234
+ contents_file_checksum_data = Puppet::Util::Checksums.method(:"#{checksum_type}_file").call(contents_file.to_path)
235
+ contents_file_checksum_data == expected_checksum_data
236
+ end
237
+
238
+ # @param contents_file [Pathname] Opaque file path to intended backup
239
+ # location
240
+ # @param bucket_file [Puppet::FileBucket::File] IO object representing
241
+ # content to back up
242
+ # @return [void]
243
+ # @api private
244
+ def copy_bucket_file_to_contents_file(contents_file, bucket_file)
245
+ Puppet::FileSystem.open(contents_file, 0440, 'wb') do |of|
246
+ # PUP-1044 writes all of the contents
247
+ bucket_file.stream() do |src|
248
+ FileUtils.copy_stream(src, of)
199
249
  end
200
250
  end
201
-
202
- # If the contents or sizes don't match, then we've found a conflict.
203
- # Unlikely, but quite bad.
204
- raise Puppet::FileBucket::BucketError, "Got passed new contents for sum #{bucket_file.checksum}"
205
251
  end
252
+
206
253
  end
207
254
  end
@@ -39,7 +39,8 @@ class Puppet::SSL::Key::File < Puppet::Indirector::SslFile
39
39
  super
40
40
 
41
41
  begin
42
- Puppet.settings.setting(:publickeydir).open_file(public_key_path(request.key), 'w') do |f|
42
+ # RFC 1421 states PEM is 7-bit ASCII https://tools.ietf.org/html/rfc1421
43
+ Puppet.settings.setting(:publickeydir).open_file(public_key_path(request.key), 'w:ASCII') do |f|
43
44
  f.print request.instance.content.public_key.to_pem
44
45
  end
45
46
  rescue => detail
@@ -112,6 +112,8 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
112
112
 
113
113
  def create_model(name, path)
114
114
  result = model.new(name)
115
+ # calls Puppet::SSL::Base#read for subclasses of Puppet::SSL::Base
116
+ # with the exception of any overrides, like Puppet::SSL::Key
115
117
  result.read(path)
116
118
  result
117
119
  end
@@ -158,13 +160,32 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
158
160
  # Yield a filehandle set up appropriately, either with our settings doing
159
161
  # the work or opening a filehandle manually.
160
162
  def write(name, path)
163
+ # All types serialized to disk contain only ASCII content:
164
+ # * SSL::Key may be a .export(OpenSSL::Cipher::DES.new(:EDE3, :CBC), pass) or .to_pem
165
+ # * All other classes are translated to strings by calling .to_pem
166
+
167
+ # Serialization of:
168
+ # Puppet::SSL::Certificate by Puppet::SSL::Certificate::Ca, Puppet::SSL::Certificate::File
169
+ # -----BEGIN CERTIFICATE-----
170
+ # Puppet::SSL::Key by Puppet::SSL::Key::Ca, Puppet::SSL::Key::File
171
+ # -----BEGIN RSA PRIVATE KEY-----
161
172
  if ca?(name) and ca_location
162
- Puppet.settings.setting(self.class.ca_setting).open('w') { |f| yield f }
173
+ Puppet.settings.setting(self.class.ca_setting).open('w:ASCII') { |f| yield f }
174
+ # Serialization of:
175
+ # Puppet::SSL::CertificateRevocationList by Puppet::SSL::CertificateRevocationList::Ca, Puppet::SSL::CertificateRevocationList::File
176
+ # -----BEGIN X509 CRL-----
163
177
  elsif file_location
164
- Puppet.settings.setting(self.class.file_setting).open('w') { |f| yield f }
178
+ Puppet.settings.setting(self.class.file_setting).open('w:ASCII') { |f| yield f }
179
+ # Serialization of:
180
+ # Puppet::SSL::Certificate by Puppet::SSL::Certificate::Ca, Puppet::SSL::Certificate::File
181
+ # -----BEGIN CERTIFICATE-----
182
+ # Puppet::SSL::CertificateRequest by Puppet::SSL::CertificateRequest::Ca, Puppet::SSL::CertificateRequest::File
183
+ # -----BEGIN CERTIFICATE REQUEST-----
184
+ # Puppet::SSL::Key by Puppet::SSL::Key::Ca, Puppet::SSL::Key::File
185
+ # -----BEGIN RSA PRIVATE KEY-----
165
186
  elsif setting = self.class.directory_setting
166
187
  begin
167
- Puppet.settings.setting(setting).open_file(path, 'w') { |f| yield f }
188
+ Puppet.settings.setting(setting).open_file(path, 'w:ASCII') { |f| yield f }
168
189
  rescue => detail
169
190
  raise Puppet::Error, "Could not write #{path} to #{setting}: #{detail}", detail.backtrace
170
191
  end
data/lib/puppet/module.rb CHANGED
@@ -65,8 +65,7 @@ class Puppet::Module
65
65
  @environment = environment
66
66
 
67
67
  assert_validity
68
-
69
- load_metadata if has_metadata?
68
+ load_metadata
70
69
 
71
70
  @absolute_path_to_manifests = Puppet::FileSystem::PathPattern.absolute(manifests)
72
71
  end
@@ -86,24 +85,12 @@ class Puppet::Module
86
85
  end
87
86
 
88
87
  def has_metadata?
89
- return false unless metadata_file
90
-
91
- return false unless Puppet::FileSystem.exist?(metadata_file)
92
-
93
88
  begin
94
- metadata = JSON.parse(File.read(metadata_file, :encoding => 'utf-8'))
95
- rescue JSON::JSONError => e
96
- msg = "#{name} has an invalid and unparsable metadata.json file. The parse error: #{e.message}"
97
- case Puppet[:strict]
98
- when :off, :warning
99
- Puppet.warning(msg)
100
- when :error
101
- raise FaultyMetadata, msg
102
- end
103
- return false
89
+ load_metadata
90
+ @metadata.is_a?(Hash) && !@metadata.empty?
91
+ rescue Puppet::Module::MissingMetadata
92
+ false
104
93
  end
105
-
106
- return metadata.is_a?(Hash) && !metadata.keys.empty?
107
94
  end
108
95
 
109
96
  FILETYPES.each do |type, location|
@@ -151,14 +138,33 @@ class Puppet::Module
151
138
  @license_file = File.join(path, "License")
152
139
  end
153
140
 
141
+ def read_metadata
142
+ md_file = metadata_file
143
+ md_file.nil? ? {} : JSON.parse(File.read(md_file, :encoding => 'utf-8'))
144
+ rescue Errno::ENOENT
145
+ {}
146
+ rescue JSON::JSONError => e
147
+ msg = "#{name} has an invalid and unparsable metadata.json file. The parse error: #{e.message}"
148
+ case Puppet[:strict]
149
+ when :off, :warning
150
+ Puppet.warning(msg)
151
+ when :error
152
+ raise FaultyMetadata, msg
153
+ end
154
+ {}
155
+ end
156
+
154
157
  def load_metadata
155
- @metadata = data = JSON.parse(File.read(metadata_file, :encoding => 'utf-8'))
158
+ return if instance_variable_defined?(:@metadata)
159
+
160
+ @metadata = data = read_metadata
161
+ return if data.empty?
162
+
156
163
  @forge_name = data['name'].gsub('-', '/') if data['name']
157
164
 
158
165
  [:source, :author, :version, :license, :dependencies].each do |attr|
159
- unless value = data[attr.to_s]
160
- raise MissingMetadata, "No #{attr} module metadata provided for #{self.name}"
161
- end
166
+ value = data[attr.to_s]
167
+ raise MissingMetadata, "No #{attr} module metadata provided for #{self.name}" if value.nil?
162
168
 
163
169
  if attr == :dependencies
164
170
  unless value.is_a?(Array)
@@ -20,7 +20,8 @@ module Puppet::Network::HTTP::Compression
20
20
  def uncompress_body(response)
21
21
  case response['content-encoding']
22
22
  when 'gzip'
23
- return Zlib::GzipReader.new(StringIO.new(response.body)).read
23
+ # ZLib::GzipReader has an associated encoding, by default Encoding.default_external
24
+ return Zlib::GzipReader.new(StringIO.new(response.body), :encoding => Encoding::BINARY).read
24
25
  when 'deflate'
25
26
  return Zlib::Inflate.new.inflate(response.body)
26
27
  when nil, 'identity'
@@ -217,7 +217,7 @@ class Puppet::Parser::Compiler
217
217
  {
218
218
  :current_environment => environment,
219
219
  :global_scope => @topscope, # 4x placeholder for new global scope
220
- :loaders => lambda {|| loaders() }, # 4x loaders
220
+ :loaders => @loaders, # 4x loaders
221
221
  :injector => lambda {|| injector() } # 4x API - via context instead of via compiler
222
222
  }
223
223
  end
@@ -357,7 +357,7 @@ class Puppet::Parser::Compiler
357
357
  end
358
358
  end
359
359
 
360
- # Evaluates each specified class in turn. If there are any classes that
360
+ # Evaluates each specified class in turn. If there are any classes that
361
361
  # can't be found, an error is raised. This method really just creates resource objects
362
362
  # that point back to the classes, and then the resources are themselves
363
363
  # evaluated later in the process.
@@ -442,10 +442,6 @@ class Puppet::Parser::Compiler
442
442
  @injector
443
443
  end
444
444
 
445
- def loaders
446
- @loaders ||= Puppet::Pops::Loaders.new(environment)
447
- end
448
-
449
445
  def boot_injector
450
446
  create_boot_injector(nil) if @boot_injector.nil?
451
447
  @boot_injector
@@ -752,6 +748,9 @@ class Puppet::Parser::Compiler
752
748
  # Create the initial scope, it is needed early
753
749
  @topscope = Puppet::Parser::Scope.new(self)
754
750
 
751
+ # Initialize loaders and Pcore
752
+ @loaders = Puppet::Pops::Loaders.new(environment)
753
+
755
754
  # Need to compute overrides here, and remember them, because we are about to
756
755
  # enter the magic zone of known_resource_types and initial import.
757
756
  # Expensive entries in the context are bound lazily.
@@ -852,47 +851,25 @@ class Puppet::Parser::Compiler
852
851
  @topscope.set_facts(facts_hash)
853
852
  end
854
853
 
854
+ SETTINGS = 'settings'.freeze
855
+
855
856
  def create_settings_scope
856
- settings_type = Puppet::Resource::Type.new :hostclass, "settings"
857
- environment.known_resource_types.add(settings_type)
857
+ resource_types = environment.known_resource_types
858
+ settings_type = resource_types.hostclass(SETTINGS)
859
+ if settings_type.nil?
860
+ settings_type = Puppet::Resource::Type.new(:hostclass, SETTINGS)
861
+ resource_types.add(settings_type)
862
+ end
858
863
 
859
- settings_resource = Puppet::Parser::Resource.new("class", "settings", :scope => @topscope)
864
+ settings_resource = Puppet::Parser::Resource.new('class', SETTINGS, :scope => @topscope)
860
865
 
861
866
  @catalog.add_resource(settings_resource)
862
867
 
863
868
  settings_type.evaluate_code(settings_resource)
864
869
 
865
870
  scope = @topscope.class_scope(settings_type)
866
-
867
- env = environment
868
- settings_hash = {}
869
- Puppet.settings.each do |name, setting|
870
- next if name == :name
871
- s_name = name.to_s
872
- # Construct a hash (in anticipation it will be set in top scope under a name like $settings)
873
- settings_hash[s_name] = transform_setting(env[name])
874
- scope[s_name] = settings_hash[s_name]
875
- end
876
- end
877
-
878
- def transform_setting(val)
879
- case val
880
- when Integer, Float, String, TrueClass, FalseClass, NilClass
881
- val
882
- when Symbol
883
- val == :undef ? nil : val.to_s
884
- when Array
885
- val.map {|entry| transform_setting(entry) }
886
- when Hash
887
- result = {}
888
- val.each {|k,v| result[transform_setting(k)] = transform_setting(v) }
889
- result
890
- else
891
- # not ideal, but required as there are settings values that are special
892
- val.to_s
893
- end
871
+ scope.merge_settings(environment.name)
894
872
  end
895
- private :transform_setting
896
873
 
897
874
  # Return an array of all of the unevaluated resources. These will be definitions,
898
875
  # which need to get evaluated into native resources.
@@ -78,7 +78,7 @@ The returned value's data type depends on the types of the results. In the examp
78
78
  above, Hiera matches the 'users' key and returns it as a hash.
79
79
 
80
80
  The `hiera` function is deprecated in favor of using `lookup` and will be removed in 6.0.0.
81
- See https://docs.puppet.com/puppet/#{Puppet.version}/reference/deprecated_language.html.
81
+ See https://docs.puppet.com/puppet/#{Puppet.minor_version}/reference/deprecated_language.html.
82
82
  Replace the calls as follows:
83
83
 
84
84
  | from | to |
@@ -66,7 +66,7 @@ $allusers = hiera_array('users') | $key | { "Key \'${key}\' not found" }
66
66
  value is a hash, Puppet raises a type mismatch error.
67
67
 
68
68
  `hiera_array` is deprecated in favor of using `lookup` and will be removed in 6.0.0.
69
- See https://docs.puppet.com/puppet/#{Puppet.version}/reference/deprecated_language.html.
69
+ See https://docs.puppet.com/puppet/#{Puppet.minor_version}/reference/deprecated_language.html.
70
70
  Replace the calls as follows:
71
71
 
72
72
  | from | to |
@@ -76,7 +76,7 @@ $allusers = hiera_hash('users') | $key | { "Key \'${key}\' not found" }
76
76
  found in the data sources are strings or arrays, Puppet raises a type mismatch error.
77
77
 
78
78
  `hiera_hash` is deprecated in favor of using `lookup` and will be removed in 6.0.0.
79
- See https://docs.puppet.com/puppet/#{Puppet.version}/reference/deprecated_language.html.
79
+ See https://docs.puppet.com/puppet/#{Puppet.minor_version}/reference/deprecated_language.html.
80
80
  Replace the calls as follows:
81
81
 
82
82
  | from | to |
@@ -76,7 +76,7 @@ hiera_include('classes') | $key | {"Key \'${key}\' not found" }
76
76
  ~~~
77
77
 
78
78
  `hiera_include` is deprecated in favor of using a combination of `include`and `lookup` and will be
79
- removed in 6.0.0. See https://docs.puppet.com/puppet/#{Puppet.version}/reference/deprecated_language.html.
79
+ removed in 6.0.0. See https://docs.puppet.com/puppet/#{Puppet.minor_version}/reference/deprecated_language.html.
80
80
  Replace the calls as follows:
81
81
 
82
82
  | from | to |
@@ -588,7 +588,7 @@ class Puppet::Parser::Scope
588
588
  end
589
589
 
590
590
  def is_topscope?
591
- compiler and self == compiler.topscope
591
+ @compiler && equal?(@compiler.topscope)
592
592
  end
593
593
 
594
594
  def lookup_qualified_variable(class_name, variable_name, position)
@@ -710,14 +710,45 @@ class Puppet::Parser::Scope
710
710
  }
711
711
  end
712
712
 
713
- RESERVED_VARIABLE_NAMES = ['trusted', 'facts'].freeze
713
+ # Merge all settings for the given _env_name_ into this scope
714
+ # @param env_name [Symbol] the name of the environment
715
+ def merge_settings(env_name)
716
+ settings = Puppet.settings
717
+ table = effective_symtable(false)
718
+ settings.each_key do |name|
719
+ next if :name == name
720
+ table[name.to_s] = transform_setting(settings.value_sym(name, env_name))
721
+ end
722
+ nil
723
+ end
724
+
725
+ def transform_setting(val)
726
+ if val.is_a?(String) || val.is_a?(Numeric) || true == val || false == val || nil == val
727
+ val
728
+ elsif val.is_a?(Array)
729
+ val.map {|entry| transform_setting(entry) }
730
+ elsif val.is_a?(Hash)
731
+ result = {}
732
+ val.each {|k,v| result[transform_setting(k)] = transform_setting(v) }
733
+ result
734
+ else
735
+ # not ideal, but required as there are settings values that are special
736
+ :undef == val ? nil : val.to_s
737
+ end
738
+ end
739
+ private :transform_setting
740
+
741
+ VARNAME_TRUSTED = 'trusted'.freeze
742
+ VARNAME_FACTS = 'facts'.freeze
743
+ VARNAME_SERVER_FACTS = 'server_facts'.freeze
744
+ RESERVED_VARIABLE_NAMES = [VARNAME_TRUSTED, VARNAME_FACTS].freeze
714
745
 
715
746
  # Set a variable in the current scope. This will override settings
716
747
  # in scopes above, but will not allow variables in the current scope
717
748
  # to be reassigned.
718
749
  # It's preferred that you use self[]= instead of this; only use this
719
750
  # when you need to set options.
720
- def setvar(name, value, options = {})
751
+ def setvar(name, value, options = EMPTY_HASH)
721
752
  if name =~ /^[0-9]+$/
722
753
  raise Puppet::ParseError.new("Cannot assign to a numeric match result variable '$#{name}'") # unless options[:ephemeral]
723
754
  end
@@ -726,12 +757,12 @@ class Puppet::Parser::Scope
726
757
  end
727
758
 
728
759
  # Check for reserved variable names
729
- if !options[:privileged] && RESERVED_VARIABLE_NAMES.include?(name)
760
+ if (name == VARNAME_TRUSTED || name == VARNAME_FACTS) && !options[:privileged]
730
761
  raise Puppet::ParseError, "Attempt to assign to a reserved variable name: '#{name}'"
731
762
  end
732
763
 
733
764
  # Check for server_facts reserved variable name if the trusted_sever_facts setting is true
734
- if Puppet[:trusted_server_facts] && name == 'server_facts' && !options[:privileged]
765
+ if name == VARNAME_SERVER_FACTS && !options[:privileged] && Puppet[:trusted_server_facts]
735
766
  raise Puppet::ParseError, "Attempt to assign to a reserved variable name: '#{name}'"
736
767
  end
737
768
 
@@ -798,15 +829,13 @@ class Puppet::Parser::Scope
798
829
  #
799
830
  # @param use_ephemeral [Boolean] whether the top most ephemeral (of any kind) should be used or not
800
831
  def effective_symtable(use_ephemeral)
801
- s = @ephemeral.last
802
- if use_ephemeral
803
- return s || @symtable
804
- else
805
- while s && !s.is_local_scope?()
806
- s = s.parent
807
- end
808
- s || @symtable
832
+ s = @ephemeral[-1]
833
+ return s || @symtable if use_ephemeral
834
+
835
+ while s && !s.is_local_scope?()
836
+ s = s.parent
809
837
  end
838
+ s || @symtable
810
839
  end
811
840
 
812
841
  # Sets the variable value of the name given as an argument to the given value. The value is
@@ -816,12 +845,12 @@ class Puppet::Parser::Scope
816
845
  #
817
846
  # @param varname [String] The variable name to which the value is assigned. Must not contain `::`
818
847
  # @param value [String] The value to assign to the given variable name.
819
- # @param options [Hash] Additional options, not part of api.
848
+ # @param options [Hash] Additional options, not part of api and no longer used.
820
849
  #
821
850
  # @api public
822
851
  #
823
- def []=(varname, value, options = {})
824
- setvar(varname, value, options = {})
852
+ def []=(varname, value, _ = nil)
853
+ setvar(varname, value)
825
854
  end
826
855
 
827
856
  def append_value(bound_value, new_value)
@@ -901,6 +930,19 @@ class Puppet::Parser::Scope
901
930
  find_global_scope.without_ephemeral_scopes(&block)
902
931
  end
903
932
 
933
+ # Execute given block with a ephemeral scope containing the given variables
934
+ # @api private
935
+ def with_local_scope(scope_variables)
936
+ local = LocalScope.new(@ephemeral.last)
937
+ scope_variables.each_pair { |k, v| local[k] = v }
938
+ @ephemeral.push(local)
939
+ begin
940
+ yield(self)
941
+ ensure
942
+ @ephemeral.pop
943
+ end
944
+ end
945
+
904
946
  # Execute given block with all ephemeral popped from the ephemeral stack
905
947
  #
906
948
  # @api private
@@ -959,7 +1001,7 @@ class Puppet::Parser::Scope
959
1001
  new_ephemeral(true)
960
1002
  match.each {|k,v| setvar(k, v, :file => file, :line => line, :ephemeral => true) }
961
1003
  # Must always have an inner match data scope (that starts out as transparent)
962
- # In 3x slightly wasteful, since a new nested scope is created for a match
1004
+ # In 3x slightly wasteful, since a new nested scope is created for a match
963
1005
  # (TODO: Fix that problem)
964
1006
  new_ephemeral(false)
965
1007
  else