puppet 4.10.1-x86-mingw32 → 4.10.4-x86-mingw32

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 (120) hide show
  1. data/ext/project_data.yaml +1 -1
  2. data/lib/puppet.rb +40 -28
  3. data/lib/puppet/application/agent.rb +1 -1
  4. data/lib/puppet/application/apply.rb +1 -1
  5. data/lib/puppet/application/cert.rb +1 -1
  6. data/lib/puppet/application/describe.rb +1 -1
  7. data/lib/puppet/application/device.rb +1 -1
  8. data/lib/puppet/application/doc.rb +3 -3
  9. data/lib/puppet/application/filebucket.rb +1 -1
  10. data/lib/puppet/application/inspect.rb +2 -2
  11. data/lib/puppet/application/lookup.rb +1 -1
  12. data/lib/puppet/application/master.rb +1 -1
  13. data/lib/puppet/application/resource.rb +7 -7
  14. data/lib/puppet/defaults.rb +1 -1
  15. data/lib/puppet/etc.rb +75 -39
  16. data/lib/puppet/face/ca.rb +1 -1
  17. data/lib/puppet/face/catalog.rb +1 -1
  18. data/lib/puppet/face/certificate.rb +1 -1
  19. data/lib/puppet/face/certificate_request.rb +1 -1
  20. data/lib/puppet/face/certificate_revocation_list.rb +1 -1
  21. data/lib/puppet/face/config.rb +1 -1
  22. data/lib/puppet/face/epp.rb +1 -1
  23. data/lib/puppet/face/facts.rb +1 -1
  24. data/lib/puppet/face/file.rb +1 -1
  25. data/lib/puppet/face/help.rb +1 -1
  26. data/lib/puppet/face/key.rb +1 -1
  27. data/lib/puppet/face/man.rb +2 -2
  28. data/lib/puppet/face/module.rb +1 -1
  29. data/lib/puppet/face/node.rb +1 -1
  30. data/lib/puppet/face/parser.rb +1 -1
  31. data/lib/puppet/face/plugin.rb +1 -1
  32. data/lib/puppet/face/report.rb +1 -1
  33. data/lib/puppet/face/resource.rb +1 -1
  34. data/lib/puppet/face/resource_type.rb +1 -1
  35. data/lib/puppet/face/status.rb +1 -1
  36. data/lib/puppet/feature/base.rb +1 -1
  37. data/lib/puppet/functions/eyaml_lookup_key.rb +16 -12
  38. data/lib/puppet/functions/hiera.rb +9 -2
  39. data/lib/puppet/functions/hiera_array.rb +9 -2
  40. data/lib/puppet/functions/hiera_hash.rb +10 -2
  41. data/lib/puppet/functions/hiera_include.rb +17 -3
  42. data/lib/puppet/functions/hocon_data.rb +6 -0
  43. data/lib/puppet/functions/json_data.rb +4 -0
  44. data/lib/puppet/functions/yaml_data.rb +4 -0
  45. data/lib/puppet/generate/models/type/type.rb +6 -5
  46. data/lib/puppet/generate/templates/type/pcore.erb +1 -1
  47. data/lib/puppet/module_tool/skeleton/templates/generator/examples/init.pp.erb +1 -1
  48. data/lib/puppet/parser/functions/create_resources.rb +8 -0
  49. data/lib/puppet/parser/scope.rb +2 -2
  50. data/lib/puppet/pops/adapters.rb +10 -4
  51. data/lib/puppet/pops/evaluator/runtime3_resource_support.rb +0 -2
  52. data/lib/puppet/pops/evaluator/runtime3_support.rb +31 -0
  53. data/lib/puppet/pops/issues.rb +8 -0
  54. data/lib/puppet/pops/loader/loader.rb +4 -0
  55. data/lib/puppet/pops/loader/module_loaders.rb +0 -2
  56. data/lib/puppet/pops/loader/static_loader.rb +1 -1
  57. data/lib/puppet/pops/loader/type_definition_instantiator.rb +1 -1
  58. data/lib/puppet/pops/loader/typed_name.rb +1 -0
  59. data/lib/puppet/pops/loaders.rb +7 -15
  60. data/lib/puppet/pops/lookup/environment_data_provider.rb +1 -1
  61. data/lib/puppet/pops/lookup/hiera_config.rb +3 -1
  62. data/lib/puppet/pops/lookup/interpolation.rb +2 -1
  63. data/lib/puppet/pops/lookup/lookup_key.rb +1 -1
  64. data/lib/puppet/pops/lookup/module_data_provider.rb +10 -2
  65. data/lib/puppet/pops/lookup/sub_lookup.rb +10 -9
  66. data/lib/puppet/pops/parser/lexer2.rb +20 -3
  67. data/lib/puppet/pops/pcore.rb +2 -2
  68. data/lib/puppet/pops/resource/resource_type_impl.rb +2 -2
  69. data/lib/puppet/pops/semantic_error.rb +12 -0
  70. data/lib/puppet/pops/serialization/deserializer.rb +7 -4
  71. data/lib/puppet/pops/types/p_type_set_type.rb +2 -2
  72. data/lib/puppet/pops/types/string_converter.rb +5 -17
  73. data/lib/puppet/pops/types/type_set_reference.rb +1 -1
  74. data/lib/puppet/pops/validation/checker4_0.rb +4 -0
  75. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  76. data/lib/puppet/provider/nameservice.rb +12 -4
  77. data/lib/puppet/provider/package/yum.rb +8 -8
  78. data/lib/puppet/provider/user/useradd.rb +1 -1
  79. data/lib/puppet/reference/configuration.rb +1 -1
  80. data/lib/puppet/resource.rb +9 -11
  81. data/lib/puppet/resource/type_collection.rb +1 -0
  82. data/lib/puppet/type/exec.rb +32 -26
  83. data/lib/puppet/type/file/mode.rb +4 -0
  84. data/lib/puppet/util/character_encoding.rb +77 -74
  85. data/lib/puppet/util/monkey_patches.rb +3 -1
  86. data/lib/puppet/util/windows/api_types.rb +3 -0
  87. data/lib/puppet/util/windows/file.rb +1 -1
  88. data/lib/puppet/version.rb +1 -1
  89. data/locales/puppet.pot +31 -7
  90. data/spec/integration/faces/documentation_spec.rb +2 -2
  91. data/spec/integration/parser/pcore_resource_spec.rb +15 -0
  92. data/spec/integration/resource/type_collection_spec.rb +6 -0
  93. data/spec/lib/puppet/face/1.0.0/huzzah.rb +1 -1
  94. data/spec/lib/puppet/face/basetest.rb +1 -1
  95. data/spec/lib/puppet/face/huzzah.rb +1 -1
  96. data/spec/lib/puppet/face/version_matching.rb +1 -1
  97. data/spec/lib/puppet_spec/character_encoding.rb +12 -0
  98. data/spec/lib/puppet_spec/compiler.rb +7 -0
  99. data/spec/shared_examples/rhel_package_provider.rb +10 -11
  100. data/spec/unit/application/resource_spec.rb +22 -1
  101. data/spec/unit/configurer/fact_handler_spec.rb +2 -1
  102. data/spec/unit/etc_spec.rb +361 -153
  103. data/spec/unit/functions/lookup_spec.rb +118 -2
  104. data/spec/unit/parser/functions/create_resources_spec.rb +47 -6
  105. data/spec/unit/parser/scope_spec.rb +8 -0
  106. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +40 -0
  107. data/spec/unit/pops/loaders/loaders_spec.rb +141 -79
  108. data/spec/unit/pops/lookup/interpolation_spec.rb +49 -9
  109. data/spec/unit/pops/lookup/lookup_spec.rb +32 -0
  110. data/spec/unit/pops/parser/lexer2_spec.rb +28 -0
  111. data/spec/unit/pops/types/p_object_type_spec.rb +1 -1
  112. data/spec/unit/pops/types/p_type_set_type_spec.rb +1 -1
  113. data/spec/unit/pops/types/string_converter_spec.rb +21 -0
  114. data/spec/unit/pops/validator/validator_spec.rb +43 -0
  115. data/spec/unit/provider/nameservice/directoryservice_spec.rb +2 -0
  116. data/spec/unit/provider/nameservice_spec.rb +113 -3
  117. data/spec/unit/provider/user/useradd_spec.rb +13 -0
  118. data/spec/unit/resource/catalog_spec.rb +21 -0
  119. data/spec/unit/util/character_encoding_spec.rb +193 -52
  120. metadata +4 -2
@@ -14,4 +14,16 @@ class Puppet::Pops::SemanticError < RuntimeError
14
14
  @semantic = semantic
15
15
  @options = options
16
16
  end
17
+
18
+ def file
19
+ @options[:file]
20
+ end
21
+
22
+ def line
23
+ @options[:line]
24
+ end
25
+
26
+ def pos
27
+ @options[:pos]
28
+ end
17
29
  end
@@ -47,10 +47,13 @@ module Serialization
47
47
  result = type.read(val.attribute_count, self)
48
48
  if result.is_a?(Types::PObjectType)
49
49
  existing_type = loader.load(:type, result.name)
50
-
51
- # Add result to the loader unless it is the exact same instance as the existing_type. The add
52
- # will succeed when the existing_type is nil.
53
- loader.add_entry(:type, result.name, result, nil) unless result.equal?(existing_type)
50
+ if result.eql?(existing_type)
51
+ result = existing_type
52
+ else
53
+ # Add result to the loader unless it is equal to the existing_type. The add
54
+ # will only succeed when the existing_type is nil.
55
+ loader.add_entry(:type, result.name, result, nil)
56
+ end
54
57
  end
55
58
  result
56
59
  when Extension::ObjectStart
@@ -279,7 +279,7 @@ class PTypeSetType < PMetaType
279
279
  if types.is_a?(Hash)
280
280
  types.each do |type_name, value|
281
281
  full_name = "#{@name}::#{type_name}".freeze
282
- typed_name = Loader::TypedName.new(:type, full_name.downcase, name_auth)
282
+ typed_name = Loader::TypedName.new(:type, full_name, name_auth)
283
283
  type = Loader::TypeDefinitionInstantiator.create_type(full_name, value, name_auth)
284
284
  loader.set_entry(typed_name, type, Adapters::SourcePosAdapter.adapt(value).to_uri)
285
285
  types[type_name] = type
@@ -300,7 +300,7 @@ class PTypeSetType < PMetaType
300
300
  if types.is_a?(Hash)
301
301
  types.each do |type_name, value|
302
302
  full_name = "#{@name}::#{type_name}".freeze
303
- typed_name = Loader::TypedName.new(:type, full_name.downcase, name_auth)
303
+ typed_name = Loader::TypedName.new(:type, full_name, name_auth)
304
304
  meta_name = value.is_a?(Hash) ? 'Object' : 'TypeAlias'
305
305
  type = Loader::TypeDefinitionInstantiator.create_named_type(full_name, meta_name, value, name_auth)
306
306
  loader.set_entry(typed_name, type)
@@ -544,25 +544,12 @@ class StringConverter
544
544
  when :s
545
545
  val.to_s
546
546
  when :q
547
- val.to_s.inspect
548
- when :puppet
549
- puppet_safe(val.to_s)
550
- when :i, :d, :x, :o, :f, :puppet
551
- converted = convert(o, PNumericType) # rest is default
552
- "%#{f}" % converted
547
+ val.inspect
553
548
  else
554
- raise FormatError.new('Runtime', f.format, 'sqidxof')
549
+ raise FormatError.new('Runtime', f.format, 'sq')
555
550
  end
556
551
  end
557
552
 
558
- # Given an unsafe string make it safe for puppet
559
- def puppet_safe(str)
560
- str = str.inspect # all specials are now quoted
561
- # all $ variables must be quoted
562
- str.gsub!("\$", "\\\$")
563
- str
564
- end
565
-
566
553
  # Basically string_PAnyType converts the value to a String and then formats it according
567
554
  # to the resulting type
568
555
  #
@@ -839,8 +826,9 @@ class StringConverter
839
826
  f = get_format(val_type, format_map)
840
827
  case f.format
841
828
  when :p
842
- str_regexp = '/'
843
- str_regexp << (val.options == 0 ? val.source : val.to_s) << '/'
829
+ rx_s = val.options == 0 ? val.source : val.to_s
830
+ rx_s = rx_s.gsub(/\//, '\/') unless Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
831
+ str_regexp = "/#{rx_s}/"
844
832
  f.orig_fmt == '%p' ? str_regexp : Kernel.format(f.orig_fmt.gsub('p', 's'), str_regexp)
845
833
  when :s
846
834
  str_regexp = val.options == 0 ? val.source : val.to_s
@@ -37,7 +37,7 @@ class TypeSetReference
37
37
  end
38
38
 
39
39
  def resolve(type_parser, loader)
40
- typed_name = Loader::TypedName.new(:type, @name.downcase, @name_authority)
40
+ typed_name = Loader::TypedName.new(:type, @name, @name_authority)
41
41
  loaded_entry = loader.load_typed(typed_name)
42
42
  type_set = loaded_entry.nil? ? nil : loaded_entry.value
43
43
 
@@ -626,6 +626,10 @@ class Checker4_0 < Evaluator::LiteralEvaluator
626
626
  # to enable better error message of the result of the expression rather than the static instruction.
627
627
  # (This can be revised as there are static constructs that are illegal, but require updating many
628
628
  # tests that expect the detailed reporting).
629
+ type_name_expr = o.type_name
630
+ if o.form && o.form != :regular && type_name_expr.is_a?(Model::QualifiedName) && type_name_expr.value == 'class'
631
+ acceptor.accept(Issues::CLASS_NOT_VIRTUALIZABLE, o)
632
+ end
629
633
  end
630
634
 
631
635
  def check_ResourceBody(o)
@@ -31,6 +31,7 @@ class ValidatorFactory_4_0 < Factory
31
31
  p[Issues::DUPLICATE_DEFAULT] = Puppet[:strict] == :off ? :ignore : Puppet[:strict]
32
32
  p[Issues::NAME_WITH_HYPHEN] = :error
33
33
  p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :ignore
34
+ p[Issues::CLASS_NOT_VIRTUALIZABLE] = Puppet[:strict] == :off ? :warning : Puppet[:strict]
34
35
  p
35
36
  end
36
37
  end
@@ -24,10 +24,12 @@ class Puppet::Provider::NameService < Puppet::Provider
24
24
 
25
25
  def instances
26
26
  objects = []
27
- listbyname do |name|
28
- objects << new(:name => name, :ensure => :present)
27
+ Puppet::Etc.send("set#{section}ent")
28
+ begin
29
+ while ent = Puppet::Etc.send("get#{section}ent")
30
+ objects << new(:name => ent.name, :canonical_name => ent.canonical_name, :ensure => :present)
31
+ end
29
32
  end
30
-
31
33
  objects
32
34
  end
33
35
 
@@ -51,6 +53,7 @@ class Puppet::Provider::NameService < Puppet::Provider
51
53
  # List everything out by name. Abstracted a bit so that it works
52
54
  # for both users and groups.
53
55
  def listbyname
56
+ Puppet.deprecation_warning(_("listbyname is deprecated and will be removed in a future release of Puppet. Please use `self.instances` to obtain a list of users."))
54
57
  names = []
55
58
  Puppet::Etc.send("set#{section()}ent")
56
59
  begin
@@ -226,7 +229,7 @@ class Puppet::Provider::NameService < Puppet::Provider
226
229
  if @objectinfo.nil? or refresh == true
227
230
  @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
228
231
  begin
229
- @objectinfo = Puppet::Etc.send(@etcmethod, @resource[:name])
232
+ @objectinfo = Puppet::Etc.send(@etcmethod, @canonical_name)
230
233
  rescue ArgumentError
231
234
  @objectinfo = nil
232
235
  end
@@ -276,6 +279,11 @@ class Puppet::Provider::NameService < Puppet::Provider
276
279
  super
277
280
  @custom_environment = {}
278
281
  @objectinfo = nil
282
+ if resource.is_a?(Hash) && !resource[:canonical_name].nil?
283
+ @canonical_name = resource[:canonical_name]
284
+ else
285
+ @canonical_name = resource[:name]
286
+ end
279
287
  end
280
288
 
281
289
  def set(param, value)
@@ -39,17 +39,17 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
39
39
  #
40
40
  # @api private
41
41
  # @param package [String] The name of the package to query
42
- # @param enablerepo [Array<String>] A list of repositories to enable for this query
43
42
  # @param disablerepo [Array<String>] A list of repositories to disable for this query
43
+ # @param enablerepo [Array<String>] A list of repositories to enable for this query
44
44
  # @param disableexcludes [Array<String>] A list of repository excludes to disable for this query
45
45
  # @return [Hash<Symbol, String>]
46
- def self.latest_package_version(package, enablerepo, disablerepo, disableexcludes)
46
+ def self.latest_package_version(package, disablerepo, enablerepo, disableexcludes)
47
47
 
48
- key = [enablerepo, disablerepo, disableexcludes]
48
+ key = [disablerepo, enablerepo, disableexcludes]
49
49
 
50
50
  @latest_versions ||= {}
51
51
  if @latest_versions[key].nil?
52
- @latest_versions[key] = check_updates(enablerepo, disablerepo, disableexcludes)
52
+ @latest_versions[key] = check_updates(disablerepo, enablerepo, disableexcludes)
53
53
  end
54
54
 
55
55
  if @latest_versions[key][package]
@@ -61,15 +61,15 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
61
61
  # combination of repositories to enable and disable.
62
62
  #
63
63
  # @api private
64
- # @param enablerepo [Array<String>] A list of repositories to enable for this query
65
64
  # @param disablerepo [Array<String>] A list of repositories to disable for this query
65
+ # @param enablerepo [Array<String>] A list of repositories to enable for this query
66
66
  # @param disableexcludes [Array<String>] A list of repository excludes to disable for this query
67
67
  # @return [Hash<String, Array<Hash<String, String>>>] All packages that were
68
68
  # found with a list of found versions for each package.
69
- def self.check_updates(enablerepo, disablerepo, disableexcludes)
69
+ def self.check_updates(disablerepo, enablerepo, disableexcludes)
70
70
  args = [command(:cmd), 'check-update']
71
- args.concat(enablerepo.map { |repo| ["--enablerepo=#{repo}"] }.flatten)
72
71
  args.concat(disablerepo.map { |repo| ["--disablerepo=#{repo}"] }.flatten)
72
+ args.concat(enablerepo.map { |repo| ["--enablerepo=#{repo}"] }.flatten)
73
73
  args.concat(disableexcludes.map { |repo| ["--disableexcludes=#{repo}"] }.flatten)
74
74
 
75
75
  output = Puppet::Util::Execution.execute(args, :failonfail => false, :combine => false)
@@ -213,7 +213,7 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
213
213
 
214
214
  # What's the latest package version available?
215
215
  def latest
216
- upd = self.class.latest_package_version(@resource[:name], enablerepo, disablerepo, disableexcludes)
216
+ upd = self.class.latest_package_version(@resource[:name], disablerepo, enablerepo, disableexcludes)
217
217
  unless upd.nil?
218
218
  # FIXME: there could be more than one update for a package
219
219
  # because of multiarch
@@ -203,7 +203,7 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
203
203
  [:expiry, :password_min_age, :password_max_age, :password].each do |shadow_property|
204
204
  define_method(shadow_property) do
205
205
  if Puppet.features.libshadow?
206
- if ent = Shadow::Passwd.getspnam(@resource.name)
206
+ if ent = Shadow::Passwd.getspnam(@canonical_name)
207
207
  method = self.class.option(shadow_property, :method)
208
208
  return unmunge(shadow_property, ent.send(method))
209
209
  end
@@ -32,7 +32,7 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc
32
32
  val = 'Unix/Linux: /var/run/puppetlabs -- Windows: C:\ProgramData\PuppetLabs\puppet\var\run -- Non-root user: ~/.puppetlabs/var/run'
33
33
  elsif name.to_s == 'logdir'
34
34
  val = 'Unix/Linux: /var/log/puppetlabs/puppet -- Windows: C:\ProgramData\PuppetLabs\puppet\var\log -- Non-root user: ~/.puppetlabs/var/log'
35
- elsif name.to_s == 'hiera.yaml'
35
+ elsif name.to_s == 'hiera_config'
36
36
  val = '$confdir/hiera.yaml. However, if a file exists at $codedir/hiera.yaml, Puppet uses that instead.'
37
37
  end
38
38
 
@@ -168,25 +168,23 @@ class Puppet::Resource
168
168
  end
169
169
 
170
170
  def self.value_to_pson_data(value)
171
- if value.is_a? Array
171
+ if value.is_a?(Array)
172
172
  value.map{|v| value_to_pson_data(v) }
173
- elsif value.is_a? Puppet::Resource
173
+ elsif value.is_a?(Hash)
174
+ result = {}
175
+ value.each_pair { |k, v| result[value_to_pson_data(k)] = value_to_pson_data(v) }
176
+ result
177
+ elsif value.is_a?(Puppet::Resource)
174
178
  value.to_s
179
+ elsif value.is_a?(Symbol) && value == :undef
180
+ nil
175
181
  else
176
182
  value
177
183
  end
178
184
  end
179
185
 
180
186
  def yaml_property_munge(x)
181
- case x
182
- when Hash
183
- x.inject({}) { |h,kv|
184
- k,v = kv
185
- h[k] = self.class.value_to_pson_data(v)
186
- h
187
- }
188
- else self.class.value_to_pson_data(x)
189
- end
187
+ self.value.to_pson_data(x)
190
188
  end
191
189
 
192
190
  YAML_ATTRIBUTES = [:@file, :@line, :@exported, :@type, :@title, :@tags, :@parameters]
@@ -231,6 +231,7 @@ class Puppet::Resource::TypeCollection
231
231
  debug_once "Not attempting to load #{type} #{fqname} as this object was missing during a prior compilation"
232
232
  end
233
233
  else
234
+ fqname = munge_name(fqname)
234
235
  result = loader.try_load_fqname(type, fqname)
235
236
  @notfound[ fqname ] = result.nil?
236
237
  end
@@ -241,10 +241,14 @@ module Puppet
241
241
  end
242
242
 
243
243
  newparam(:refresh) do
244
- desc "How to refresh this command. By default, the exec is just
245
- called again when it receives an event from another resource,
246
- but this parameter allows you to define a different command
247
- for refreshing."
244
+ desc "An alternate command to run when the `exec` receives a refresh event
245
+ from another resource. By default, Puppet runs the main command again.
246
+ For more details, see the notes about refresh behavior above, in the
247
+ description for this resource type.
248
+
249
+ Note that this alternate command runs with the same `provider`, `path`,
250
+ `user`, and `group` as the main command. If the `path` isn't set, you
251
+ must fully qualify the command's name."
248
252
 
249
253
  validate do |command|
250
254
  provider.validatecmd(command)
@@ -406,8 +410,10 @@ module Puppet
406
410
 
407
411
  newcheck(:unless) do
408
412
  desc <<-'EOT'
409
- If this parameter is set, then this `exec` will run unless
410
- the command has an exit code of 0. For example:
413
+ A test command that checks the state of the target system and restricts
414
+ when the `exec` can run. If present, Puppet runs this test command
415
+ first, then runs the main command unless the test has an exit code of 0
416
+ (success). For example:
411
417
 
412
418
  exec { '/bin/echo root >> /usr/lib/cron/cron.allow':
413
419
  path => '/usr/bin:/usr/sbin:/bin',
@@ -417,17 +423,16 @@ module Puppet
417
423
  This would add `root` to the cron.allow file (on Solaris) unless
418
424
  `grep` determines it's already there.
419
425
 
420
- Note that this command follows the same rules as the main command,
421
- such as which user and group it's run as.
422
- This also means it must be fully qualified if the path is not set.
423
- It also uses the same provider as the main command, so any behavior
424
- that differs by provider will match.
426
+ Note that this test command runs with the same `provider`, `path`,
427
+ `user`, and `group` as the main command. If the `path` isn't set, you
428
+ must fully qualify the command's name.
425
429
 
426
- Also note that unless can take an array as its value, e.g.:
430
+ This parameter can also take an array of commands. For example:
427
431
 
428
432
  unless => ['test -f /tmp/file1', 'test -f /tmp/file2'],
429
433
 
430
- This will only run the exec if _all_ conditions in the array return false.
434
+ This `exec` would only run if every command in the array has a
435
+ non-zero exit code.
431
436
  EOT
432
437
 
433
438
  validate do |cmds|
@@ -457,28 +462,29 @@ module Puppet
457
462
 
458
463
  newcheck(:onlyif) do
459
464
  desc <<-'EOT'
460
- If this parameter is set, then this `exec` will only run if
461
- the command has an exit code of 0. For example:
465
+ A test command that checks the state of the target system and restricts
466
+ when the `exec` can run. If present, Puppet runs this test command
467
+ first, and only runs the main command if the test has an exit code of 0
468
+ (success). For example:
462
469
 
463
470
  exec { 'logrotate':
464
- path => '/usr/bin:/usr/sbin:/bin',
465
- onlyif => 'test `du /var/log/messages | cut -f1` -gt 100000',
471
+ path => '/usr/bin:/usr/sbin:/bin',
472
+ provider => shell,
473
+ onlyif => 'test `du /var/log/messages | cut -f1` -gt 100000',
466
474
  }
467
475
 
468
- This would run `logrotate` only if that test returned true.
469
-
470
- Note that this command follows the same rules as the main command,
471
- such as which user and group it's run as.
472
- This also means it must be fully qualified if the path is not set.
476
+ This would run `logrotate` only if that test returns true.
473
477
 
474
- It also uses the same provider as the main command, so any behavior
475
- that differs by provider will match.
478
+ Note that this test command runs with the same `provider`, `path`,
479
+ `user`, and `group` as the main command. If the `path` isn't set, you
480
+ must fully qualify the command's name.
476
481
 
477
- Also note that onlyif can take an array as its value, e.g.:
482
+ This parameter can also take an array of commands. For example:
478
483
 
479
484
  onlyif => ['test -f /tmp/file1', 'test -f /tmp/file2'],
480
485
 
481
- This will only run the exec if _all_ conditions in the array return true.
486
+ This `exec` would only run if every command in the array has an
487
+ exit code of 0 (success).
482
488
  EOT
483
489
 
484
490
  validate do |cmds|
@@ -13,6 +13,10 @@ module Puppet
13
13
  notation. This value **must** be specified as a string; do not use
14
14
  un-quoted numbers to represent file modes.
15
15
 
16
+ If the mode is omitted (or explicitly set to `undef`), Puppet does not
17
+ enforce permissions on existing files and creates new files with
18
+ permissions of `0644`.
19
+
16
20
  The `file` type uses traditional Unix permission schemes and translates
17
21
  them to equivalent permissions for systems which represent permissions
18
22
  differently, including Windows. For detailed ACL controls on Windows,
@@ -2,94 +2,97 @@
2
2
 
3
3
  module Puppet::Util::CharacterEncoding
4
4
  class << self
5
- # Warning! This is a destructive method - the string supplied is modified!
5
+ # Given a string, attempts to convert a copy of the string to UTF-8. Conversion uses
6
+ # encode - the string's internal byte representation is modifed to UTF-8.
7
+ #
8
+ # This method is intended for situations where we generally trust that the
9
+ # string's bytes are a faithful representation of the current encoding
10
+ # associated with it, and can use it as a starting point for transcoding
11
+ # (conversion) to UTF-8.
12
+ #
6
13
  # @api public
7
- # @param [String] string a string to transcode / force_encode to utf-8
8
- # @return [String] string if already utf-8, OR
9
- # the same string with external encoding set to utf-8 if bytes are valid utf-8 OR
10
- # the same string transcoded to utf-8 OR
11
- # nil upon a failure to legitimately set external encoding or transcode string
12
- def convert_to_utf_8!(string)
13
- currently_valid = string.valid_encoding?
14
-
14
+ # @param [String] string a string to transcode
15
+ # @return [String] copy of the original string, in UTF-8 if transcodable
16
+ def convert_to_utf_8(string)
17
+ original_encoding = string.encoding
18
+ string_copy = string.dup
15
19
  begin
16
- if string.encoding == Encoding::UTF_8
17
- if currently_valid
18
- return string
19
- else
20
- # If a string is currently believed to be UTF-8, but is also not
21
- # valid_encoding?, we have no recourse but to fail because we have no
22
- # idea what encoding this string originally came from where it *was*
23
- # valid - all we know is it's not currently valid UTF-8.
24
- raise EncodingError
20
+ if original_encoding == Encoding::UTF_8
21
+ if !string_copy.valid_encoding?
22
+ Puppet.debug(_("%{value} is already labeled as UTF-8 but this encoding is invalid. It cannot be transcoded by Puppet.") %
23
+ { value: string.dump })
25
24
  end
26
- elsif valid_utf_8_bytes?(string)
27
- # Before we try to transcode the string, check if it is valid UTF-8 as
28
- # currently constitued (in its non-UTF-8 encoding), and if it is, limit
29
- # ourselves to setting the external encoding of the string to UTF-8
30
- # rather than actually transcoding it. We do this to handle
31
- # a couple scenarios:
32
-
33
- # The first scenario is that the string was originally valid UTF-8 but
34
- # the current puppet run is not in a UTF-8 environment. In this case,
35
- # the string will likely have invalid byte sequences (i.e.,
36
- # string.valid_encoding? == false), and attempting to transcode will
37
- # fail with Encoding::InvalidByteSequenceError, referencing the
38
- # invalid byte sequence in the original, pre-transcode, string. We
39
- # might have gotten here, for example, if puppet is run first in a
40
- # user context with UTF-8 encoding (setting the "is" value to UTF-8)
41
- # and then later run via cron without UTF-8 specified, resulting in in
42
- # EN_US (ISO-8859-1) on many systems. In this scenario we're
43
- # effectively best-guessing this string originated as UTF-8 and only
44
- # set external encoding to UTF-8 - transcoding would have failed
45
- # anyway.
46
-
47
- # The second scenario (more rare, I expect) is that this string does
48
- # NOT have invalid byte sequences (string.valid_encoding? == true),
49
- # but is *ALSO valid unicode*.
50
- # Our example case is "\u16A0" - "RUNIC LETTER FEHU FEOH FE"
51
- # http://www.fileformat.info/info/unicode/char/16A0/index.htm
52
- # 0xE1 0x9A 0xA0 / 225 154 160
53
- # These bytes are valid in ISO-8859-1 but the character they represent
54
- # transcodes cleanly in ruby to *different* characters in UTF-8.
55
- # That's not what we want if the user intended the original string as
56
- # UTF-8. We can only guess, so if the string is valid UTF-8 as
57
- # currently constituted, we default to assuming the string originated
58
- # in UTF-8 and do not transcode it - we only set external encoding.
59
- return string.force_encoding(Encoding::UTF_8)
60
- elsif currently_valid
61
- # If the string is not currently valid UTF-8 but it can be transcoded
62
- # (it is valid in its current encoding), we can guess this string was
63
- # not originally unicode. Transcode it to UTF-8. For strings with
64
- # original encodings like SHIFT_JIS, this should be the final result.
65
- return string.encode!(Encoding::UTF_8)
25
+ # String is aleady valid UTF-8 - noop
26
+ return string_copy
66
27
  else
67
- # If the string is neither valid UTF-8 as-is nor valid in its current
68
- # encoding, fail. It requires user remediation.
69
- raise EncodingError
28
+ # If the string comes to us as BINARY encoded, we don't know what it
29
+ # started as. However, to encode! we need a starting place, and our
30
+ # best guess is whatever the system currently is (default_external).
31
+ # So set external_encoding to default_external before we try to
32
+ # transcode to UTF-8.
33
+ string_copy.force_encoding(Encoding.default_external) if original_encoding == Encoding::BINARY
34
+ return string_copy.encode(Encoding::UTF_8)
70
35
  end
71
36
  rescue EncodingError => detail
37
+ # Set the encoding on our copy back to its original if we modified it
38
+ string_copy.force_encoding(original_encoding) if original_encoding == Encoding::BINARY
39
+
72
40
  # Catch both our own self-determined failure to transcode as well as any
73
41
  # error on ruby's part, ie Encoding::UndefinedConversionError on a
74
42
  # failure to encode!.
75
- Puppet.debug(_("%{error}: %{value} is not valid UTF-8 and cannot be transcoded by Puppet.") %
43
+ Puppet.debug(_("%{error}: %{value} cannot be transcoded by Puppet.") %
76
44
  { error: detail.inspect, value: string.dump })
77
- return nil
45
+ return string_copy
78
46
  end
79
47
  end
80
48
 
81
- private
49
+ # Given a string, tests if that string's bytes represent valid UTF-8, and if
50
+ # so return a copy of the string with external enocding set to UTF-8. Does
51
+ # not modify the byte representation of the string. If the string does not
52
+ # represent valid UTF-8, does not set the external encoding.
53
+ #
54
+ # This method is intended for situations where we do not believe that the
55
+ # encoding associated with a string is an accurate reflection of its actual
56
+ # bytes, i.e., effectively when we believe Ruby is incorrect in its
57
+ # assertion of the encoding of the string.
58
+ #
59
+ # @api public
60
+ # @param [String] string to set external encoding (re-label) to utf-8
61
+ # @return [String] a copy of string with external encoding set to utf-8, or
62
+ # a copy of the original string if override would result in invalid encoding.
63
+ def override_encoding_to_utf_8(string)
64
+ string_copy = string.dup
65
+ original_encoding = string_copy.encoding
66
+ return string_copy if original_encoding == Encoding::UTF_8
67
+ if string_copy.force_encoding(Encoding::UTF_8).valid_encoding?
68
+ return string_copy
69
+ else
70
+ Puppet.debug(_("%{value} is not valid UTF-8 and result of overriding encoding would be invalid.") % { value: string.dump })
71
+ # Set copy back to its original encoding before returning
72
+ return string_copy.force_encoding(original_encoding)
73
+ end
74
+ end
82
75
 
83
- # Do our best to determine if a string is valid UTF-8 via String#valid_encoding? without permanently
84
- # modifying or duplicating the string due to performance concerns
85
- # @api private
86
- # @param [String] string a string to test
87
- # @return [Boolean] whether we think the string is UTF-8 or not
88
- def valid_utf_8_bytes?(string)
89
- original_encoding = string.encoding
90
- valid = string.force_encoding(Encoding::UTF_8).valid_encoding?
91
- string.force_encoding(original_encoding)
92
- valid
76
+ REPLACEMENT_CHAR_MAP = {
77
+ Encoding::UTF_8 => "\uFFFD",
78
+ Encoding::UTF_16LE => "\xFD\xFF".force_encoding(Encoding::UTF_16LE),
79
+ }
80
+
81
+ # Given a string, return a copy of that string with any invalid byte
82
+ # sequences in its current encoding replaced with the replacement character
83
+ # "\uFFFD" (UTF-8) if the string is UTF-8 or UTF-16LE, or "?" otherwise.
84
+ # @param string a string to remove invalid byte sequences from
85
+ # @return a copy of string invalid byte sequences replaced by the unicode
86
+ # replacement character or "?" character
87
+ # @note does not modify encoding, but new string will have different bytes
88
+ # from original. Only needed for ruby 1.9.3 support.
89
+ def scrub(string)
90
+ if string.respond_to?(:scrub)
91
+ string.scrub
92
+ else
93
+ replacement_character = REPLACEMENT_CHAR_MAP[string.encoding] || '?'
94
+ string.chars.map { |c| c.valid_encoding? ? c : replacement_character }.join
95
+ end
93
96
  end
94
97
  end
95
98
  end