puppet 5.5.14 → 5.5.16

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +18 -17
  4. data/ext/solaris/smf/puppet.xml +2 -0
  5. data/lib/hiera/scope.rb +7 -0
  6. data/lib/puppet.rb +1 -1
  7. data/lib/puppet/application/device.rb +22 -10
  8. data/lib/puppet/configurer.rb +23 -38
  9. data/lib/puppet/network/http/connection.rb +2 -0
  10. data/lib/puppet/pops/types/types.rb +5 -3
  11. data/lib/puppet/provider.rb +1 -2
  12. data/lib/puppet/provider/cron/crontab.rb +1 -1
  13. data/lib/puppet/provider/package.rb +2 -0
  14. data/lib/puppet/provider/package/dpkg.rb +15 -2
  15. data/lib/puppet/provider/package/gem.rb +65 -29
  16. data/lib/puppet/provider/package/pip.rb +136 -111
  17. data/lib/puppet/provider/package/pip3.rb +1 -1
  18. data/lib/puppet/provider/package/puppet_gem.rb +1 -1
  19. data/lib/puppet/provider/package/rpm.rb +27 -16
  20. data/lib/puppet/provider/package/yum.rb +1 -1
  21. data/lib/puppet/provider/package_targetable.rb +68 -0
  22. data/lib/puppet/provider/service/upstart.rb +8 -8
  23. data/lib/puppet/provider/user/useradd.rb +16 -13
  24. data/lib/puppet/settings/server_list_setting.rb +9 -0
  25. data/lib/puppet/ssl/validator/default_validator.rb +30 -0
  26. data/lib/puppet/type/package.rb +46 -9
  27. data/lib/puppet/util/pidlock.rb +15 -1
  28. data/lib/puppet/util/windows/process.rb +70 -0
  29. data/lib/puppet/util/windows/registry.rb +7 -1
  30. data/lib/puppet/util/windows/user.rb +14 -4
  31. data/lib/puppet/version.rb +1 -1
  32. data/locales/puppet.pot +81 -78
  33. data/man/man5/puppet.conf.5 +2 -2
  34. data/man/man8/puppet-agent.8 +1 -1
  35. data/man/man8/puppet-apply.8 +1 -1
  36. data/man/man8/puppet-ca.8 +1 -1
  37. data/man/man8/puppet-catalog.8 +1 -1
  38. data/man/man8/puppet-cert.8 +1 -1
  39. data/man/man8/puppet-certificate.8 +1 -1
  40. data/man/man8/puppet-certificate_request.8 +1 -1
  41. data/man/man8/puppet-certificate_revocation_list.8 +1 -1
  42. data/man/man8/puppet-config.8 +1 -1
  43. data/man/man8/puppet-describe.8 +1 -1
  44. data/man/man8/puppet-device.8 +1 -1
  45. data/man/man8/puppet-doc.8 +1 -1
  46. data/man/man8/puppet-epp.8 +1 -1
  47. data/man/man8/puppet-facts.8 +1 -1
  48. data/man/man8/puppet-filebucket.8 +1 -1
  49. data/man/man8/puppet-generate.8 +1 -1
  50. data/man/man8/puppet-help.8 +1 -1
  51. data/man/man8/puppet-key.8 +1 -1
  52. data/man/man8/puppet-lookup.8 +1 -1
  53. data/man/man8/puppet-man.8 +1 -1
  54. data/man/man8/puppet-master.8 +1 -1
  55. data/man/man8/puppet-module.8 +1 -1
  56. data/man/man8/puppet-node.8 +1 -1
  57. data/man/man8/puppet-parser.8 +1 -1
  58. data/man/man8/puppet-plugin.8 +1 -1
  59. data/man/man8/puppet-report.8 +1 -1
  60. data/man/man8/puppet-resource.8 +1 -1
  61. data/man/man8/puppet-script.8 +1 -1
  62. data/man/man8/puppet-status.8 +1 -1
  63. data/man/man8/puppet.8 +2 -2
  64. data/spec/integration/network/http_pool_spec.rb +120 -0
  65. data/spec/integration/type/package_spec.rb +1 -1
  66. data/spec/integration/util/windows/registry_spec.rb +52 -0
  67. data/spec/integration/util/windows/user_spec.rb +19 -0
  68. data/spec/lib/puppet_spec/https.rb +166 -0
  69. data/spec/unit/configurer_spec.rb +49 -13
  70. data/spec/unit/functions/new_spec.rb +15 -0
  71. data/spec/unit/hiera/scope_spec.rb +7 -0
  72. data/spec/unit/network/http/connection_spec.rb +0 -130
  73. data/spec/unit/provider/package/dpkg_spec.rb +18 -1
  74. data/spec/unit/provider/package/gem_spec.rb +101 -48
  75. data/spec/unit/provider/package/pip3_spec.rb +17 -0
  76. data/spec/unit/provider/package/pip_spec.rb +59 -68
  77. data/spec/unit/provider/package/puppet_gem_spec.rb +22 -6
  78. data/spec/unit/provider/package/rpm_spec.rb +116 -27
  79. data/spec/unit/provider/service/upstart_spec.rb +3 -19
  80. data/spec/unit/settings/server_list_setting_spec.rb +21 -0
  81. data/spec/unit/ssl/validator_spec.rb +2 -0
  82. data/spec/unit/util/pidlock_spec.rb +46 -0
  83. metadata +9 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 457e3317b4f1de69b941861e392aec0a5e77875bf250f42ab10d787556e23f85
4
- data.tar.gz: dc3a1f408970a88c764df1774c8061eefd003ff77b9fac788aae78637d4ff5d2
3
+ metadata.gz: 2ba0da3d29969d7c34b2afda4af74d93b7ab1f859061416941e9b87020802e88
4
+ data.tar.gz: 0fbfb06a22c8b18ff0f7ff377dbc55eca9b8d1fc91dc31131f863fb85373907c
5
5
  SHA512:
6
- metadata.gz: 9390b16d6251dc422fba0a818708adc7104380a9368698ce331ed8dfb01a8c3fe0a763810f6cce90eaa92bfefcfd5c6fcbd1e26bd8a38b8fc339c7c3c13c16ca
7
- data.tar.gz: f305210329e690c40c35cf4384da6277dbcced8de413f347e9ce98525358a4d851980e69ebcb35429347e3f02ace0ee2511a892141fec89235762de01a98e5bb
6
+ metadata.gz: 8f7dfc8a1fe72d734f04fcb0434243c192acbf89c017460a090c24b111e8b63bddde10bc3a51c669b78bd18be8a05d85517250e4c73a5016f5a76662518a5f9c
7
+ data.tar.gz: 7f070dfea28cc0c6872fd9b99f5a6c6f77b523e109f11facde42293ac523428c69d050c7feaff7342b6adb59e1430988adb128d4713a566aebe4bcbc046aee81
data/Gemfile CHANGED
@@ -70,6 +70,8 @@ group(:development, :test) do
70
70
  # webmock requires addressable as as of 2.5.0 addressable started
71
71
  # requiring the public_suffix gem which requires Ruby 2
72
72
  gem 'addressable', '< 2.5.0'
73
+ # webmock requires hashdiff which requires ruby 2 as of 0.3.9
74
+ gem 'hashdiff', '0.3.8'
73
75
  gem 'webmock', '~> 1.24'
74
76
  gem 'vcr', '~> 2.9'
75
77
  gem "hiera-eyaml", :require => false
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- puppet (5.5.14)
4
+ puppet (5.5.16)
5
5
  CFPropertyList (~> 2.2)
6
6
  facter (>= 2.4.0, < 4)
7
7
  fast_gettext (~> 1.1.2)
@@ -32,7 +32,7 @@ GEM
32
32
  fast_gettext (~> 1.1.0)
33
33
  gettext (>= 3.0.2)
34
34
  locale
35
- hashdiff (0.3.9)
35
+ hashdiff (0.3.8)
36
36
  hiera (3.5.0)
37
37
  hiera-eyaml (3.0.0)
38
38
  highline (~> 1.6.19)
@@ -43,21 +43,21 @@ GEM
43
43
  json-schema (2.8.1)
44
44
  addressable (>= 2.4)
45
45
  locale (2.1.2)
46
- memory_profiler (0.9.13)
46
+ memory_profiler (0.9.14)
47
47
  metaclass (0.0.4)
48
48
  method_source (0.9.2)
49
- mocha (1.8.0)
49
+ mocha (1.9.0)
50
50
  metaclass (~> 0.0.1)
51
- msgpack (1.2.10)
51
+ msgpack (1.3.0)
52
52
  multi_json (1.13.1)
53
53
  mustache (1.1.0)
54
54
  net-ssh (4.2.0)
55
55
  optimist (3.0.0)
56
- packaging (0.99.30)
56
+ packaging (0.99.36)
57
57
  artifactory (~> 2)
58
58
  rake (~> 12.3)
59
59
  parallel (1.17.0)
60
- parser (2.6.2.1)
60
+ parser (2.6.3.0)
61
61
  ast (~> 2.4.0)
62
62
  pathspec (0.2.1)
63
63
  powerpack (0.1.2)
@@ -65,7 +65,7 @@ GEM
65
65
  coderay (~> 1.1.0)
66
66
  method_source (~> 0.9.0)
67
67
  puppet-lint (2.3.6)
68
- puppet-syntax (2.4.3)
68
+ puppet-syntax (2.5.0)
69
69
  rake
70
70
  puppetlabs_spec_helper (2.14.1)
71
71
  mocha (~> 1.0)
@@ -90,9 +90,9 @@ GEM
90
90
  rspec-mocks (~> 3.8.0)
91
91
  rspec-collection_matchers (1.1.3)
92
92
  rspec-expectations (>= 2.99.0.beta1)
93
- rspec-core (3.8.0)
93
+ rspec-core (3.8.2)
94
94
  rspec-support (~> 3.8.0)
95
- rspec-expectations (3.8.3)
95
+ rspec-expectations (3.8.4)
96
96
  diff-lcs (>= 1.2.0, < 2.0)
97
97
  rspec-support (~> 3.8.0)
98
98
  rspec-its (1.3.0)
@@ -100,12 +100,12 @@ GEM
100
100
  rspec-expectations (>= 3.0.0)
101
101
  rspec-legacy_formatters (1.0.1)
102
102
  rspec (~> 3.0)
103
- rspec-mocks (3.8.0)
103
+ rspec-mocks (3.8.1)
104
104
  diff-lcs (>= 1.2.0, < 2.0)
105
105
  rspec-support (~> 3.8.0)
106
- rspec-puppet (2.7.3)
106
+ rspec-puppet (2.7.5)
107
107
  rspec
108
- rspec-support (3.8.0)
108
+ rspec-support (3.8.2)
109
109
  rubocop (0.49.1)
110
110
  parallel (~> 1.10)
111
111
  parser (>= 2.3.3.1, < 3.0)
@@ -115,17 +115,17 @@ GEM
115
115
  unicode-display_width (~> 1.0, >= 1.0.1)
116
116
  rubocop-i18n (1.2.0)
117
117
  rubocop (~> 0.49.0)
118
- ruby-prof (0.17.0)
119
- ruby-progressbar (1.10.0)
118
+ ruby-prof (0.18.0)
119
+ ruby-progressbar (1.10.1)
120
120
  safe_yaml (1.0.5)
121
121
  text (1.3.1)
122
- unicode-display_width (1.5.0)
122
+ unicode-display_width (1.6.0)
123
123
  vcr (2.9.3)
124
124
  webmock (1.24.6)
125
125
  addressable (>= 2.3.6)
126
126
  crack (>= 0.3.2)
127
127
  hashdiff
128
- yard (0.9.19)
128
+ yard (0.9.20)
129
129
  yarjuf (2.0.0)
130
130
  builder
131
131
  rspec (~> 3)
@@ -136,6 +136,7 @@ PLATFORMS
136
136
  DEPENDENCIES
137
137
  addressable (< 2.5.0)
138
138
  gettext-setup (~> 0.28)
139
+ hashdiff (= 0.3.8)
139
140
  hiera-eyaml
140
141
  json-schema (~> 2.0)
141
142
  memory_profiler
@@ -28,6 +28,8 @@
28
28
 
29
29
  <exec_method type="method" name="stop" exec="/lib/svc/method/puppet stop" timeout_seconds="60"/>
30
30
 
31
+ <exec_method type="method" name="refresh" exec=":kill" timeout_seconds="60"/>
32
+
31
33
  <stability value="Evolving"/>
32
34
 
33
35
  <template>
@@ -1,5 +1,8 @@
1
+ require 'forwardable'
1
2
  class Hiera
2
3
  class Scope
4
+ extend Forwardable
5
+
3
6
  CALLING_CLASS = 'calling_class'.freeze
4
7
  CALLING_CLASS_PATH = 'calling_class_path'.freeze
5
8
  CALLING_MODULE = 'calling_module'.freeze
@@ -79,5 +82,9 @@ class Hiera
79
82
  end
80
83
  end
81
84
  private :find_hostclass
85
+
86
+ # This is needed for type conversion to work
87
+ def_delegators :@real, :call_function
88
+
82
89
  end
83
90
  end
@@ -1,7 +1,7 @@
1
1
  require 'puppet/version'
2
2
 
3
3
  if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new("1.9.3")
4
- raise LoadError, _("Puppet %{version} requires ruby 1.9.3 or greater.") % { version: Puppet.version }
4
+ raise LoadError, "Puppet #{Puppet.version} requires Ruby 1.9.3 or greater, found Ruby #{RUBY_VERSION.dup}."
5
5
  end
6
6
 
7
7
  Puppet::OLDEST_RECOMMENDED_RUBY_VERSION = '2.3.0'
@@ -266,10 +266,29 @@ Licensed under the Apache 2.0 License
266
266
  Puppet[:vardir] = ::File.join(Puppet[:devicedir], device.name)
267
267
  Puppet[:certname] = device.name
268
268
 
269
- unless options[:resource] || options[:facts] || options[:apply] || options[:libdir]
270
- Puppet::Configurer::PluginHandler.new.download_plugins(env)
269
+ unless options[:resource] || options[:facts] || options[:apply]
270
+ # this will reload and recompute default settings and create the devices sub vardir
271
+ Puppet.settings.use :main, :agent, :ssl
272
+
273
+ # Since it's too complicated to fix properly in the default settings, we workaround for PUP-9642 here.
274
+ # See https://github.com/puppetlabs/puppet/pull/7483#issuecomment-483455997 for details.
275
+ # This has to happen after `settings.use` above, so the directory is created and before `setup_host` below, where the SSL
276
+ # routines would fail with access errors
277
+ if Puppet.features.root? && !Puppet::Util::Platform.windows?
278
+ user = Puppet::Type.type(:user).new(name: Puppet[:user]).exists? ? Puppet[:user] : nil
279
+ group = Puppet::Type.type(:group).new(name: Puppet[:group]).exists? ? Puppet[:group] : nil
280
+ Puppet.debug("Fixing perms for #{user}:#{group} on #{Puppet[:confdir]}")
281
+ FileUtils.chown(user, group, Puppet[:confdir]) if user || group
282
+ end
283
+
284
+ # ask for a ssl cert if needed, and setup the ssl system for this device.
285
+ setup_host
286
+
287
+ # only pluginsync if we do not have a libdir specified on the command line
288
+ Puppet::Configurer::PluginHandler.new.download_plugins(env) unless options[:libdir]
271
289
  end
272
- # this init the device singleton, so that the facts terminus
290
+
291
+ # this inits the device singleton, so that the facts terminus
273
292
  # and the various network_device provider can use it
274
293
  Puppet::Util::NetworkDevice.init(device)
275
294
 
@@ -316,13 +335,6 @@ Licensed under the Apache 2.0 License
316
335
  end
317
336
  else
318
337
  Puppet.info _("starting applying configuration to %{target} at %{scheme}%{url_host}%{port}%{url_path}") % { target: device.name, scheme: scheme, url_host: device_url.host, port: port, url_path: device_url.path }
319
- # this will reload and recompute default settings and create the devices sub vardir
320
- Puppet.settings.use :main, :agent, :ssl
321
- # ask for a ssl cert if needed, but at least
322
- # setup the ssl system for this device.
323
- setup_host
324
-
325
- require 'puppet/configurer'
326
338
  configurer = Puppet::Configurer.new
327
339
  configurer.run(:network_device => true, :pluginsync => Puppet::Configurer.should_pluginsync? && !options[:libdir])
328
340
  end
@@ -212,24 +212,23 @@ class Puppet::Configurer
212
212
 
213
213
  # Skip failover logic if the server_list setting is empty
214
214
  if Puppet.settings[:server_list].nil? || Puppet.settings[:server_list].empty?
215
- do_failover = false;
215
+ do_failover = false
216
216
  else
217
217
  do_failover = true
218
218
  end
219
219
  # When we are passed a catalog, that means we're in apply
220
220
  # mode. We shouldn't try to do any failover in that case.
221
221
  if options[:catalog].nil? && do_failover
222
- found = find_functional_server()
223
- server = found[:server]
222
+ server, port = find_functional_server
224
223
  if server.nil?
225
- raise Puppet::Error, _("Could not select a functional puppet master from server_list: '%{server_list}'") % { server_list: Puppet[:server_list] }
224
+ raise Puppet::Error, _("Could not select a functional puppet master from server_list: '%{server_list}'") % { server_list: Puppet.settings.value(:server_list, Puppet[:environment].to_sym, true) }
226
225
  else
227
226
  #TRANSLATORS 'server_list' is the name of a setting and should not be translated
228
- Puppet.debug _("Selected server from the `server_list` setting: %{server}:%{port}") % {server: server[0], port: server[1]}
229
- report.master_used = "#{server[0]}:#{server[1]}"
227
+ Puppet.debug _("Selected puppet server from the `server_list` setting: %{server}:%{port}") % { server: server, port: port }
228
+ report.master_used = "#{server}:#{port}"
230
229
  end
231
- Puppet.override(:server => server[0], :serverport => server[1]) do
232
- completed = run_internal(options.merge(:node => found[:node]))
230
+ Puppet.override(server: server, serverport: port) do
231
+ completed = run_internal(options)
233
232
  end
234
233
  else
235
234
  completed = run_internal(options)
@@ -283,7 +282,7 @@ class Puppet::Configurer
283
282
  begin
284
283
  node = nil
285
284
  node_retr_time = thinmark do
286
- node = options[:node] || Puppet::Node.indirection.find(Puppet[:node_name_value],
285
+ node = Puppet::Node.indirection.find(Puppet[:node_name_value],
287
286
  :environment => Puppet::Node::Environment.remote(@environment),
288
287
  :configured_environment => configured_environment,
289
288
  :ignore_cache => true,
@@ -382,37 +381,23 @@ class Puppet::Configurer
382
381
  end
383
382
  private :run_internal
384
383
 
385
- def find_functional_server()
386
- configured_environment = Puppet[:environment] if Puppet.settings.set_by_config?(:environment)
387
-
388
- node = nil
389
- selected_server = Puppet.settings[:server_list].find do |server|
390
- # Puppet.override doesn't return the result of its block, so we
391
- # need to handle this manually
392
- found = false
393
- server[1] ||= Puppet[:masterport]
394
- Puppet.override(:server => server[0], :serverport => server[1]) do
395
- begin
396
- node = Puppet::Node.indirection.find(Puppet[:node_name_value],
397
- :environment => Puppet::Node::Environment.remote(@environment),
398
- :configured_environment => configured_environment,
399
- :ignore_cache => true,
400
- :transaction_uuid => @transaction_uuid,
401
- :fail_on_404 => false)
402
- found = true
403
- rescue => detail
404
- #TRANSLATORS 'server_list' is the name of a setting and should not be translated
405
- Puppet.debug _("Unable to connect to server from server_list setting: %{detail}") % {detail: detail}
406
- end
384
+ def find_functional_server
385
+ Puppet.settings[:server_list].each do |server|
386
+ host = server[0]
387
+ port = server[1] || Puppet[:masterport]
388
+ begin
389
+ http = Puppet::Network::HttpPool.http_ssl_instance(host, port)
390
+ response = http.get('/status/v1/simple/master')
391
+ return [host, port] if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPForbidden)
392
+
393
+ Puppet.debug(_("Puppet server %{host}:%{port} is unavailable: %{code} %{reason}") %
394
+ { host: host, port: port, code: response.code, reason: response.message })
395
+ rescue => detail
396
+ #TRANSLATORS 'server_list' is the name of a setting and should not be translated
397
+ Puppet.debug _("Unable to connect to server from server_list setting: %{detail}") % {detail: detail}
407
398
  end
408
- found
409
- end
410
- unless selected_server.nil?
411
- #TRANSLATORS 'server_list' is the name of a setting and should not be translated
412
- Puppet.debug _("Selected functional server from the `server_list` setting: %{server}") % {server: selected_server}
413
399
  end
414
- { :node => node,
415
- :server => selected_server }
400
+ [nil, nil]
416
401
  end
417
402
  private :find_functional_server
418
403
 
@@ -333,6 +333,8 @@ module Puppet::Network::HTTP
333
333
  end
334
334
  response
335
335
  rescue OpenSSL::SSL::SSLError => error
336
+ raise @verify.last_error if @verify.last_error
337
+
336
338
  # can be nil
337
339
  peer_cert = @verify.peer_certs.last
338
340
 
@@ -843,14 +843,16 @@ INTEGER_HEX = '(?:0[xX][0-9A-Fa-f]+)'
843
843
  INTEGER_OCT = '(?:0[0-7]+)'
844
844
  INTEGER_BIN = '(?:0[bB][01]+)'
845
845
  INTEGER_DEC = '(?:0|[1-9]\d*)'
846
+ INTEGER_DEC_OR_OCT = '(?:\d+)'
846
847
  SIGN_PREFIX = '[+-]?\s*'
847
848
 
848
849
  OPTIONAL_FRACTION = '(?:\.\d+)?'
849
850
  OPTIONAL_EXPONENT = '(?:[eE]-?\d+)?'
850
851
  FLOAT_DEC = '(?:' + INTEGER_DEC + OPTIONAL_FRACTION + OPTIONAL_EXPONENT + ')'
851
852
 
852
- INTEGER_PATTERN = '\A' + SIGN_PREFIX + '(?:' + INTEGER_DEC + '|' + INTEGER_HEX + '|' + INTEGER_OCT + '|' + INTEGER_BIN + ')\z'
853
- FLOAT_PATTERN = '\A' + SIGN_PREFIX + '(?:' + FLOAT_DEC + '|' + INTEGER_HEX + '|' + INTEGER_OCT + '|' + INTEGER_BIN + ')\z'
853
+ INTEGER_PATTERN = '\A' + SIGN_PREFIX + '(?:' + INTEGER_DEC + '|' + INTEGER_HEX + '|' + INTEGER_OCT + '|' + INTEGER_BIN + ')\z'
854
+ INTEGER_PATTERN_LENIENT = '\A' + SIGN_PREFIX + '(?:' + INTEGER_DEC_OR_OCT + '|' + INTEGER_HEX + '|' + INTEGER_BIN + ')\z'
855
+ FLOAT_PATTERN = '\A' + SIGN_PREFIX + '(?:' + FLOAT_DEC + '|' + INTEGER_HEX + '|' + INTEGER_OCT + '|' + INTEGER_BIN + ')\z'
854
856
 
855
857
  # @api public
856
858
  #
@@ -1089,7 +1091,7 @@ class PIntegerType < PNumericType
1089
1091
  @@new_function ||= Puppet::Functions.create_loaded_function(:new, loader) do
1090
1092
  local_types do
1091
1093
  type 'Radix = Variant[Default, Integer[2,2], Integer[8,8], Integer[10,10], Integer[16,16]]'
1092
- type "Convertible = Variant[Numeric, Boolean, Pattern[/#{INTEGER_PATTERN}/], Timespan, Timestamp]"
1094
+ type "Convertible = Variant[Numeric, Boolean, Pattern[/#{INTEGER_PATTERN_LENIENT}/], Timespan, Timestamp]"
1093
1095
  type 'NamedArgs = Struct[{from => Convertible, Optional[radix] => Radix, Optional[abs] => Boolean}]'
1094
1096
  end
1095
1097
 
@@ -384,7 +384,7 @@ class Puppet::Provider
384
384
  # @raise [Puppet::DevError] Error indicating that the method should have been implemented by subclass.
385
385
  # @see prefetch
386
386
  def self.instances
387
- raise Puppet::DevError, _("Provider %{provider} has not defined the 'instances' class method") % { provider: self.name }
387
+ raise Puppet::DevError, _("To support listing resources of this type the '%{provider}' provider needs to implement an 'instances' class method returning the current set of resources. We recommend porting your module to the simpler Resource API instead: https://puppet.com/search/docs?keys=resource+api") % { provider: self.name }
388
388
  end
389
389
 
390
390
  # Creates getter- and setter- methods for each property supported by the resource type.
@@ -610,4 +610,3 @@ class Puppet::Provider
610
610
  # @return [void]
611
611
  # @api public
612
612
  end
613
-
@@ -258,7 +258,7 @@ Puppet::Type.type(:cron).provide(:crontab, :parent => Puppet::Provider::ParsedFi
258
258
  end
259
259
 
260
260
  CRONTAB_DIR = case Facter.value("osfamily")
261
- when "Debian", "HP-UX"
261
+ when "Debian", "HP-UX", "Solaris"
262
262
  "/var/spool/cron/crontabs"
263
263
  when /BSD/
264
264
  "/var/cron/tabs"
@@ -1,3 +1,5 @@
1
+ require 'puppet/provider'
2
+
1
3
  class Puppet::Provider::Package < Puppet::Provider
2
4
  # Prefetch our package list, yo.
3
5
  def self.prefetch(packages)
@@ -81,7 +81,6 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package
81
81
  unless file = @resource[:source]
82
82
  raise ArgumentError, _("You cannot install dpkg packages without a source")
83
83
  end
84
-
85
84
  args = []
86
85
 
87
86
  # We always unhold when installing to remove any prior hold.
@@ -146,7 +145,9 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package
146
145
  end
147
146
 
148
147
  def hold
149
- self.install
148
+ if package_not_installed?(@resource[:name])
149
+ self.install
150
+ end
150
151
  Tempfile.open('puppet_dpkg_set_selection') do |tmpfile|
151
152
  tmpfile.write("#{@resource[:name]} hold\n")
152
153
  tmpfile.flush
@@ -162,4 +163,16 @@ Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package
162
163
  end
163
164
  end
164
165
 
166
+ def package_not_installed?(name)
167
+ if !name.nil? && !name.empty?
168
+ begin
169
+ dpkgquery("-W", "--showformat", self.class::DPKG_QUERY_FORMAT_STRING, name)
170
+ rescue Puppet::ExecutionFailure
171
+ # return true if exception is generated because package is not found
172
+ return true
173
+ end
174
+ return false
175
+ end
176
+ raise ArgumentError.new("Package name is nil or empty")
177
+ end
165
178
  end
@@ -1,8 +1,8 @@
1
- require 'puppet/provider/package'
1
+ require 'puppet/provider/package_targetable'
2
2
  require 'uri'
3
3
 
4
4
  # Ruby gems support.
5
- Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package do
5
+ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package::Targetable do
6
6
  desc "Ruby Gem support. If a URL is passed via `source`, then that URL is
7
7
  appended to the list of remote gem repositories; to ensure that only the
8
8
  specified source is used, also pass `--clear-sources` via `install_options`.
@@ -15,9 +15,31 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
15
15
  These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
16
16
  or an array where each element is either a string or a hash."
17
17
 
18
- has_feature :versionable, :install_options, :uninstall_options
18
+ has_feature :versionable, :install_options, :uninstall_options, :targetable
19
19
 
20
- commands :gemcmd => "gem"
20
+ # Override the specificity method to return 1 if gem is not set as default provider
21
+ def self.specificity
22
+ match = default_match
23
+ length = match ? match.length : 0
24
+
25
+ return 1 if length == 0
26
+
27
+ super
28
+ end
29
+
30
+ # Define the default provider package command name when the provider is targetable.
31
+ # Required by Puppet::Provider::Package::Targetable::resource_or_provider_command
32
+
33
+ def self.provider_command
34
+ command(:gemcmd)
35
+ end
36
+
37
+ # Define the default provider package command as optional when the provider is targetable.
38
+ # Doing do defers the evaluation of provider suitability until all commands are evaluated.
39
+
40
+ has_command(:gemcmd, 'gem') do
41
+ is_optional
42
+ end
21
43
 
22
44
  # CommandDefiner in provider.rb creates convenience execution methods that set failonfail, combine, and optionally, environment.
23
45
  # And when a child provider defines its own command via commands() or has_command(), the provider-specific path is always returned by command().
@@ -26,12 +48,29 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
26
48
  #
27
49
  # In this case, causing the puppet_gem provider to inherit the parent gem provider's convenience gemcmd() methods, with the wrong path.
28
50
 
29
- def self.execute_gem_command(command_options)
30
- cmd = [command(:gemcmd)] << command_options
51
+ def self.execute_gem_command(command, command_options)
52
+ validate_command(command)
53
+ cmd = [command] << command_options
31
54
 
32
55
  execute(cmd, {:failonfail => true, :combine => true, :custom_environment => {"HOME"=>ENV["HOME"]}})
33
56
  end
34
57
 
58
+ def self.instances(target_command = nil)
59
+ if target_command
60
+ command = target_command
61
+ else
62
+ command = provider_command
63
+ # The default provider package command is optional.
64
+ return [] unless command
65
+ end
66
+
67
+ gemlist(:command => command, :local => true).collect do |pkg|
68
+ # Track the command when the provider is targetable.
69
+ pkg[:command] = command
70
+ new(pkg)
71
+ end
72
+ end
73
+
35
74
  def self.gemlist(options)
36
75
  command_options = ["list"]
37
76
 
@@ -48,7 +87,7 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
48
87
  end
49
88
 
50
89
  begin
51
- list = execute_gem_command(command_options).lines.
90
+ list = execute_gem_command(options[:command], command_options).lines.
52
91
  map {|set| gemsplit(set) }.
53
92
  reject {|x| x.nil? }
54
93
  rescue Puppet::ExecutionFailure => detail
@@ -83,12 +122,6 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
83
122
  end
84
123
  end
85
124
 
86
- def self.instances(justme = false)
87
- gemlist(:local => true).collect do |hash|
88
- new(hash)
89
- end
90
- end
91
-
92
125
  def insync?(is)
93
126
  return false unless is && is != :absent
94
127
 
@@ -105,13 +138,13 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
105
138
  is.any? { |version| dependency.match?('', version) }
106
139
  end
107
140
 
108
- def rubygem_version
141
+ def rubygem_version(command)
109
142
  command_options = ["--version"]
110
-
111
- self.class.execute_gem_command(command_options)
143
+ self.class.execute_gem_command(command, command_options)
112
144
  end
113
145
 
114
146
  def install(useversion = true)
147
+ command = resource_or_provider_command
115
148
  command_options = ["install"]
116
149
  command_options += install_options if resource[:install_options]
117
150
 
@@ -122,7 +155,7 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
122
155
  command_options << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
123
156
  end
124
157
 
125
- if Puppet::Util::Package.versioncmp(rubygem_version, '2.0.0') == -1
158
+ if Puppet::Util::Package.versioncmp(rubygem_version(command), '2.0.0') == -1
126
159
  command_options << "--no-rdoc" << "--no-ri"
127
160
  else
128
161
  command_options << "--no-document"
@@ -157,31 +190,34 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
157
190
  command_options << resource[:name]
158
191
  end
159
192
 
160
- output = self.class.execute_gem_command(command_options)
161
- # Apparently some gem versions don't exit non-0 on failure
193
+ output = self.class.execute_gem_command(command, command_options)
194
+ # Apparently some gem versions don't exit non-0 on failure.
162
195
  self.fail _("Could not install: %{output}") % { output: output.chomp } if output.include?("ERROR")
163
196
  end
164
197
 
165
198
  def latest
166
- # This always gets the latest version available.
167
- options = {:justme => resource[:name]}
168
- options.merge!({:source => resource[:source]}) unless resource[:source].nil?
169
- hash = self.class.gemlist(options)
170
-
171
- hash[:ensure][0]
199
+ command = resource_or_provider_command
200
+ options = { :command => command, :justme => resource[:name] }
201
+ options[:source] = resource[:source] unless resource[:source].nil?
202
+ pkg = self.class.gemlist(options)
203
+ pkg[:ensure][0]
172
204
  end
173
205
 
174
206
  def query
175
- self.class.gemlist(:justme => resource[:name], :local => true)
207
+ command = resource_or_provider_command
208
+ options = { :command => command, :justme => resource[:name], :local => true }
209
+ pkg = self.class.gemlist(options)
210
+ pkg[:command] = command unless pkg.nil?
211
+ pkg
176
212
  end
177
213
 
178
214
  def uninstall
215
+ command = resource_or_provider_command
179
216
  command_options = ["uninstall"]
180
217
  command_options << "--executables" << "--all" << resource[:name]
181
218
  command_options += uninstall_options if resource[:uninstall_options]
182
-
183
- output = self.class.execute_gem_command(command_options)
184
- # Apparently some gem versions don't exit non-0 on failure
219
+ output = self.class.execute_gem_command(command, command_options)
220
+ # Apparently some gem versions don't exit non-0 on failure.
185
221
  self.fail _("Could not uninstall: %{output}") % { output: output.chomp } if output.include?("ERROR")
186
222
  end
187
223