puppet 4.1.0 → 4.2.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 (117) hide show
  1. data/ext/osx/puppet.plist +32 -0
  2. data/ext/redhat/client.init +3 -6
  3. data/ext/redhat/client.sysconfig +1 -10
  4. data/ext/suse/client.init +3 -6
  5. data/ext/systemd/puppet.service +2 -1
  6. data/lib/puppet.rb +1 -1
  7. data/lib/puppet/agent.rb +4 -19
  8. data/lib/puppet/application/apply.rb +22 -6
  9. data/lib/puppet/configurer.rb +3 -2
  10. data/lib/puppet/configurer/plugin_handler.rb +6 -2
  11. data/lib/puppet/face/plugin.rb +7 -14
  12. data/lib/puppet/forge/repository.rb +1 -2
  13. data/lib/puppet/indirector/catalog/compiler.rb +4 -3
  14. data/lib/puppet/indirector/facts/facter.rb +8 -0
  15. data/lib/puppet/module.rb +17 -12
  16. data/lib/puppet/network/http/factory.rb +8 -4
  17. data/lib/puppet/node/environment.rb +11 -7
  18. data/lib/puppet/parser/ast/pops_bridge.rb +5 -0
  19. data/lib/puppet/parser/functions/fqdn_rand.rb +2 -2
  20. data/lib/puppet/parser/scope.rb +39 -13
  21. data/lib/puppet/pops.rb +1 -0
  22. data/lib/puppet/pops/evaluator/runtime3_converter.rb +1 -1
  23. data/lib/puppet/pops/evaluator/runtime3_support.rb +31 -0
  24. data/lib/puppet/pops/parser/epp_support.rb +4 -2
  25. data/lib/puppet/property/ensure.rb +1 -1
  26. data/lib/puppet/provider.rb +5 -0
  27. data/lib/puppet/provider/augeas/augeas.rb +5 -0
  28. data/lib/puppet/provider/group/pw.rb +1 -0
  29. data/lib/puppet/provider/group/windows_adsi.rb +9 -0
  30. data/lib/puppet/provider/mount/parsed.rb +15 -1
  31. data/lib/puppet/provider/package.rb +6 -2
  32. data/lib/puppet/provider/package/gem.rb +16 -0
  33. data/lib/puppet/provider/package/openbsd.rb +7 -7
  34. data/lib/puppet/provider/package/pacman.rb +9 -8
  35. data/lib/puppet/provider/package/pip.rb +1 -1
  36. data/lib/puppet/provider/package/pip3.rb +18 -0
  37. data/lib/puppet/provider/package/pkgdmg.rb +4 -2
  38. data/lib/puppet/provider/package/pkgin.rb +3 -3
  39. data/lib/puppet/provider/package/rpm.rb +8 -14
  40. data/lib/puppet/provider/package/yum.rb +5 -4
  41. data/lib/puppet/provider/service/base.rb +3 -2
  42. data/lib/puppet/provider/service/bsd.rb +7 -7
  43. data/lib/puppet/provider/service/debian.rb +2 -1
  44. data/lib/puppet/provider/service/freebsd.rb +1 -1
  45. data/lib/puppet/provider/service/systemd.rb +75 -6
  46. data/lib/puppet/provider/service/upstart.rb +1 -1
  47. data/lib/puppet/provider/user/pw.rb +1 -0
  48. data/lib/puppet/resource/catalog.rb +1 -1
  49. data/lib/puppet/resource/status.rb +9 -0
  50. data/lib/puppet/resource/type.rb +4 -2
  51. data/lib/puppet/settings.rb +43 -16
  52. data/lib/puppet/transaction.rb +27 -13
  53. data/lib/puppet/type/augeas.rb +1 -0
  54. data/lib/puppet/type/exec.rb +11 -2
  55. data/lib/puppet/type/group.rb +9 -1
  56. data/lib/puppet/type/mount.rb +2 -0
  57. data/lib/puppet/type/package.rb +13 -2
  58. data/lib/puppet/type/service.rb +9 -0
  59. data/lib/puppet/util.rb +8 -3
  60. data/lib/puppet/util/execution.rb +2 -2
  61. data/lib/puppet/util/http_proxy.rb +60 -0
  62. data/lib/puppet/util/log.rb +1 -1
  63. data/lib/puppet/util/splayer.rb +18 -0
  64. data/lib/puppet/version.rb +1 -1
  65. data/spec/fixtures/unit/provider/package/yum/yum-check-update-obsoletes.txt +195 -0
  66. data/spec/integration/application/apply_spec.rb +72 -30
  67. data/spec/integration/indirector/facts/facter_spec.rb +38 -0
  68. data/spec/integration/parser/scope_spec.rb +20 -2
  69. data/spec/integration/provider/mount_spec.rb +23 -36
  70. data/spec/integration/transaction_spec.rb +40 -1
  71. data/spec/integration/type/file_spec.rb +36 -0
  72. data/spec/integration/type/package_spec.rb +65 -0
  73. data/spec/lib/matchers/include_in_order.rb +0 -1
  74. data/spec/lib/puppet_spec/files.rb +14 -0
  75. data/spec/unit/agent_spec.rb +0 -38
  76. data/spec/unit/application/apply_spec.rb +13 -0
  77. data/spec/unit/configurer/plugin_handler_spec.rb +42 -13
  78. data/spec/unit/configurer_spec.rb +5 -0
  79. data/spec/unit/face/plugin_spec.rb +33 -4
  80. data/spec/unit/file_serving/configuration/parser_spec.rb +25 -30
  81. data/spec/unit/indirector/catalog/compiler_spec.rb +16 -0
  82. data/spec/unit/indirector/facts/facter_spec.rb +2 -1
  83. data/spec/unit/module_spec.rb +0 -23
  84. data/spec/unit/network/http/factory_spec.rb +14 -0
  85. data/spec/unit/parser/functions/fqdn_rand_spec.rb +6 -2
  86. data/spec/unit/parser/functions/generate_spec.rb +3 -12
  87. data/spec/unit/parser/scope_spec.rb +9 -0
  88. data/spec/unit/pops/evaluator/runtime3_converter_spec.rb +19 -0
  89. data/spec/unit/pops/evaluator/variables_spec.rb +1 -1
  90. data/spec/unit/pops/parser/lexer2_spec.rb +35 -3
  91. data/spec/unit/provider/augeas/augeas_spec.rb +9 -0
  92. data/spec/unit/provider/group/windows_adsi_spec.rb +5 -0
  93. data/spec/unit/provider/package/aptrpm_spec.rb +2 -2
  94. data/spec/unit/provider/package/base_spec.rb +18 -0
  95. data/spec/unit/provider/package/gem_spec.rb +70 -0
  96. data/spec/unit/provider/package/pacman_spec.rb +55 -0
  97. data/spec/unit/provider/package/pip3_spec.rb +257 -0
  98. data/spec/unit/provider/package/pip_spec.rb +1 -1
  99. data/spec/unit/provider/package/pkgdmg_spec.rb +18 -0
  100. data/spec/unit/provider/package/pkgin_spec.rb +23 -13
  101. data/spec/unit/provider/package/yum_spec.rb +11 -0
  102. data/spec/unit/provider/service/bsd_spec.rb +130 -0
  103. data/spec/unit/provider/service/debian_spec.rb +12 -1
  104. data/spec/unit/provider/service/freebsd_spec.rb +16 -0
  105. data/spec/unit/provider/service/systemd_spec.rb +84 -7
  106. data/spec/unit/provider/service/upstart_spec.rb +1 -0
  107. data/spec/unit/provider/zone/solaris_spec.rb +45 -12
  108. data/spec/unit/puppet_spec.rb +1 -1
  109. data/spec/unit/resource/catalog_spec.rb +5 -0
  110. data/spec/unit/type/mount_spec.rb +8 -0
  111. data/spec/unit/type/service_spec.rb +5 -0
  112. data/spec/unit/util/http_proxy_spec.rb +87 -0
  113. data/spec/unit/util/log_spec.rb +12 -1
  114. data/spec/unit/util/splayer_spec.rb +45 -0
  115. metadata +3057 -3035
  116. checksums.yaml +0 -7
  117. data/ext/systemd/puppetmaster.service +0 -11
@@ -23,6 +23,11 @@ class Puppet::Parser::AST::PopsBridge
23
23
  Puppet::Pops::Model::ModelTreeDumper.new.dump(@value)
24
24
  end
25
25
 
26
+ def source_text
27
+ source_adapter = Puppet::Pops::Utils.find_closest_positioned(@value)
28
+ source_adapter ? source_adapter.extract_text() : nil
29
+ end
30
+
26
31
  def evaluate(scope)
27
32
  object = @@evaluator.evaluate(scope, @value)
28
33
  @@evaluator.convert_to_3x(object, scope)
@@ -4,7 +4,7 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :arity => -2, :type => :rvalu
4
4
  "Usage: `fqdn_rand(MAX, [SEED])`. MAX is required and must be a positive
5
5
  integer; SEED is optional and may be any number or string.
6
6
 
7
- Generates a random whole number greater than or equal to 0 and less than MAX,
7
+ Generates a random Integer number greater than or equal to 0 and less than MAX,
8
8
  combining the `$fqdn` fact and the value of SEED for repeatable randomness.
9
9
  (That is, each node will get a different random number from this function, but
10
10
  a given node's result will be the same every time unless its hostname changes.)
@@ -17,5 +17,5 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :arity => -2, :type => :rvalu
17
17
  `fqdn_rand(30, 'expensive job 2')` will produce totally different numbers.)") do |args|
18
18
  max = args.shift.to_i
19
19
  seed = Digest::MD5.hexdigest([self['::fqdn'],args].join(':')).hex
20
- Puppet::Util.deterministic_rand(seed,max)
20
+ Puppet::Util.deterministic_rand_int(seed,max)
21
21
  end
@@ -484,24 +484,36 @@ class Puppet::Parser::Scope
484
484
  def lookup_qualified_variable(class_name, variable_name, position)
485
485
  begin
486
486
  if lookup_as_local_name?(class_name, variable_name)
487
- self[variable_name]
487
+ if is_topscope?
488
+ # This is the case where $::x is looked up from within the topscope itself, or from a local scope
489
+ # parented at the top scope. In this case, the lookup must ignore local and ephemeral scopes.
490
+ #
491
+ handle_not_found(class_name, variable_name, position) unless @symtable.include?(variable_name)
492
+ @symtable[variable_name]
493
+ else
494
+ self[variable_name]
495
+ end
488
496
  else
489
497
  qualified_scope(class_name).lookupvar(variable_name, position)
490
498
  end
491
499
  rescue RuntimeError => e
492
- unless Puppet[:strict_variables]
493
- # Do not issue warning if strict variables are on, as an error will be raised by variable_not_found
494
- location = if position[:lineproc]
495
- " at #{position[:lineproc].call}"
496
- elsif position[:file] && position[:line]
497
- " at #{position[:file]}:#{position[:line]}"
498
- else
499
- ""
500
- end
501
- warning "Could not look up qualified variable '#{class_name}::#{variable_name}'; #{e.message}#{location}"
502
- end
503
- variable_not_found("#{class_name}::#{variable_name}", e.message)
500
+ handle_not_found(class_name, variable_name, position, e.message)
501
+ end
502
+ end
503
+
504
+ def handle_not_found(class_name, variable_name, position, reason = nil)
505
+ unless Puppet[:strict_variables]
506
+ # Do not issue warning if strict variables are on, as an error will be raised by variable_not_found
507
+ location = if position[:lineproc]
508
+ " at #{position[:lineproc].call}"
509
+ elsif position[:file] && position[:line]
510
+ " at #{position[:file]}:#{position[:line]}"
511
+ else
512
+ ""
513
+ end
514
+ warning "Could not look up qualified variable '#{class_name}::#{variable_name}'; #{reason}#{location}"
504
515
  end
516
+ variable_not_found("#{class_name}::#{variable_name}", reason)
505
517
  end
506
518
 
507
519
  # Handles the special case of looking up fully qualified variable in not yet evaluated top scope
@@ -724,6 +736,8 @@ class Puppet::Parser::Scope
724
736
  "Scope(#{@resource})"
725
737
  end
726
738
 
739
+ alias_method :inspect, :to_s
740
+
727
741
  # remove ephemeral scope up to level
728
742
  # TODO: Who uses :all ? Remove ??
729
743
  #
@@ -860,6 +874,18 @@ class Puppet::Parser::Scope
860
874
  end
861
875
  end
862
876
 
877
+ # Calls a 3.x or 4.x function by name with arguments given in an array using the 4.x calling convention
878
+ # and returns the result.
879
+ # Note that it is the caller's responsibility to rescue the given ArgumentError and provide location information
880
+ # to aid the user find the problem. The problem is otherwise reported against the source location that
881
+ # invoked the function that ultimately called this method.
882
+ #
883
+ # @return [Object] the result of the called function
884
+ # @raise ArgumentError if the function does not exist
885
+ def call_function(func_name, args, &block)
886
+ Puppet::Pops::Parser::EvaluatingParser.new.evaluator.external_call_function(func_name, args, self, &block)
887
+ end
888
+
863
889
  private
864
890
 
865
891
  def assert_class_and_title(type_name, title)
@@ -131,5 +131,6 @@ module Puppet
131
131
  require 'puppet/parser/ast/pops_bridge'
132
132
  require 'puppet/bindings'
133
133
  require 'puppet/functions'
134
+ require 'puppet/loaders'
134
135
  end
135
136
  require 'puppet/plugins/data_providers'
@@ -140,7 +140,7 @@ class Runtime3Converter
140
140
  when Puppet::Pops::Types::PResourceType
141
141
  type_name = split_type.type_name
142
142
  title = split_type.title
143
- if type_name =~ /^(::)?[Cc]lass/
143
+ if type_name =~ /^(::)?[Cc]lass$/
144
144
  ['class', title.nil? ? nil : title.sub(/^::/, '')]
145
145
  else
146
146
  # Ensure that title is '' if nil
@@ -231,6 +231,37 @@ module Puppet::Pops::Evaluator::Runtime3Support
231
231
  n
232
232
  end
233
233
 
234
+ # Provides the ability to call a 3.x or 4.x function from the perspective of a 3.x function or ERB template.
235
+ # The arguments to the function must be an Array containing values compliant with the 4.x calling convention.
236
+ # If the targeted function is a 3.x function, the values will be transformed.
237
+ # @param name [String] the name of the function (without the 'function_' prefix used by scope)
238
+ # @param args [Array] arguments, may be empty
239
+ # @param scope [Object] the (runtime specific) scope where evaluation takes place
240
+ # @raise ArgumentError 'unknown function' if the function does not exist
241
+ #
242
+ def external_call_function(name, args, scope, &block)
243
+ # Call via 4x API if the function exists there
244
+ loaders = scope.compiler.loaders
245
+ # Since this is a call from non puppet code, it is not possible to relate it to a module loader
246
+ # It is known where the call originates by using the scope associated module - but this is the calling scope
247
+ # and it does not defined the visibility of functions from a ruby function's perspective. Instead,
248
+ # this is done from the perspective of the environment.
249
+ loader = loaders.private_environment_loader
250
+ if loader && func = loader.load(:function, name)
251
+ return func.call(scope, *args, &block)
252
+ end
253
+
254
+ # Call via 3x API if function exists there
255
+ raise ArgumentError, "Unknown function '#{name}'" unless Puppet::Parser::Functions.function(name)
256
+
257
+ # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x.
258
+ # NOTE: Passing an empty string last converts nil/:undef to empty string
259
+ mapped_args = Puppet::Pops::Evaluator::Runtime3Converter.map_args(args, scope, '')
260
+ result = scope.send("function_#{name}", mapped_args, &block)
261
+ # Prevent non r-value functions from leaking their result (they are not written to care about this)
262
+ Puppet::Parser::Functions.rvalue?(name) ? result : nil
263
+ end
264
+
234
265
  def call_function(name, args, o, scope, &block)
235
266
  # Call via 4x API if the function exists there
236
267
  loaders = scope.compiler.loaders
@@ -183,7 +183,7 @@ module Puppet::Pops::Parser::EppSupport
183
183
  until scanner.eos?
184
184
  part = @scanner.scan_until(/(<%)|\z/)
185
185
  if @skip_leading
186
- part.gsub!(/^[ \t]*\r?\n?/,'')
186
+ part.sub!(/^[ \t]*\r?(?:\n|\z)?/,'')
187
187
  @skip_leading = false
188
188
  end
189
189
  # The spec for %%> is to transform it into a literal %>. This is done here, as %%> otherwise would go
@@ -208,7 +208,7 @@ module Puppet::Pops::Parser::EppSupport
208
208
  # trim trailing whitespace on same line from accumulated s
209
209
  # return text and signal switch to pp mode
210
210
  @scanner.getch # drop the -
211
- s.gsub!(/\r?\n?[ \t]*<%\z/, '')
211
+ s.sub!(/[ \t]*<%\z/, '')
212
212
  @mode = :epp
213
213
  return s
214
214
 
@@ -240,6 +240,8 @@ module Puppet::Pops::Parser::EppSupport
240
240
  @mode = :error
241
241
  return s
242
242
  end
243
+ # Always trim leading whitespace on the same line when there is a comment
244
+ s.sub!(/[ \t]*\z/, '')
243
245
  @skip_leading = true if part.end_with?("-%>")
244
246
  # Continue scanning for more text
245
247
 
@@ -49,7 +49,7 @@ class Puppet::Property::Ensure < Puppet::Property
49
49
 
50
50
  def change_to_s(currentvalue, newvalue)
51
51
  begin
52
- if currentvalue == :absent or currentvalue.nil?
52
+ if currentvalue == :absent || currentvalue.nil?
53
53
  return "created"
54
54
  elsif newvalue == :absent
55
55
  return "removed"
@@ -551,6 +551,11 @@ class Puppet::Provider
551
551
  "#{@resource}(provider=#{self.class.name})"
552
552
  end
553
553
 
554
+ # @return [String] Returns a human readable string with information about the resource and the provider.
555
+ def inspect
556
+ to_s
557
+ end
558
+
554
559
  # Makes providers comparable.
555
560
  include Comparable
556
561
  # Compares this provider against another provider.
@@ -41,6 +41,7 @@ Puppet::Type.type(:augeas).provide(:augeas) do
41
41
  "clearm" => [ :path, :string ],
42
42
  "touch" => [ :path ],
43
43
  "mv" => [ :path, :path ],
44
+ "rename" => [ :path, :string ],
44
45
  "insert" => [ :string, :string, :path ],
45
46
  "get" => [ :path, :comparator, :string ],
46
47
  "defvar" => [ :string, :path ],
@@ -502,6 +503,10 @@ Puppet::Type.type(:augeas).provide(:augeas) do
502
503
  debug("sending command '#{command}' with params #{cmd_array.inspect}")
503
504
  rv = aug.mv(cmd_array[0], cmd_array[1])
504
505
  fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
506
+ when "rename"
507
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
508
+ rv = aug.rename(cmd_array[0], cmd_array[1])
509
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
505
510
  else fail("Command '#{command}' is not supported")
506
511
  end
507
512
  rescue StandardError => e
@@ -7,6 +7,7 @@ Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService:
7
7
  has_features :manages_members
8
8
 
9
9
  defaultfor :operatingsystem => [:freebsd, :dragonfly]
10
+ confine :operatingsystem => [:freebsd, :dragonfly]
10
11
 
11
12
  options :members, :flag => "-M", :method => :mem
12
13
 
@@ -38,6 +38,11 @@ Puppet::Type.type(:group).provide :windows_adsi do
38
38
  return '' if users.nil? or !users.kind_of?(Array)
39
39
  users = users.map do |user_name|
40
40
  sid = Puppet::Util::Windows::SID.name_to_sid_object(user_name)
41
+ if !sid
42
+ resource.debug("#{user_name} (unresolvable to SID)")
43
+ next user_name
44
+ end
45
+
41
46
  if sid.account =~ /\\/
42
47
  account, _ = Puppet::Util::Windows::ADSI::User.parse_name(sid.account)
43
48
  else
@@ -49,6 +54,10 @@ Puppet::Type.type(:group).provide :windows_adsi do
49
54
  return users.join(',')
50
55
  end
51
56
 
57
+ def member_valid?(user_name)
58
+ ! Puppet::Util::Windows::SID.name_to_sid_object(user_name).nil?
59
+ end
60
+
52
61
  def group
53
62
  @group ||= Puppet::Util::Windows::ADSI::Group.new(@resource[:name])
54
63
  end
@@ -178,7 +178,21 @@ Puppet::Type.type(:mount).provide(
178
178
  end
179
179
  end
180
180
  else
181
- record_line self.name, :fields => @fields, :separator => /\s+/, :joiner => "\t", :optional => optional_fields
181
+ record_line self.name, :fields => @fields, :separator => /\s+/, :joiner => "\t", :optional => optional_fields, :block_eval => :instance do
182
+ def pre_gen(record)
183
+ if !record[:options] || record[:options].empty?
184
+ if Facter.value(:kernel) == 'Linux'
185
+ record[:options] = 'defaults'
186
+ else
187
+ raise Puppet::Error, "Mount[#{record[:name]}]: Field 'options' is required"
188
+ end
189
+ end
190
+ if !record[:fstype] || record[:fstype].empty?
191
+ raise Puppet::Error, "Mount[#{record[:name]}]: Field 'fstype' is required"
192
+ end
193
+ record
194
+ end
195
+ end
182
196
  end
183
197
 
184
198
  # Every entry in fstab is :unmounted until we can prove different
@@ -16,8 +16,12 @@ class Puppet::Provider::Package < Puppet::Provider
16
16
  # Look up the current status.
17
17
  def properties
18
18
  if @property_hash.empty?
19
- @property_hash = query || {:ensure => :absent}
20
- @property_hash[:ensure] = :absent if @property_hash.empty?
19
+ # For providers that support purging, default to purged; otherwise default to absent
20
+ # Purged is the "most uninstalled" a package can be, so a purged package will be in-sync with
21
+ # either `ensure => absent` or `ensure => purged`; an absent package will be out of sync with `ensure => purged`.
22
+ default_status = self.class.feature?(:purgeable) ? :purged : :absent
23
+ @property_hash = query || { :ensure => ( default_status )}
24
+ @property_hash[:ensure] = default_status if @property_hash.empty?
21
25
  end
22
26
  @property_hash.dup
23
27
  end
@@ -74,6 +74,22 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
74
74
  end
75
75
  end
76
76
 
77
+ def insync?(is)
78
+ return false unless is && is != :absent
79
+
80
+ begin
81
+ dependency = Gem::Dependency.new('', resource[:ensure])
82
+ rescue ArgumentError
83
+ # Bad requirements will cause an error during gem command invocation, so just return not in sync
84
+ return false
85
+ end
86
+
87
+ is = [is] unless is.is_a? Array
88
+
89
+ # Check if any version matches the dependency
90
+ is.any? { |version| dependency.match?('', version) }
91
+ end
92
+
77
93
  def install(useversion = true)
78
94
  command = [command(:gemcmd), "install"]
79
95
  command << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
@@ -78,10 +78,11 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa
78
78
  end
79
79
 
80
80
  output = Puppet::Util.withenv(e_vars) {pkginfo "-Q", query}
81
+ version = properties[:ensure]
81
82
 
82
83
  if output.nil? or output.size == 0 or output =~ /Error from /
83
84
  debug "Failed to query for #{resource[:name]}"
84
- return properties[:ensure]
85
+ return version
85
86
  else
86
87
  # Remove all fuzzy matches first.
87
88
  output = output.split.select {|p| p =~ /^#{resource[:name]}-(\d[^-]*)[-]?(\w*)/ }.join
@@ -90,22 +91,21 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa
90
91
 
91
92
  if output =~ /^#{resource[:name]}-(\d[^-]*)[-]?(\w*) \(installed\)$/
92
93
  debug "Package is already the latest available"
93
- return properties[:ensure]
94
+ return version
94
95
  else
95
96
  match = /^(.*)-(\d[^-]*)[-]?(\w*)$/.match(output)
96
97
  debug "Latest available for #{resource[:name]}: #{match[2]}"
97
98
 
98
- if properties[:ensure].to_sym == :absent
99
+ if version.to_sym == :absent || version.to_sym == :purged
99
100
  return match[2]
100
101
  end
101
102
 
102
- vcmp = properties[:ensure].split('.').map{|s|s.to_i} <=> match[2].split('.').map{|s|s.to_i}
103
+ vcmp = version.split('.').map{|s|s.to_i} <=> match[2].split('.').map{|s|s.to_i}
103
104
  if vcmp > 0
104
- debug "ensure: #{properties[:ensure]}"
105
105
  # The locally installed package may actually be newer than what a mirror
106
106
  # has. Log it at debug, but ignore it otherwise.
107
- debug "Package #{resource[:name]} #{properties[:ensure]} newer then available #{match[2]}"
108
- return properties[:ensure]
107
+ debug "Package #{resource[:name]} #{version} newer then available #{match[2]}"
108
+ return version
109
109
  else
110
110
  return match[2]
111
111
  end
@@ -30,7 +30,8 @@ Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Packag
30
30
  begin
31
31
  !pacman("-Sg", name).empty?
32
32
  rescue Puppet::ExecutionFailure
33
- fail("Error while determining if '#{@resource[:name]}' is a group")
33
+ # pacman returns an expected non-zero exit code when the name is not a group
34
+ false
34
35
  end
35
36
  end
36
37
 
@@ -74,10 +75,10 @@ Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Packag
74
75
  def self.get_installed_packages
75
76
  begin
76
77
  packages = {}
77
- execpipe([command(:pacman), "-Q"]) do |process|
78
+ execpipe([command(:pacman), "-Q"]) do |pipe|
78
79
  # pacman -Q output is 'packagename version-rel'
79
80
  regex = %r{^(\S+)\s(\S+)}
80
- process.each_line do |line|
81
+ pipe.each_line do |line|
81
82
  if match = regex.match(line)
82
83
  packages[match.captures[0]] = match.captures[1]
83
84
  else
@@ -98,8 +99,8 @@ Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Packag
98
99
  # Build a hash of group name => list of packages
99
100
  command = [command(:pacman), "-Sgg"]
100
101
  command << filter if filter
101
- execpipe(command) do |process|
102
- process.each_line do |line|
102
+ execpipe(command) do |pipe|
103
+ pipe.each_line do |line|
103
104
  name, package = line.split
104
105
  packages = (groups[name] ||= [])
105
106
  packages << package
@@ -115,11 +116,11 @@ Puppet::Type.type(:package).provide :pacman, :parent => Puppet::Provider::Packag
115
116
  groups.each do |name, packages|
116
117
  groups[name] = packages.sort.map {|package| "#{package} #{installed_packages[package]}"}.join ', '
117
118
  end
118
-
119
- groups
120
119
  rescue Puppet::ExecutionFailure
121
- fail("Error while getting installed groups")
120
+ # pacman returns an expected non-zero exit code when the filter name is not a group
121
+ raise unless filter
122
122
  end
123
+ groups
123
124
  end
124
125
 
125
126
  # Because Archlinux is a rolling release based distro, installing a package
@@ -117,7 +117,7 @@ Puppet::Type.type(:package).provide :pip,
117
117
  self.class.commands :pip => pathname
118
118
  pip *args
119
119
  else
120
- raise e, 'Could not locate the pip command.', e.backtrace
120
+ raise e, "Could not locate the #{self.class.cmd} command.", e.backtrace
121
121
  end
122
122
  end
123
123
 
@@ -0,0 +1,18 @@
1
+ # Puppet package provider for Python's `pip3` package management frontend.
2
+ # <http://pip.openplans.org/>
3
+
4
+ require 'puppet/provider/package/pip'
5
+
6
+ Puppet::Type.type(:package).provide :pip3,
7
+ :parent => :pip do
8
+
9
+ desc "Python packages via `pip3`.
10
+
11
+ This provider supports the `install_options` attribute, which allows command-line flags to be passed to pip3.
12
+ These options should be specified as a string (e.g. '--flag'), a hash (e.g. {'--flag' => 'value'}),
13
+ or an array where each element is either a string or a hash."
14
+
15
+ def self.cmd
16
+ "pip3"
17
+ end
18
+ end
@@ -68,8 +68,10 @@ Puppet::Type.type(:package).provide :pkgdmg, :parent => Puppet::Provider::Packag
68
68
  end
69
69
 
70
70
  def self.installpkgdmg(source, name)
71
- http_proxy_host = Puppet::Util::HttpProxy.http_proxy_host
72
- http_proxy_port = Puppet::Util::HttpProxy.http_proxy_port
71
+ unless Puppet::Util::HttpProxy.no_proxy?(source)
72
+ http_proxy_host = Puppet::Util::HttpProxy.http_proxy_host
73
+ http_proxy_port = Puppet::Util::HttpProxy.http_proxy_port
74
+ end
73
75
 
74
76
  unless source =~ /\.dmg$/i || source =~ /\.pkg$/i
75
77
  raise Puppet::Error.new("Mac OS X PKG DMG's must specify a source string ending in .dmg or flat .pkg file")