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
@@ -1,11 +1,10 @@
1
1
  # Puppet package provider for Python's `pip` package management frontend.
2
2
  # <http://pip.pypa.io/>
3
3
 
4
- require 'puppet/provider/package'
4
+ require 'puppet/provider/package_targetable'
5
5
  require 'puppet/util/http_proxy'
6
6
 
7
- Puppet::Type.type(:package).provide :pip,
8
- :parent => ::Puppet::Provider::Package do
7
+ Puppet::Type.type(:package).provide :pip, :parent => ::Puppet::Provider::Package::Targetable do
9
8
 
10
9
  desc "Python packages via `pip`.
11
10
 
@@ -13,43 +12,24 @@ Puppet::Type.type(:package).provide :pip,
13
12
  These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
14
13
  or an array where each element is either a string or a hash."
15
14
 
16
- has_feature :installable, :uninstallable, :upgradeable, :versionable, :install_options
15
+ has_feature :installable, :uninstallable, :upgradeable, :versionable, :install_options, :targetable
17
16
 
18
- # Parse lines of output from `pip freeze`, which are structured as
19
- # _package_==_version_.
20
- def self.parse(line)
21
- if line.chomp =~ /^([^=]+)==([^=]+)$/
22
- {:ensure => $2, :name => $1, :provider => name}
23
- else
24
- nil
25
- end
26
- end
17
+ # Override the specificity method to return 1 if pip is not set as default provider
18
+ def self.specificity
19
+ match = default_match
20
+ length = match ? match.length : 0
27
21
 
28
- # Return an array of structured information about every installed package
29
- # that's managed by `pip` or an empty array if `pip` is not available.
30
- def self.instances
31
- packages = []
32
- pip_cmd = self.pip_cmd
33
- return [] unless pip_cmd
34
- command = [pip_cmd, 'freeze']
35
- if Puppet::Util::Package.versioncmp(self.pip_version, '8.1.0') >= 0 # a >= b
36
- command << '--all'
37
- end
38
- execpipe command do |process|
39
- process.collect do |line|
40
- next unless options = parse(line)
41
- packages << new(options)
42
- end
43
- end
22
+ return 1 if length == 0
44
23
 
45
- # Pip can also upgrade pip, but it's not listed in freeze so need to special case it
46
- # Pip list would also show pip installed version, but "pip list" doesn't exist for older versions of pip (E.G v1.0)
47
- # Not needed when "pip freeze --all" is available
48
- if Puppet::Util::Package.versioncmp(self.pip_version, '8.1.0') == -1 && version = self.pip_version
49
- packages << new({:ensure => version, :name => File.basename(pip_cmd), :provider => name})
50
- end
24
+ super
25
+ end
51
26
 
52
- packages
27
+ # Define the default provider package command name when the provider is targetable.
28
+ # Required by Puppet::Provider::Package::Targetable::resource_or_provider_command
29
+
30
+ def self.provider_command
31
+ # Ensure pip can upgrade pip, which usually puts pip into a new path /usr/local/bin/pip (compared to /usr/bin/pip)
32
+ self.cmd.map { |c| which(c) }.find { |c| c != nil }
53
33
  end
54
34
 
55
35
  def self.cmd
@@ -60,104 +40,95 @@ Puppet::Type.type(:package).provide :pip,
60
40
  end
61
41
  end
62
42
 
63
- def self.pip_cmd
64
- self.cmd.map { |c| which(c) }.find { |c| c != nil }
65
- end
66
-
67
- def self.pip_version
68
- pip_cmd = self.pip_cmd
69
- return nil unless pip_cmd
70
-
71
- execpipe [pip_cmd, '--version'] do |process|
43
+ def self.pip_version(command)
44
+ execpipe [command, '--version'] do |process|
72
45
  process.collect do |line|
73
46
  return line.strip.match(/^pip (\d+\.\d+\.?\d*).*$/)[1]
74
47
  end
75
48
  end
76
49
  end
77
50
 
78
- # Return structured information about a particular package or `nil` if
79
- # it is not installed or `pip` itself is not available.
80
- def query
81
- self.class.instances.each do |provider_pip|
82
- return provider_pip.properties if @resource[:name].downcase == provider_pip.name.downcase
51
+ # Return an array of structured information about every installed package
52
+ # that's managed by `pip` or an empty array if `pip` is not available.
53
+
54
+ def self.instances(target_command = nil)
55
+ if target_command
56
+ command = target_command
57
+ self.validate_command(command)
58
+ else
59
+ command = provider_command
83
60
  end
84
- return nil
85
- end
86
61
 
87
- # Use pip CLI to look up versions from PyPI repositories, honoring local pip config such as custom repositories
88
- def latest
89
- return nil unless self.class.pip_cmd
90
- if Puppet::Util::Package.versioncmp(self.class.pip_version, '1.5.4') == -1 # a < b
91
- return latest_with_old_pip
62
+ packages = []
63
+ return packages unless command
64
+
65
+ command_options = ['freeze']
66
+ command_version = self.pip_version(command)
67
+ if Puppet::Util::Package.versioncmp(command_version, '8.1.0') >= 0
68
+ command_options << '--all'
92
69
  end
93
- latest_with_new_pip
94
- end
95
70
 
96
- # Install a package. The ensure parameter may specify installed,
97
- # latest, a version number, or, in conjunction with the source
98
- # parameter, an SCM revision. In that case, the source parameter
99
- # gives the fully-qualified URL to the repository.
100
- def install
101
- args = %w{install -q}
102
- args += install_options if @resource[:install_options]
103
- if @resource[:source]
104
- if String === @resource[:ensure]
105
- args << "#{@resource[:source]}@#{@resource[:ensure]}#egg=#{
106
- @resource[:name]}"
107
- else
108
- args << "#{@resource[:source]}#egg=#{@resource[:name]}"
109
- end
110
- else
111
- case @resource[:ensure]
112
- when String
113
- args << "#{@resource[:name]}==#{@resource[:ensure]}"
114
- when :latest
115
- args << "--upgrade" << @resource[:name]
116
- else
117
- args << @resource[:name]
71
+ execpipe [command, command_options] do |process|
72
+ process.collect do |line|
73
+ next unless pkg = parse(line)
74
+ pkg[:command] = command
75
+ packages << new(pkg)
118
76
  end
119
77
  end
120
- lazy_pip(*args)
121
- end
122
78
 
123
- # Uninstall a package. Uninstall won't work reliably on Debian/Ubuntu
124
- # unless this issue gets fixed.
125
- # <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562544>
126
- def uninstall
127
- lazy_pip "uninstall", "-y", "-q", @resource[:name]
79
+ # Pip can also upgrade pip, but it's not listed in freeze so need to special case it
80
+ # Pip list would also show pip installed version, but "pip list" doesn't exist for older versions of pip (E.G v1.0)
81
+ # Not needed when "pip freeze --all" is available.
82
+ if Puppet::Util::Package.versioncmp(command_version, '8.1.0') == -1
83
+ packages << new({:ensure => command_version, :name => File.basename(command), :provider => name, :command => command})
84
+ end
85
+
86
+ packages
128
87
  end
129
88
 
130
- def update
131
- install
89
+ # Parse lines of output from `pip freeze`, which are structured as:
90
+ # _package_==_version_
91
+
92
+ def self.parse(line)
93
+ if line.chomp =~ /^([^=]+)==([^=]+)$/
94
+ {:ensure => $2, :name => $1, :provider => name}
95
+ end
132
96
  end
133
97
 
134
- # Execute a `pip` command. If Puppet doesn't yet know how to do so,
135
- # try to teach it and if even that fails, raise the error.
136
- private
137
- def lazy_pip(*args)
138
- pip(*args)
139
- rescue NoMethodError => e
140
- # Ensure pip can upgrade pip, which usually puts pip into a new path /usr/local/bin/pip (compared to /usr/bin/pip)
141
- # The path to pip needs to be looked up again in the subsequent request. Using the preferred approach as noted
142
- # in provider.rb ensures this (copied below for reference)
143
- #
144
- # @note From provider.rb; It is preferred if the commands are not entered with absolute paths as this allows puppet
145
- # to search for them using the PATH variable.
146
- if pathname = self.class.cmd.map { |c| which(c) }.find { |c| c != nil }
147
- self.class.commands :pip => File.basename(pathname)
148
- pip(*args)
149
- else
150
- raise e, "Could not locate command #{self.class.cmd.join(' and ')}.", e.backtrace
98
+ # Return structured information about a particular package or `nil`
99
+ # if the package is not installed or `pip` itself is not available.
100
+
101
+ def query
102
+ command = resource_or_provider_command
103
+ self.class.validate_command(command)
104
+
105
+ self.class.instances(command).each do |pkg|
106
+ return pkg.properties if @resource[:name].downcase == pkg.name.downcase
151
107
  end
108
+ return nil
152
109
  end
153
110
 
154
- def install_options
155
- join_options(@resource[:install_options])
111
+ # Use pip CLI to look up versions from PyPI repositories,
112
+ # honoring local pip config such as custom repositories.
113
+
114
+ def latest
115
+ command = resource_or_provider_command
116
+ self.class.validate_command(command)
117
+
118
+ command_version = self.class.pip_version(command)
119
+ if Puppet::Util::Package.versioncmp(command_version, '1.5.4') == -1
120
+ latest_with_old_pip
121
+ else
122
+ latest_with_new_pip
123
+ end
156
124
  end
157
125
 
158
126
  def latest_with_new_pip
127
+ command = resource_or_provider_command
128
+ self.class.validate_command(command)
129
+
159
130
  # Less resource intensive approach for pip version 1.5.4 and above
160
- execpipe ["#{self.class.pip_cmd}", "install", "#{@resource[:name]}==versionplease"] do |process|
131
+ execpipe [command, "install", "#{@resource[:name]}==versionplease"] do |process|
161
132
  process.collect do |line|
162
133
  # PIP OUTPUT: Could not find a version that satisfies the requirement Django==versionplease (from versions: 1.1.3, 1.8rc1)
163
134
  if line =~ /from versions: /
@@ -173,8 +144,11 @@ Puppet::Type.type(:package).provide :pip,
173
144
  end
174
145
 
175
146
  def latest_with_old_pip
147
+ command = resource_or_provider_command
148
+ self.class.validate_command(command)
149
+
176
150
  Dir.mktmpdir("puppet_pip") do |dir|
177
- execpipe ["#{self.class.pip_cmd}", "install", "#{@resource[:name]}", "-d", "#{dir}", "-v"] do |process|
151
+ execpipe [command, "install", "#{@resource[:name]}", "-d", "#{dir}", "-v"] do |process|
178
152
  process.collect do |line|
179
153
  # PIP OUTPUT: Using version 0.10.1 (newest of versions: 0.10.1, 0.10, 0.9, 0.8.1, 0.8, 0.7.2, 0.7.1, 0.7, 0.6.1, 0.6, 0.5.2, 0.5.1, 0.5, 0.4, 0.3.1, 0.3, 0.2, 0.1)
180
154
  if line =~ /Using version (.+?) \(newest of versions/
@@ -185,4 +159,55 @@ Puppet::Type.type(:package).provide :pip,
185
159
  end
186
160
  end
187
161
  end
162
+
163
+ # Install a package. The ensure parameter may specify installed,
164
+ # latest, a version number, or, in conjunction with the source
165
+ # parameter, an SCM revision. In that case, the source parameter
166
+ # gives the fully-qualified URL to the repository.
167
+
168
+ def install
169
+ command = resource_or_provider_command
170
+ self.class.validate_command(command)
171
+
172
+ command_options = %w{install -q}
173
+ command_options += install_options if @resource[:install_options]
174
+ if @resource[:source]
175
+ if String === @resource[:ensure]
176
+ command_options << "#{@resource[:source]}@#{@resource[:ensure]}#egg=#{@resource[:name]}"
177
+ else
178
+ command_options << "#{@resource[:source]}#egg=#{@resource[:name]}"
179
+ end
180
+ else
181
+ case @resource[:ensure]
182
+ when String
183
+ command_options << "#{@resource[:name]}==#{@resource[:ensure]}"
184
+ when :latest
185
+ command_options << "--upgrade" << @resource[:name]
186
+ else
187
+ command_options << @resource[:name]
188
+ end
189
+ end
190
+
191
+ execute([command, command_options])
192
+ end
193
+
194
+ # Uninstall a package. Uninstall won't work reliably on Debian/Ubuntu unless this issue gets fixed.
195
+ # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562544
196
+
197
+ def uninstall
198
+ command = resource_or_provider_command
199
+ self.class.validate_command(command)
200
+
201
+ command_options = ["uninstall", "-y", "-q", @resource[:name]]
202
+
203
+ execute([command, command_options])
204
+ end
205
+
206
+ def update
207
+ install
208
+ end
209
+
210
+ def install_options
211
+ join_options(@resource[:install_options])
212
+ end
188
213
  end
@@ -12,7 +12,7 @@ Puppet::Type.type(:package).provide :pip3,
12
12
  These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
13
13
  or an array where each element is either a string or a hash."
14
14
 
15
- has_feature :installable, :uninstallable, :upgradeable, :versionable, :install_options
15
+ has_feature :installable, :uninstallable, :upgradeable, :versionable, :install_options, :targetable
16
16
 
17
17
  def self.cmd
18
18
  ["pip3"]
@@ -1,4 +1,4 @@
1
- require 'puppet/provider/package'
1
+ require 'puppet/provider/package/gem'
2
2
 
3
3
  Puppet::Type.type(:package).provide :puppet_gem, :parent => :gem do
4
4
  desc "Puppet Ruby Gem support. This provider is useful for managing
@@ -155,28 +155,39 @@ Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Pr
155
155
  end
156
156
 
157
157
  def uninstall
158
- query if get(:arch) == :absent
159
- nvr = "#{get(:name)}-#{get(:version)}-#{get(:release)}"
160
- arch = ".#{get(:arch)}"
161
- # If they specified an arch in the manifest, erase that Otherwise,
162
- # erase the arch we got back from the query. If multiple arches are
163
- # installed and only the package name is specified (without the
164
- # arch), this will uninstall all of them on successive runs of the
165
- # client, one after the other
166
-
167
- # version of RPM prior to 4.2.1 can't accept the architecture as
168
- # part of the package name.
169
- unless Puppet::Util::Package.versioncmp(self.class.current_version, '4.2.1') < 0
170
- if @resource[:name][-arch.size, arch.size] == arch
171
- nvr += arch
158
+ query
159
+ # If version and release (or only version) is specified in the resource,
160
+ # uninstall using them, otherwise uninstall using only the name of the package.
161
+ name = get(:name)
162
+ version = get(:version)
163
+ release = get(:release)
164
+ nav = "#{name}-#{version}"
165
+ nvr = "#{nav}-#{release}"
166
+ if @resource[:name].start_with? nvr
167
+ identifier = nvr
168
+ else
169
+ if @resource[:name].start_with? nav
170
+ identifier = nav
172
171
  else
173
- nvr += ".#{get(:arch)}"
172
+ identifier = name
173
+ end
174
+ end
175
+ # If an arch is specified in the resource, uninstall that arch,
176
+ # otherwise uninstall the arch returned by query.
177
+ # If multiple arches are installed and arch is not specified,
178
+ # this will uninstall all of them after successive runs.
179
+ #
180
+ # rpm prior to 4.2.1 cannot accept architecture as part of the package name.
181
+ unless Puppet::Util::Package.versioncmp(self.class.current_version, '4.2.1') < 0
182
+ arch = ".#{get(:arch)}"
183
+ if @resource[:name].end_with? arch
184
+ identifier += arch
174
185
  end
175
186
  end
176
187
 
177
188
  flag = ['-e']
178
189
  flag += uninstall_options if resource[:uninstall_options]
179
- rpm flag, nvr
190
+ rpm flag, identifier
180
191
  end
181
192
 
182
193
  def update
@@ -107,7 +107,7 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
107
107
  end
108
108
 
109
109
  def self.update_to_hash(pkgname, pkgversion)
110
-
110
+
111
111
  # The pkgname string has two parts: name, and architecture. Architecture
112
112
  # is the portion of the string following the last "." character. All
113
113
  # characters preceding the final dot are the package name. Parse out
@@ -0,0 +1,68 @@
1
+ # Targetable package providers implement a `command` attribute.
2
+ #
3
+ # The `packages` hash passed to `Puppet::Provider::Package::prefetch` is deduplicated,
4
+ # as it is keyed only by name in `Puppet::Transaction::prefetch_if_necessary`.
5
+ #
6
+ # (The `packages` hash passed to ``Puppet::Provider::Package::prefetch`` should be keyed by all namevars,
7
+ # possibly via a `prefetchV2` method that could take a better data structure.)
8
+ #
9
+ # In addition, `Puppet::Provider::Package::properties` calls `query` in the provider.
10
+ require 'puppet/provider/package'
11
+
12
+ # But `query` in the provider depends upon whether a `command` attribute is defined for the resource.
13
+ # This is a Catch-22.
14
+ #
15
+ # Instead ...
16
+ #
17
+ # Inspect any package to access the catalog (every package includes a reference to the catalog).
18
+ # Inspect the catalog to find all of the `command` attributes for all of the packages of this class.
19
+ # Find all of the package instances using each package `command`, including the default provider command.
20
+ # Assign each instance's `provider` by selecting it from the `packages` hash passed to `prefetch`, based upon `name` and `command`.
21
+ #
22
+ # The original `command` parameter in the catalog is not populated by the default (`:default`) for the parameter in type/package.rb.
23
+ # Rather, the result of the `original_parameters` is `nil` when the `command` parameter is undefined in the catalog.
24
+
25
+ class Puppet::Provider::Package::Targetable < Puppet::Provider::Package
26
+ # Prefetch our package list, yo.
27
+ def self.prefetch(packages)
28
+ catalog_packages = packages.first[1]::catalog::resources.select{ |p| p.provider.class == self }
29
+ package_commands = catalog_packages.map { |catalog_package| catalog_package::original_parameters[:command] }.uniq
30
+ package_commands.each do |command|
31
+ instances(command).each do |instance|
32
+ catalog_packages.each do |catalog_package|
33
+ if catalog_package[:name] == instance.name && catalog_package::original_parameters[:command] == command
34
+ catalog_package.provider = instance
35
+ self.debug "Prefetched instance: %{name} via command: %{command}" % { name: instance.name, cmd: (command || :default)}
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ # Returns the resource command or provider command.
43
+
44
+ def resource_or_provider_command
45
+ resource::original_parameters[:command] || self.class.provider_command
46
+ end
47
+
48
+ # Targetable providers use has_command/is_optional to defer validation of provider suitability.
49
+ # Evaluate provider suitability here and now by validating that the command is defined and exists.
50
+ #
51
+ # cmd: the full path to the package command.
52
+
53
+ def self.validate_command(cmd)
54
+ unless cmd
55
+ raise Puppet::Error, _("Provider %{name} package command is not functional on this host") % { name: name }
56
+ end
57
+ unless File.file?(cmd)
58
+ raise Puppet::Error, _("Provider %{name} package command '%{cmd}' does not exist on this host") % { name: name, cmd: cmd }
59
+ end
60
+ end
61
+
62
+ # Return information about the package, its provider, and its (optional) command.
63
+
64
+ def to_s
65
+ cmd = resource[:command] || :default
66
+ "#{@resource}(provider=#{self.class.name})(command=#{cmd})"
67
+ end
68
+ end