puppet 7.8.0 → 7.9.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +5 -5
  3. data/Gemfile.lock +9 -9
  4. data/README.md +4 -4
  5. data/ext/project_data.yaml +1 -0
  6. data/install.rb +0 -4
  7. data/lib/puppet.rb +3 -3
  8. data/lib/puppet/application/filebucket.rb +1 -0
  9. data/lib/puppet/application/resource.rb +15 -2
  10. data/lib/puppet/application/ssl.rb +1 -0
  11. data/lib/puppet/defaults.rb +7 -0
  12. data/lib/puppet/environments.rb +10 -0
  13. data/lib/puppet/face/help/action.erb +1 -0
  14. data/lib/puppet/face/help/face.erb +1 -0
  15. data/lib/puppet/face/node/clean.rb +1 -1
  16. data/lib/puppet/file_system/file_impl.rb +1 -1
  17. data/lib/puppet/file_system/windows.rb +2 -2
  18. data/lib/puppet/forge.rb +3 -3
  19. data/lib/puppet/forge/cache.rb +1 -1
  20. data/lib/puppet/functions/empty.rb +8 -0
  21. data/lib/puppet/functions/strftime.rb +1 -0
  22. data/lib/puppet/functions/unwrap.rb +17 -2
  23. data/lib/puppet/indirector/resource/ral.rb +6 -1
  24. data/lib/puppet/interface/documentation.rb +1 -0
  25. data/lib/puppet/module_tool/applications/installer.rb +4 -0
  26. data/lib/puppet/module_tool/errors/shared.rb +17 -0
  27. data/lib/puppet/module_tool/tar/mini.rb +1 -1
  28. data/lib/puppet/pops/types/type_mismatch_describer.rb +1 -1
  29. data/lib/puppet/provider/exec/posix.rb +16 -4
  30. data/lib/puppet/provider/package/pip.rb +15 -3
  31. data/lib/puppet/provider/package/windows.rb +14 -1
  32. data/lib/puppet/provider/package/windows/exe_package.rb +30 -1
  33. data/lib/puppet/provider/package/windows/package.rb +2 -1
  34. data/lib/puppet/provider/parsedfile.rb +3 -0
  35. data/lib/puppet/resource/type_collection.rb +2 -0
  36. data/lib/puppet/settings.rb +30 -7
  37. data/lib/puppet/settings/config_file.rb +1 -8
  38. data/lib/puppet/settings/value_translator.rb +0 -1
  39. data/lib/puppet/type/exec.rb +16 -3
  40. data/lib/puppet/type/file/mode.rb +6 -0
  41. data/lib/puppet/type/tidy.rb +1 -1
  42. data/lib/puppet/type/user.rb +1 -1
  43. data/lib/puppet/util/monkey_patches.rb +2 -17
  44. data/lib/puppet/util/symbolic_file_mode.rb +29 -17
  45. data/lib/puppet/util/windows/sid.rb +3 -1
  46. data/lib/puppet/version.rb +1 -1
  47. data/lib/puppet/x509/cert_provider.rb +3 -21
  48. data/locales/puppet.pot +207 -171
  49. data/man/man5/puppet.conf.5 +2 -2
  50. data/man/man8/puppet-agent.8 +1 -1
  51. data/man/man8/puppet-apply.8 +1 -1
  52. data/man/man8/puppet-catalog.8 +9 -9
  53. data/man/man8/puppet-config.8 +1 -1
  54. data/man/man8/puppet-describe.8 +1 -1
  55. data/man/man8/puppet-device.8 +1 -1
  56. data/man/man8/puppet-doc.8 +1 -1
  57. data/man/man8/puppet-epp.8 +1 -1
  58. data/man/man8/puppet-facts.8 +7 -7
  59. data/man/man8/puppet-filebucket.8 +1 -1
  60. data/man/man8/puppet-generate.8 +1 -1
  61. data/man/man8/puppet-help.8 +1 -1
  62. data/man/man8/puppet-lookup.8 +1 -1
  63. data/man/man8/puppet-module.8 +1 -1
  64. data/man/man8/puppet-node.8 +5 -5
  65. data/man/man8/puppet-parser.8 +1 -1
  66. data/man/man8/puppet-plugin.8 +1 -1
  67. data/man/man8/puppet-report.8 +5 -5
  68. data/man/man8/puppet-resource.8 +1 -1
  69. data/man/man8/puppet-script.8 +1 -1
  70. data/man/man8/puppet-ssl.8 +1 -1
  71. data/man/man8/puppet.8 +2 -2
  72. data/spec/fixtures/ssl/127.0.0.1-key.pem +106 -106
  73. data/spec/fixtures/ssl/127.0.0.1.pem +48 -48
  74. data/spec/fixtures/ssl/bad-basic-constraints.pem +54 -54
  75. data/spec/fixtures/ssl/bad-int-basic-constraints.pem +51 -51
  76. data/spec/fixtures/ssl/ca.pem +52 -52
  77. data/spec/fixtures/ssl/crl.pem +25 -25
  78. data/spec/fixtures/ssl/ec-key-openssl.pem +8 -0
  79. data/spec/fixtures/ssl/ec-key-pk8.pem +5 -0
  80. data/spec/fixtures/ssl/ec-key.pem +11 -11
  81. data/spec/fixtures/ssl/ec.pem +32 -32
  82. data/spec/fixtures/ssl/encrypted-ec-key.pem +12 -12
  83. data/spec/fixtures/ssl/encrypted-key.pem +107 -107
  84. data/spec/fixtures/ssl/intermediate-agent-crl.pem +25 -25
  85. data/spec/fixtures/ssl/intermediate-agent.pem +54 -54
  86. data/spec/fixtures/ssl/intermediate-crl.pem +28 -28
  87. data/spec/fixtures/ssl/intermediate.pem +51 -51
  88. data/spec/fixtures/ssl/oid-key.pem +117 -0
  89. data/spec/fixtures/ssl/oid.pem +69 -0
  90. data/spec/fixtures/ssl/pluto-key.pem +106 -106
  91. data/spec/fixtures/ssl/pluto.pem +50 -50
  92. data/spec/fixtures/ssl/request-key.pem +106 -106
  93. data/spec/fixtures/ssl/request.pem +45 -45
  94. data/spec/fixtures/ssl/revoked-key.pem +106 -106
  95. data/spec/fixtures/ssl/revoked.pem +49 -49
  96. data/spec/fixtures/ssl/signed-key.pem +106 -106
  97. data/spec/fixtures/ssl/signed.pem +47 -47
  98. data/spec/fixtures/ssl/tampered-cert.pem +49 -49
  99. data/spec/fixtures/ssl/tampered-csr.pem +45 -45
  100. data/spec/fixtures/ssl/trusted_oid_mapping.yaml +5 -0
  101. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +106 -106
  102. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +48 -48
  103. data/spec/fixtures/ssl/unknown-ca-key.pem +106 -106
  104. data/spec/fixtures/ssl/unknown-ca.pem +52 -52
  105. data/spec/integration/application/filebucket_spec.rb +11 -0
  106. data/spec/integration/application/module_spec.rb +21 -0
  107. data/spec/integration/application/resource_spec.rb +35 -1
  108. data/spec/integration/application/ssl_spec.rb +20 -0
  109. data/spec/integration/defaults_spec.rb +5 -0
  110. data/spec/integration/environments/settings_interpolation_spec.rb +0 -4
  111. data/spec/integration/indirector/facts/facter_spec.rb +90 -36
  112. data/spec/integration/type/exec_spec.rb +70 -45
  113. data/spec/lib/puppet/test_ca.rb +5 -0
  114. data/spec/lib/puppet_spec/settings.rb +1 -0
  115. data/spec/unit/environments_spec.rb +35 -0
  116. data/spec/unit/file_system_spec.rb +6 -0
  117. data/spec/unit/functions/assert_type_spec.rb +1 -1
  118. data/spec/unit/functions/empty_spec.rb +10 -0
  119. data/spec/unit/functions/lookup_spec.rb +23 -0
  120. data/spec/unit/functions/unwrap_spec.rb +8 -0
  121. data/spec/unit/functions4_spec.rb +2 -2
  122. data/spec/unit/indirector/resource/ral_spec.rb +40 -75
  123. data/spec/unit/module_tool/applications/installer_spec.rb +13 -2
  124. data/spec/unit/parser/compiler_spec.rb +29 -0
  125. data/spec/unit/parser/templatewrapper_spec.rb +12 -2
  126. data/spec/unit/pops/loaders/dependency_loader_spec.rb +0 -9
  127. data/spec/unit/pops/parser/lexer2_spec.rb +0 -4
  128. data/spec/unit/provider/package/pip_spec.rb +37 -0
  129. data/spec/unit/provider/package/windows/exe_package_spec.rb +17 -0
  130. data/spec/unit/provider/parsedfile_spec.rb +10 -0
  131. data/spec/unit/resource/type_collection_spec.rb +16 -0
  132. data/spec/unit/resource/type_spec.rb +2 -2
  133. data/spec/unit/settings/config_file_spec.rb +1 -11
  134. data/spec/unit/settings/value_translator_spec.rb +4 -5
  135. data/spec/unit/settings_spec.rb +120 -79
  136. data/spec/unit/ssl/ssl_provider_spec.rb +18 -16
  137. data/spec/unit/type/exec_spec.rb +76 -29
  138. data/spec/unit/type/file/source_spec.rb +4 -4
  139. data/spec/unit/type/tidy_spec.rb +7 -0
  140. data/spec/unit/util/ldap/connection_spec.rb +10 -10
  141. data/spec/unit/util/ldap/manager_spec.rb +2 -2
  142. data/spec/unit/util/windows/sid_spec.rb +39 -4
  143. data/spec/unit/util_spec.rb +1 -3
  144. data/spec/unit/x509/cert_provider_spec.rb +9 -1
  145. data/tasks/generate_cert_fixtures.rake +10 -1
  146. metadata +16 -3
@@ -24,7 +24,12 @@ class Puppet::Resource::Ral < Puppet::Indirector::Code
24
24
  type(request).instances.map do |res|
25
25
  res.to_resource
26
26
  end.find_all do |res|
27
- conditions.all? {|property, value| res.to_resource[property].to_s == value.to_s}
27
+ conditions.all? do |property, value|
28
+ # even though `res` is an instance of Puppet::Resource, calling
29
+ # `res[:name]` on it returns nil, and for some reason it is necessary
30
+ # to invoke the Puppet::Resource#copy_as_resource copy constructor...
31
+ res.copy_as_resource[property].to_s == value.to_s
32
+ end
28
33
  end.sort_by(&:title)
29
34
  end
30
35
 
@@ -76,6 +76,7 @@ class Puppet::Interface
76
76
  s.text(" ")
77
77
 
78
78
  options.each do |option|
79
+ next if option == :extra
79
80
  option = get_option(option)
80
81
  wrap = option.required? ? %w{ < > } : %w{ [ ] }
81
82
 
@@ -59,6 +59,10 @@ module Puppet::ModuleTool
59
59
  results = { :action => :install, :module_name => name, :module_version => version }
60
60
 
61
61
  begin
62
+ if !@local_tarball && name !~ /-/
63
+ raise InvalidModuleNameError.new(module_name: @name, suggestion: "puppetlabs-#{@name}", action: :install)
64
+ end
65
+
62
66
  installed_module = installed_modules[name]
63
67
  if installed_module
64
68
  unless forced?
@@ -127,6 +127,23 @@ module Puppet::ModuleTool::Errors
127
127
  end
128
128
  end
129
129
 
130
+ class InvalidModuleNameError < ModuleToolError
131
+ def initialize(options)
132
+ @module_name = options[:module_name]
133
+ @suggestion = options[:suggestion]
134
+ @action = options[:action]
135
+ super _("Could not %{action} '%{module_name}', did you mean '%{suggestion}'?") % { action: @action, module_name: @module_name, suggestion: @suggestion }
136
+ end
137
+
138
+ def multiline
139
+ message = []
140
+ message << _("Could not %{action} module '%{module_name}'") % { action: @action, module_name: @module_name }
141
+ message << _(" The name '%{module_name}' is invalid") % { module_name: @module_name }
142
+ message << _(" Did you mean `puppet module %{action} %{suggestion}`?") % { action: @action, suggestion: @suggestion }
143
+ message.join("\n")
144
+ end
145
+ end
146
+
130
147
  class NotInstalledError < ModuleToolError
131
148
  def initialize(options)
132
149
  @module_name = options[:module_name]
@@ -107,7 +107,7 @@ class Puppet::ModuleTool::Tar::Mini
107
107
  raise Puppet::ModuleTool::Errors::InvalidPathInPackageError, :entry_path => path, :directory => destdir
108
108
  end
109
109
 
110
- path = File.expand_path File.join(destdir, path)
110
+ path = Pathname.new(File.join(destdir, path)).cleanpath.to_path
111
111
 
112
112
  if path !~ /\A#{Regexp.escape destdir}/
113
113
  raise Puppet::ModuleTool::Errors::InvalidPathInPackageError, :entry_path => path, :directory => destdir
@@ -640,7 +640,7 @@ module Types
640
640
  result = ["#{label} expects (#{signature_string(sig)})"]
641
641
  result.concat(error_arrays[0].map { |e| " rejected:#{e.chop_path(0).format}" })
642
642
  else
643
- result = ["#{label} expects one of:"]
643
+ result = ["The function #{label} was called with arguments it does not accept. It expects one of:"]
644
644
  signatures.each_with_index do |sg, index|
645
645
  result << " (#{signature_string(sg)})"
646
646
  result.concat(error_arrays[index].map { |e| " rejected:#{e.chop_path(0).format}" })
@@ -6,10 +6,22 @@ Puppet::Type.type(:exec).provide :posix, :parent => Puppet::Provider::Exec do
6
6
  defaultfor :feature => :posix
7
7
 
8
8
  desc <<-EOT
9
- Executes external binaries directly, without passing through a shell or
10
- performing any interpolation. This is a safer and more predictable way
11
- to execute most commands, but prevents the use of globbing and shell
12
- built-ins (including control logic like "for" and "if" statements).
9
+ Executes external binaries by invoking Ruby's `Kernel.exec`.
10
+ When the command is a string, it will be executed directly,
11
+ without a shell, if it follows these rules:
12
+ - no meta characters
13
+ - no shell reserved word and no special built-in
14
+
15
+ When the command is an Array of Strings, passed as `[cmdname, arg1, ...]`
16
+ it will be executed directly(the first element is taken as a command name
17
+ and the rest are passed as parameters to command with no shell expansion)
18
+ This is a safer and more predictable way to execute most commands,
19
+ but prevents the use of globbing and shell built-ins (including control
20
+ logic like "for" and "if" statements).
21
+
22
+ If the use of globbing and shell built-ins is desired, please check
23
+ the `shell` provider
24
+
13
25
  EOT
14
26
 
15
27
  # Verify that we have the executable
@@ -126,7 +126,7 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
126
126
  if self.class.compare_pip_versions(command_version, '1.5.4') == -1
127
127
  available_versions_with_old_pip.last
128
128
  else
129
- available_versions_with_new_pip.last
129
+ available_versions_with_new_pip(command_version).last
130
130
  end
131
131
  end
132
132
 
@@ -149,15 +149,17 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
149
149
  if self.class.compare_pip_versions(command_version, '1.5.4') == -1
150
150
  available_versions_with_old_pip
151
151
  else
152
- available_versions_with_new_pip
152
+ available_versions_with_new_pip(command_version)
153
153
  end
154
154
  end
155
155
 
156
- def available_versions_with_new_pip
156
+ def available_versions_with_new_pip(command_version)
157
157
  command = resource_or_provider_command
158
158
  self.class.validate_command(command)
159
159
 
160
160
  command_and_options = [self.class.quote(command), 'install', "#{@resource[:name]}==versionplease"]
161
+ extra_arg = list_extra_flags(command_version)
162
+ command_and_options << extra_arg if extra_arg
161
163
  command_and_options << install_options if @resource[:install_options]
162
164
  execpipe command_and_options do |process|
163
165
  process.collect do |line|
@@ -328,4 +330,14 @@ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package
328
330
  path
329
331
  end
330
332
  end
333
+
334
+ private
335
+
336
+ def list_extra_flags(command_version)
337
+ klass = self.class
338
+ if klass.compare_pip_versions(command_version, '20.2.4') == 1 &&
339
+ klass.compare_pip_versions(command_version, '21.1') == -1
340
+ '--use-deprecated=legacy-resolver'
341
+ end
342
+ end
331
343
  end
@@ -30,6 +30,19 @@ Puppet::Type.type(:package).provide(:windows, :parent => Puppet::Provider::Packa
30
30
  has_feature :versionable
31
31
 
32
32
  attr_accessor :package
33
+ class << self
34
+ attr_accessor :paths
35
+ end
36
+
37
+ def self.post_resource_eval
38
+ @paths.each do |path|
39
+ begin
40
+ Puppet::FileSystem.unlink(path)
41
+ rescue => detail
42
+ raise Puppet::Error.new(_("Error when unlinking %{path}: %{detail}") % { path: path ,detail: detail.message}, detail)
43
+ end
44
+ end if @paths
45
+ end
33
46
 
34
47
  # Return an array of provider instances
35
48
  def self.instances
@@ -64,7 +77,7 @@ Puppet::Type.type(:package).provide(:windows, :parent => Puppet::Provider::Packa
64
77
 
65
78
  command = [installer.install_command(resource), install_options].flatten.compact.join(' ')
66
79
  working_dir = File.dirname(resource[:source])
67
- if !Puppet::FileSystem.exist?(working_dir) && resource[:source] =~ /\.msi"?\Z/i
80
+ unless Puppet::FileSystem.exist?(working_dir)
68
81
  working_dir = nil
69
82
  end
70
83
  output = execute(command, :failonfail => false, :combine => true, :cwd => working_dir, :suppress_window => true)
@@ -17,6 +17,11 @@ class Puppet::Provider::Package::Windows
17
17
  'WindowsInstaller',
18
18
  ]
19
19
 
20
+ def self.register(path)
21
+ Puppet::Type::Package::ProviderWindows.paths ||= []
22
+ Puppet::Type::Package::ProviderWindows.paths << path
23
+ end
24
+
20
25
  # Return an instance of the package from the registry, or nil
21
26
  def self.from_registry(name, values)
22
27
  if valid?(name, values)
@@ -55,7 +60,31 @@ class Puppet::Provider::Package::Windows
55
60
  end
56
61
 
57
62
  def self.install_command(resource)
58
- munge(resource[:source])
63
+ file_location = resource[:source]
64
+ if file_location.start_with?('http://', 'https://')
65
+ tempfile = Tempfile.new(['','.exe'])
66
+ begin
67
+ uri = URI(Puppet::Util.uri_encode(file_location))
68
+ client = Puppet.runtime[:http]
69
+ client.get(uri, options: { include_system_store: true }) do |response|
70
+ raise Puppet::HTTP::ResponseError.new(response) unless response.success?
71
+
72
+ File.open(tempfile.path, 'wb') do |file|
73
+ response.read_body do |data|
74
+ file.write(data)
75
+ end
76
+ end
77
+ end
78
+ rescue => detail
79
+ raise Puppet::Error.new(_("Error when installing %{package}: %{detail}") % { package: resource[:name] ,detail: detail.message}, detail)
80
+ ensure
81
+ self.register(tempfile.path)
82
+ tempfile.close()
83
+ file_location = tempfile.path
84
+ end
85
+ end
86
+
87
+ munge(file_location)
59
88
  end
60
89
 
61
90
  def uninstall_command
@@ -67,7 +67,8 @@ class Puppet::Provider::Package::Windows
67
67
  # REMIND: what about msp, etc
68
68
  MsiPackage
69
69
  when /\.exe"?\Z/i
70
- fail(_("The source does not exist: '%{source}'") % { source: resource[:source] }) unless Puppet::FileSystem.exist?(resource[:source])
70
+ fail(_("The source does not exist: '%{source}'") % { source: resource[:source] }) unless
71
+ Puppet::FileSystem.exist?(resource[:source]) || resource[:source].start_with?('http://', 'https://')
71
72
  ExePackage
72
73
  else
73
74
  fail(_("Don't know how to install '%{source}'") % { source: resource[:source] })
@@ -280,6 +280,9 @@ class Puppet::Provider::ParsedFile < Puppet::Provider
280
280
  def self.prefetch_target(target)
281
281
  begin
282
282
  target_records = retrieve(target)
283
+ unless target_records
284
+ raise Puppet::DevError, _("Prefetching %{target} for provider %{name} returned nil") % { target: target, name: self.name }
285
+ end
283
286
  rescue Puppet::Util::FileType::FileReadError => detail
284
287
  if @raise_prefetch_errors
285
288
  # We will raise an error later in flush_target. This way,
@@ -61,6 +61,7 @@ class Puppet::Resource::TypeCollection
61
61
  def add_hostclass(instance)
62
62
  handle_hostclass_merge(instance)
63
63
  dupe_check(instance, @hostclasses) { |dupe| _("Class '%{klass}' is already defined%{error}; cannot redefine") % { klass: instance.name, error: dupe.error_context } }
64
+ dupe_check(instance, @nodes) { |dupe| _("Node '%{klass}' is already defined%{error}; cannot be redefined as a class") % { klass: instance.name, error: dupe.error_context } }
64
65
  dupe_check(instance, @definitions) { |dupe| _("Definition '%{klass}' is already defined%{error}; cannot be redefined as a class") % { klass: instance.name, error: dupe.error_context } }
65
66
 
66
67
  @hostclasses[instance.name] = instance
@@ -93,6 +94,7 @@ class Puppet::Resource::TypeCollection
93
94
 
94
95
  def add_node(instance)
95
96
  dupe_check(instance, @nodes) { |dupe| _("Node '%{name}' is already defined%{error}; cannot redefine") % { name: instance.name, error: dupe.error_context } }
97
+ dupe_check(instance, @hostclasses) { |dupe| _("Class '%{klass}' is already defined%{error}; cannot be redefined as a node") % { klass: instance.name, error: dupe.error_context } }
96
98
 
97
99
  @node_list << instance
98
100
  @nodes[instance.name] = instance
@@ -868,7 +868,11 @@ class Puppet::Settings
868
868
  if self[:user]
869
869
  user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure
870
870
 
871
- @service_user_available = user.exists?
871
+ if user.suitable?
872
+ @service_user_available = user.exists?
873
+ else
874
+ raise Puppet::Error, (_("Cannot manage owner permissions, because the provider for '%{name}' is not functional") % { name: user })
875
+ end
872
876
  else
873
877
  @service_user_available = false
874
878
  end
@@ -880,7 +884,11 @@ class Puppet::Settings
880
884
  if self[:group]
881
885
  group = Puppet::Type.type(:group).new :name => self[:group], :audit => :ensure
882
886
 
883
- @service_group_available = group.exists?
887
+ if group.suitable?
888
+ @service_group_available = group.exists?
889
+ else
890
+ raise Puppet::Error, (_("Cannot manage group permissions, because the provider for '%{name}' is not functional") % { name: group })
891
+ end
884
892
  else
885
893
  @service_group_available = false
886
894
  end
@@ -889,9 +897,16 @@ class Puppet::Settings
889
897
  # Allow later inspection to determine if the setting was set on the
890
898
  # command line, or through some other code path. Used for the
891
899
  # `dns_alt_names` option during cert generate. --daniel 2011-10-18
892
- def set_by_cli?(param)
900
+ #
901
+ # @param param [String, Symbol] the setting to look up
902
+ # @return [Object, nil] the value of the setting or nil if unset
903
+ def set_by_cli(param)
893
904
  param = param.to_sym
894
- !@value_sets[:cli].lookup(param).nil?
905
+ @value_sets[:cli].lookup(param)
906
+ end
907
+
908
+ def set_by_cli?(param)
909
+ !!set_by_cli(param)
895
910
  end
896
911
 
897
912
  # Get values from a search path entry.
@@ -924,9 +939,13 @@ class Puppet::Settings
924
939
  end
925
940
  end
926
941
 
927
- # Allow later inspection to determine if the setting was set by user
928
- # config, rather than a default setting.
929
- def set_in_section?(param, section)
942
+ # Allow later inspection to determine if the setting was set in a specific
943
+ # section
944
+ #
945
+ # @param param [String, Symbol] the setting to look up
946
+ # @param section [Symbol] the section in which to look up the setting
947
+ # @return [Object, nil] the value of the setting or nil if unset
948
+ def set_in_section(param, section)
930
949
  param = param.to_sym
931
950
  vals = searchpath_values(SearchPathElement.new(section, :section))
932
951
  if vals
@@ -934,6 +953,10 @@ class Puppet::Settings
934
953
  end
935
954
  end
936
955
 
956
+ def set_in_section?(param, section)
957
+ !!set_in_section(param, section)
958
+ end
959
+
937
960
  # Patches the value for a param in a section.
938
961
  # This method is required to support the use case of unifying --dns-alt-names and
939
962
  # --dns_alt_names in the certificate face. Ideally this should be cleaned up.
@@ -98,14 +98,7 @@ private
98
98
 
99
99
  def parse_setting(setting, section)
100
100
  var = setting.name.intern
101
-
102
- # We don't want to munge modes, because they're specified in octal, so we'll
103
- # just leave them as a String, since Puppet handles that case correctly.
104
- if var == :mode
105
- value = setting.value
106
- else
107
- value = @value_converter[setting.value]
108
- end
101
+ value = @value_converter[setting.value]
109
102
 
110
103
  # Check to see if this is a file argument and it has extra options
111
104
  begin
@@ -5,7 +5,6 @@ class Puppet::Settings::ValueTranslator
5
5
  return case value
6
6
  when /^false$/i; false
7
7
  when /^true$/i; true
8
- when /^\d+$/i; Integer(value)
9
8
  when true; true
10
9
  when false; false
11
10
  else
@@ -201,7 +201,9 @@ module Puppet
201
201
  only uses the resource title to ensure `exec`s are unique."
202
202
 
203
203
  validate do |command|
204
- raise ArgumentError, _("Command must be a String, got value of class %{klass}") % { klass: command.class } unless command.is_a? String
204
+ unless command.is_a?(String) || command.is_a?(Array)
205
+ raise ArgumentError, _("Command must be a String or Array<String>, got value of class %{klass}") % { klass: command.class }
206
+ end
205
207
  end
206
208
  end
207
209
 
@@ -458,6 +460,10 @@ module Puppet
458
460
 
459
461
  unless => ['test -f /tmp/file1', 'test -f /tmp/file2'],
460
462
 
463
+ or an array of arrays. For example:
464
+
465
+ unless => [['test', '-f', '/tmp/file1'], 'test -f /tmp/file2']
466
+
461
467
  This `exec` would only run if every command in the array has a
462
468
  non-zero exit code.
463
469
  EOT
@@ -514,6 +520,10 @@ module Puppet
514
520
 
515
521
  onlyif => ['test -f /tmp/file1', 'test -f /tmp/file2'],
516
522
 
523
+ or an array of arrays. For example:
524
+
525
+ onlyif => [['test', '-f', '/tmp/file1'], 'test -f /tmp/file2']
526
+
517
527
  This `exec` would only run if every command in the array has an
518
528
  exit code of 0 (success).
519
529
  EOT
@@ -562,12 +572,14 @@ module Puppet
562
572
  reqs << self[:cwd] if self[:cwd]
563
573
 
564
574
  file_regex = Puppet::Util::Platform.windows? ? %r{^([a-zA-Z]:[\\/]\S+)} : %r{^(/\S+)}
575
+ cmd = self[:command]
576
+ cmd = cmd[0] if cmd.is_a? Array
565
577
 
566
- self[:command].scan(file_regex) { |str|
578
+ cmd.scan(file_regex) { |str|
567
579
  reqs << str
568
580
  }
569
581
 
570
- self[:command].scan(/^"([^"]+)"/) { |str|
582
+ cmd.scan(/^"([^"]+)"/) { |str|
571
583
  reqs << str
572
584
  }
573
585
 
@@ -583,6 +595,7 @@ module Puppet
583
595
  # fully qualified. It might not be a bad idea to add
584
596
  # unqualified files, but, well, that's a bit more annoying
585
597
  # to do.
598
+ line = line[0] if line.is_a? Array
586
599
  reqs += line.scan(file_regex)
587
600
  end
588
601
  }
@@ -90,9 +90,15 @@ module Puppet
90
90
  raise Puppet::Error, "The file mode specification is invalid: #{value.inspect}"
91
91
  end
92
92
 
93
+ # normalizes to symbolic form, e.g. u+a, an octal string without leading 0
93
94
  normalize_symbolic_mode(value)
94
95
  end
95
96
 
97
+ unmunge do |value|
98
+ # return symbolic form or octal string *with* leading 0's
99
+ display_mode(value) if value
100
+ end
101
+
96
102
  def desired_mode_from_current(desired, current)
97
103
  current = current.to_i(8) if current.is_a? String
98
104
  is_a_directory = @resource.stat && @resource.stat.directory?
@@ -144,7 +144,7 @@ Puppet::Type.newtype(:tidy) do
144
144
 
145
145
  def tidy?(path, stat)
146
146
  # If the file's older than we allow, we should get rid of it.
147
- (Time.now.to_i - stat.send(resource[:type]).to_i) > value
147
+ (Time.now.to_i - stat.send(resource[:type]).to_i) >= value
148
148
  end
149
149
 
150
150
  munge do |age|