puppet 2.7.9 → 2.7.11

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 (187) hide show
  1. data/CHANGELOG +413 -0
  2. data/README_DEVELOPER.md +28 -0
  3. data/conf/redhat/puppet.spec +10 -1
  4. data/conf/solaris/pkginfo +1 -1
  5. data/conf/suse/puppet.spec +7 -4
  6. data/ext/envpuppet.bat +13 -0
  7. data/ext/rack/files/apache2.conf +4 -0
  8. data/install.rb +4 -8
  9. data/lib/puppet.rb +1 -1
  10. data/lib/puppet/agent.rb +7 -0
  11. data/lib/puppet/agent/disabler.rb +27 -0
  12. data/lib/puppet/agent/locker.rb +0 -10
  13. data/lib/puppet/application.rb +3 -0
  14. data/lib/puppet/application/agent.rb +13 -3
  15. data/lib/puppet/application/apply.rb +6 -6
  16. data/lib/puppet/application/cert.rb +5 -5
  17. data/lib/puppet/application/instrumentation_data.rb +4 -0
  18. data/lib/puppet/application/instrumentation_listener.rb +4 -0
  19. data/lib/puppet/application/instrumentation_probe.rb +4 -0
  20. data/lib/puppet/configurer.rb +3 -1
  21. data/lib/puppet/configurer/downloader.rb +4 -2
  22. data/lib/puppet/configurer/fact_handler.rb +0 -21
  23. data/lib/puppet/daemon.rb +3 -4
  24. data/lib/puppet/defaults.rb +2 -2
  25. data/lib/puppet/face/instrumentation_data.rb +28 -0
  26. data/lib/puppet/face/instrumentation_listener.rb +96 -0
  27. data/lib/puppet/face/instrumentation_probe.rb +77 -0
  28. data/lib/puppet/face/module/list.rb +64 -0
  29. data/lib/puppet/face/module/uninstall.rb +50 -0
  30. data/lib/puppet/face/node/clean.rb +1 -4
  31. data/lib/puppet/feature/base.rb +1 -0
  32. data/lib/puppet/file_serving/content.rb +1 -1
  33. data/lib/puppet/indirector/facts/facter.rb +20 -7
  34. data/lib/puppet/indirector/facts/inventory_active_record.rb +14 -11
  35. data/lib/puppet/indirector/indirection.rb +7 -0
  36. data/lib/puppet/indirector/instrumentation_data.rb +3 -0
  37. data/lib/puppet/indirector/instrumentation_data/local.rb +19 -0
  38. data/lib/puppet/indirector/instrumentation_data/rest.rb +5 -0
  39. data/lib/puppet/indirector/instrumentation_listener.rb +3 -0
  40. data/lib/puppet/indirector/instrumentation_listener/local.rb +23 -0
  41. data/lib/puppet/indirector/instrumentation_listener/rest.rb +5 -0
  42. data/lib/puppet/indirector/instrumentation_probe.rb +3 -0
  43. data/lib/puppet/indirector/instrumentation_probe/local.rb +24 -0
  44. data/lib/puppet/indirector/instrumentation_probe/rest.rb +5 -0
  45. data/lib/puppet/indirector/rest.rb +1 -1
  46. data/lib/puppet/module.rb +13 -17
  47. data/lib/puppet/module_tool/applications.rb +1 -0
  48. data/lib/puppet/module_tool/applications/uninstaller.rb +33 -0
  49. data/lib/puppet/module_tool/contents_description.rb +1 -1
  50. data/lib/puppet/network/server.rb +2 -3
  51. data/lib/puppet/node/environment.rb +16 -3
  52. data/lib/puppet/parser/ast/leaf.rb +1 -1
  53. data/lib/puppet/parser/functions/create_resources.rb +1 -1
  54. data/lib/puppet/parser/type_loader.rb +1 -1
  55. data/lib/puppet/property.rb +46 -14
  56. data/lib/puppet/provider.rb +13 -4
  57. data/lib/puppet/provider/augeas/augeas.rb +6 -4
  58. data/lib/puppet/provider/group/pw.rb +24 -10
  59. data/lib/puppet/provider/nameservice/directoryservice.rb +146 -37
  60. data/lib/puppet/provider/package/pip.rb +1 -1
  61. data/lib/puppet/provider/package/yum.rb +1 -2
  62. data/lib/puppet/provider/service/debian.rb +14 -0
  63. data/lib/puppet/provider/service/launchd.rb +1 -1
  64. data/lib/puppet/provider/service/smf.rb +2 -2
  65. data/lib/puppet/provider/user/pw.rb +56 -2
  66. data/lib/puppet/provider/user/user_role_add.rb +32 -22
  67. data/lib/puppet/provider/user/windows_adsi.rb +1 -0
  68. data/lib/puppet/rails/benchmark.rb +1 -1
  69. data/lib/puppet/reports/store.rb +8 -1
  70. data/lib/puppet/resource/catalog.rb +5 -1
  71. data/lib/puppet/simple_graph.rb +11 -14
  72. data/lib/puppet/transaction.rb +10 -4
  73. data/lib/puppet/transaction/report.rb +9 -3
  74. data/lib/puppet/type.rb +19 -7
  75. data/lib/puppet/type/exec.rb +1 -1
  76. data/lib/puppet/type/file.rb +4 -1
  77. data/lib/puppet/type/file/ensure.rb +5 -1
  78. data/lib/puppet/type/file/mode.rb +45 -10
  79. data/lib/puppet/type/file/source.rb +4 -0
  80. data/lib/puppet/type/host.rb +17 -3
  81. data/lib/puppet/type/k5login.rb +3 -2
  82. data/lib/puppet/type/schedule.rb +3 -2
  83. data/lib/puppet/util.rb +83 -27
  84. data/lib/puppet/util/anonymous_filelock.rb +36 -0
  85. data/lib/puppet/util/docs.rb +18 -2
  86. data/lib/puppet/util/instrumentation.rb +173 -0
  87. data/lib/puppet/util/instrumentation/data.rb +34 -0
  88. data/lib/puppet/util/instrumentation/indirection_probe.rb +29 -0
  89. data/lib/puppet/util/instrumentation/instrumentable.rb +143 -0
  90. data/lib/puppet/util/instrumentation/listener.rb +60 -0
  91. data/lib/puppet/util/instrumentation/listeners/log.rb +29 -0
  92. data/lib/puppet/util/instrumentation/listeners/performance.rb +30 -0
  93. data/lib/puppet/util/monkey_patches.rb +8 -0
  94. data/lib/puppet/util/pidlock.rb +21 -25
  95. data/lib/puppet/util/rdoc/parser.rb +2 -2
  96. data/lib/puppet/util/reference.rb +8 -23
  97. data/lib/puppet/util/retryaction.rb +48 -0
  98. data/lib/puppet/util/suidmanager.rb +70 -39
  99. data/lib/puppet/util/symbolic_file_mode.rb +140 -0
  100. data/spec/integration/configurer_spec.rb +5 -0
  101. data/spec/integration/indirector/direct_file_server_spec.rb +1 -1
  102. data/spec/integration/indirector/file_content/file_server_spec.rb +7 -7
  103. data/spec/integration/provider/package_spec.rb +7 -0
  104. data/spec/unit/agent/disabler_spec.rb +60 -0
  105. data/spec/unit/agent/locker_spec.rb +0 -12
  106. data/spec/unit/agent_spec.rb +8 -0
  107. data/spec/unit/application/agent_spec.rb +38 -1
  108. data/spec/unit/application/apply_spec.rb +34 -40
  109. data/spec/unit/application/cert_spec.rb +1 -1
  110. data/spec/unit/application_spec.rb +6 -0
  111. data/spec/unit/configurer/downloader_spec.rb +29 -10
  112. data/spec/unit/configurer/fact_handler_spec.rb +5 -29
  113. data/spec/unit/configurer_spec.rb +8 -8
  114. data/spec/unit/daemon_spec.rb +12 -26
  115. data/spec/unit/face/instrumentation_data.rb +7 -0
  116. data/spec/unit/face/instrumentation_listener.rb +38 -0
  117. data/spec/unit/face/instrumentation_probe.rb +21 -0
  118. data/spec/unit/face/node_spec.rb +111 -111
  119. data/spec/unit/file_serving/content_spec.rb +2 -2
  120. data/spec/unit/indirector/facts/facter_spec.rb +25 -3
  121. data/spec/unit/indirector/facts/inventory_active_record_spec.rb +14 -4
  122. data/spec/unit/indirector/instrumentation_data/local_spec.rb +52 -0
  123. data/spec/unit/indirector/instrumentation_data/rest_spec.rb +11 -0
  124. data/spec/unit/indirector/instrumentation_listener/local_spec.rb +65 -0
  125. data/spec/unit/indirector/instrumentation_listener/rest_spec.rb +11 -0
  126. data/spec/unit/indirector/instrumentation_probe/local_spec.rb +65 -0
  127. data/spec/unit/indirector/instrumentation_probe/rest_spec.rb +11 -0
  128. data/spec/unit/module_spec.rb +39 -125
  129. data/spec/unit/module_tool/uninstaller_spec.rb +44 -0
  130. data/spec/unit/network/server_spec.rb +2 -20
  131. data/spec/unit/node/environment_spec.rb +76 -58
  132. data/spec/unit/parser/ast/asthash_spec.rb +1 -2
  133. data/spec/unit/parser/ast/leaf_spec.rb +16 -0
  134. data/spec/unit/property/keyvalue_spec.rb +5 -2
  135. data/spec/unit/property_spec.rb +260 -159
  136. data/spec/unit/provider/augeas/augeas_spec.rb +2 -2
  137. data/spec/unit/provider/group/pw_spec.rb +81 -0
  138. data/spec/unit/provider/nameservice/directoryservice_spec.rb +102 -0
  139. data/spec/unit/provider/package/pip_spec.rb +7 -0
  140. data/spec/unit/provider/package/yum_spec.rb +45 -1
  141. data/spec/unit/provider/service/debian_spec.rb +15 -0
  142. data/spec/unit/provider/service/launchd_spec.rb +48 -43
  143. data/spec/unit/provider/service/smf_spec.rb +3 -3
  144. data/spec/unit/provider/user/pw_spec.rb +183 -0
  145. data/spec/unit/provider/user/user_role_add_spec.rb +46 -39
  146. data/spec/unit/provider/user/windows_adsi_spec.rb +1 -0
  147. data/spec/unit/provider_spec.rb +32 -0
  148. data/spec/unit/reports/store_spec.rb +19 -1
  149. data/spec/unit/simple_graph_spec.rb +34 -19
  150. data/spec/unit/ssl/certificate_factory_spec.rb +3 -3
  151. data/spec/unit/transaction/report_spec.rb +29 -1
  152. data/spec/unit/transaction_spec.rb +32 -46
  153. data/spec/unit/type/file/mode_spec.rb +1 -1
  154. data/spec/unit/type/file/source_spec.rb +28 -3
  155. data/spec/unit/type/file_spec.rb +17 -16
  156. data/spec/unit/type/host_spec.rb +527 -0
  157. data/spec/unit/type/k5login_spec.rb +115 -0
  158. data/spec/unit/type/schedule_spec.rb +6 -6
  159. data/spec/unit/type_spec.rb +51 -0
  160. data/spec/unit/util/anonymous_filelock_spec.rb +78 -0
  161. data/spec/unit/util/execution_stub_spec.rb +2 -1
  162. data/spec/unit/util/instrumentation/data_spec.rb +44 -0
  163. data/spec/unit/util/instrumentation/indirection_probe_spec.rb +19 -0
  164. data/spec/unit/util/instrumentation/instrumentable_spec.rb +186 -0
  165. data/spec/unit/util/instrumentation/listener_spec.rb +100 -0
  166. data/spec/unit/util/instrumentation/listeners/log_spec.rb +34 -0
  167. data/spec/unit/util/instrumentation/listeners/performance_spec.rb +36 -0
  168. data/spec/unit/util/instrumentation_spec.rb +181 -0
  169. data/spec/unit/util/pidlock_spec.rb +208 -0
  170. data/spec/unit/util/rdoc/parser_spec.rb +1 -1
  171. data/spec/unit/util/reference_spec.rb +16 -6
  172. data/spec/unit/util/retryaction_spec.rb +62 -0
  173. data/spec/unit/util/suidmanager_spec.rb +101 -83
  174. data/spec/unit/util/symbolic_file_mode_spec.rb +182 -0
  175. data/spec/unit/util_spec.rb +126 -0
  176. data/tasks/rake/apple.rake +176 -0
  177. data/tasks/rake/templates/prototype.plist.erb +38 -0
  178. metadata +61 -13
  179. data/lib/puppet/application/module.rb +0 -3
  180. data/lib/puppet/face/module.rb +0 -12
  181. data/spec/unit/face/module/build_spec.rb +0 -30
  182. data/spec/unit/face/module/changes_spec.rb +0 -30
  183. data/spec/unit/face/module/clean_spec.rb +0 -30
  184. data/spec/unit/face/module/generate_spec.rb +0 -30
  185. data/spec/unit/face/module/install_spec.rb +0 -75
  186. data/spec/unit/face/module/search_spec.rb +0 -40
  187. data/test/util/pidlock.rb +0 -126
@@ -1,3 +1,4 @@
1
+ require 'puppet/util'
1
2
  require 'puppet/util/user_attr'
2
3
 
3
4
  Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => :useradd do
@@ -145,11 +146,22 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source =>
145
146
  run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs")
146
147
  end
147
148
 
149
+
150
+ # This helper makes it possible to test this on stub data without having to
151
+ # do too many crazy things!
152
+ def target_file_path
153
+ "/etc/shadow"
154
+ end
155
+ private :target_file_path
156
+
148
157
  #Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return it
149
158
  #No abstraction, all esoteric knowledge of file formats, yay
150
159
  def shadow_entry
151
160
  return @shadow_entry if defined? @shadow_entry
152
- @shadow_entry = File.readlines("/etc/shadow").reject { |r| r =~ /^[^\w]/ }.collect { |l| l.chomp.split(':') }.find { |user, _| user == @resource[:name] }
161
+ @shadow_entry = File.readlines(target_file_path).
162
+ reject { |r| r =~ /^[^\w]/ }.
163
+ collect { |l| l.chomp.split(':') }.
164
+ find { |user, _| user == @resource[:name] }
153
165
  end
154
166
 
155
167
  def password
@@ -164,33 +176,31 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source =>
164
176
  shadow_entry ? shadow_entry[4] : :absent
165
177
  end
166
178
 
167
- #Read in /etc/shadow, find the line for our used and rewrite it with the new pw
168
- #Smooth like 80 grit
179
+ # Read in /etc/shadow, find the line for our used and rewrite it with the
180
+ # new pw. Smooth like 80 grit sandpaper.
181
+ #
182
+ # Now uses the `replace_file` mechanism to minimize the chance that we lose
183
+ # data, but it is still terrible. We still skip platform locking, so a
184
+ # concurrent `vipw -s` session will have no idea we risk data loss.
169
185
  def password=(cryptopw)
170
186
  begin
171
- File.open(shadow_file, "r") do |shadow|
172
- File.open("#{shadow_file}_tmp", "w", 0600) do |shadow_tmp|
173
- while line = shadow.gets
174
- line_arr = line.split(':')
175
- if line_arr[0] == @resource[:name]
176
- line_arr[1] = cryptopw
177
- line_arr[2] = Time.now().to_i / 86400
178
- line = line_arr.join(':')
179
- end
180
- shadow_tmp.print line
187
+ shadow = File.read(target_file_path)
188
+
189
+ # Go Mifune loves the race here where we can lose data because
190
+ # /etc/shadow changed between reading it and writing it.
191
+ # --daniel 2012-02-05
192
+ Puppet::Util.replace_file(target_file_path, 0640) do |fh|
193
+ shadow.each_line do |line|
194
+ line_arr = line.split(':')
195
+ if line_arr[0] == @resource[:name]
196
+ line_arr[1] = cryptopw
197
+ line = line_arr.join(':')
181
198
  end
199
+ fh.print line
182
200
  end
183
201
  end
184
- File.rename("#{shadow_file}_tmp", shadow_file)
185
202
  rescue => detail
186
- fail "Could not write temporary shadow file: #{detail}"
187
- ensure
188
- # Make sure this *always* gets deleted
189
- File.unlink("#{shadow_file}_tmp") if File.exist?("#{shadow_file}_tmp")
203
+ fail "Could not write replace #{target_file_path}: #{detail}"
190
204
  end
191
205
  end
192
-
193
- private
194
-
195
- def shadow_file; '/etc/shadow'; end
196
206
  end
@@ -22,6 +22,7 @@ Puppet::Type.type(:user).provide :windows_adsi do
22
22
 
23
23
  def create
24
24
  @user = Puppet::Util::ADSI::User.create(@resource[:name])
25
+ @user.password = @resource[:password]
25
26
  @user.commit
26
27
 
27
28
  [:comment, :home, :groups].each do |prop|
@@ -58,6 +58,6 @@ module Puppet::Rails::Benchmark
58
58
  data = {}
59
59
  end
60
60
  data[branch] = $benchmarks
61
- Puppet::Util.secure_open(file, "w") { |f| f.print YAML.dump(data) }
61
+ Puppet::Util.replace_file(file, 0644) { |f| f.print YAML.dump(data) }
62
62
  end
63
63
  end
@@ -1,4 +1,6 @@
1
1
  require 'puppet'
2
+ require 'fileutils'
3
+ require 'tempfile'
2
4
 
3
5
  Puppet::Reports.register_report(:store) do
4
6
  desc "Store the yaml report on disk. Each host sends its report as a YAML dump
@@ -29,10 +31,15 @@ Puppet::Reports.register_report(:store) do
29
31
 
30
32
  file = File.join(dir, name)
31
33
 
34
+ f = Tempfile.new(name, dir)
32
35
  begin
33
- File.open(file, "w", 0640) do |f|
36
+ begin
37
+ f.chmod(0640)
34
38
  f.print to_yaml
39
+ ensure
40
+ f.close
35
41
  end
42
+ FileUtils.mv(f.path, file)
36
43
  rescue => detail
37
44
  puts detail.backtrace if Puppet[:trace]
38
45
  Puppet.warning "Could not write report for #{client} at #{file}: #{detail}"
@@ -547,7 +547,11 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph
547
547
  ::File.open(Puppet[:resourcefile], "w") do |f|
548
548
  to_print = resources.map do |resource|
549
549
  next unless resource.managed?
550
- "#{resource.type}[#{resource[resource.name_var]}]"
550
+ if resource.name_var
551
+ "#{resource.type}[#{resource[resource.name_var]}]"
552
+ else
553
+ "#{resource.ref.downcase}"
554
+ end
551
555
  end.compact
552
556
  f.puts to_print.join("\n")
553
557
  end
@@ -136,18 +136,7 @@ class Puppet::SimpleGraph
136
136
  s[:seen][top] = false
137
137
  this_scc << top
138
138
  end until top == vertex
139
- # NOTE: if we don't reverse we get the components in the opposite
140
- # order to what a human being would expect; reverse should be an
141
- # O(1) operation, without even copying, because we know the length
142
- # of the source, but I worry that an implementation will get this
143
- # wrong. Still, the worst case is O(n) for n vertices as we can't
144
- # possibly put a vertex into two SCCs.
145
- #
146
- # Also, my feeling is that most implementations are going to do
147
- # better with a reverse operation than a string of 'unshift'
148
- # insertions at the head of the array; if they were going to mess
149
- # up the performance of one, it would be unshift.
150
- s[:scc] << this_scc.reverse
139
+ s[:scc] << this_scc
151
140
  end
152
141
  recur.pop # done with this node, finally.
153
142
  end
@@ -181,7 +170,15 @@ class Puppet::SimpleGraph
181
170
  end
182
171
  end
183
172
 
184
- state[:scc].select { |c| c.length > 1 }
173
+ # To provide consistent results to the user, given that a hash is never
174
+ # assured to return the same order, and given our graph processing is
175
+ # based on hash tables, we need to sort the cycles internally, as well as
176
+ # the set of cycles.
177
+ #
178
+ # Given we are in a failure state here, any extra cost is more or less
179
+ # irrelevant compared to the cost of a fix - which is on a human
180
+ # time-scale.
181
+ state[:scc].select { |c| c.length > 1 }.map {|x| x.sort }.sort
185
182
  end
186
183
 
187
184
  # Perform a BFS on the sub graph representing the cycle, with a view to
@@ -215,7 +212,7 @@ class Puppet::SimpleGraph
215
212
  end
216
213
  end
217
214
 
218
- return found
215
+ return found.sort
219
216
  end
220
217
 
221
218
  def report_cycles_in_graph
@@ -100,6 +100,7 @@ class Puppet::Transaction
100
100
  if resource.is_a?(Puppet::Type::Component)
101
101
  Puppet.warning "Somehow left a component in the relationship graph"
102
102
  else
103
+ resource.info "Starting to evaluate the resource" if Puppet[:evaltrace] and @catalog.host_config?
103
104
  seconds = thinmark { eval_resource(resource) }
104
105
  resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config?
105
106
  end
@@ -317,10 +318,6 @@ class Puppet::Transaction
317
318
  @blockers = {}
318
319
  @unguessable_deterministic_key = Hash.new { |h,k| h[k] = Digest::SHA1.hexdigest("NaCl, MgSO4 (salts) and then #{k.ref}") }
319
320
  @providerless_types = []
320
- vertices.each do |v|
321
- blockers[v] = direct_dependencies_of(v).length
322
- enqueue(v) if blockers[v] == 0
323
- end
324
321
  end
325
322
  def method_missing(*args,&block)
326
323
  real_graph.send(*args,&block)
@@ -335,6 +332,13 @@ class Puppet::Transaction
335
332
 
336
333
  real_graph.add_edge(f,t,label)
337
334
  end
335
+ # Enqueue the initial set of resources, those with no dependencies.
336
+ def enqueue_roots
337
+ vertices.each do |v|
338
+ blockers[v] = direct_dependencies_of(v).length
339
+ enqueue(v) if blockers[v] == 0
340
+ end
341
+ end
338
342
  # Decrement the blocker count for the resource by 1. If the number of
339
343
  # blockers is unknown, count them and THEN decrement by 1.
340
344
  def unblock(resource)
@@ -364,6 +368,8 @@ class Puppet::Transaction
364
368
  def traverse(&block)
365
369
  real_graph.report_cycles_in_graph
366
370
 
371
+ enqueue_roots
372
+
367
373
  deferred_resources = []
368
374
 
369
375
  while (resource = next_resource) && !transaction.stop_processing?
@@ -115,7 +115,7 @@ class Puppet::Transaction::Report
115
115
 
116
116
  # Provide a raw hash summary of this report.
117
117
  def raw_summary
118
- report = {}
118
+ report = { "version" => { "config" => configuration_version, "puppet" => Puppet.version } }
119
119
 
120
120
  @metrics.each do |name, metric|
121
121
  key = metric.name.to_s
@@ -151,7 +151,7 @@ class Puppet::Transaction::Report
151
151
 
152
152
  def calculate_event_metrics
153
153
  metrics = Hash.new(0)
154
- metrics["total"] = 0
154
+ %w{total failure success}.each { |m| metrics[m] = 0 }
155
155
  resource_statuses.each do |name, status|
156
156
  metrics["total"] += status.events.length
157
157
  status.events.each do |event|
@@ -163,9 +163,15 @@ class Puppet::Transaction::Report
163
163
  end
164
164
 
165
165
  def calculate_resource_metrics
166
- metrics = Hash.new(0)
166
+ metrics = {}
167
167
  metrics["total"] = resource_statuses.length
168
168
 
169
+ # force every resource key in the report to be present
170
+ # even if no resources is in this given state
171
+ Puppet::Resource::Status::STATES.each do |state|
172
+ metrics[state.to_s] = 0
173
+ end
174
+
169
175
  resource_statuses.each do |name, status|
170
176
  Puppet::Resource::Status::STATES.each do |state|
171
177
  metrics[state.to_s] += 1 if status.send(state)
@@ -23,6 +23,17 @@ class Type
23
23
  include Puppet::FileCollection::Lookup
24
24
  include Puppet::Util::Tagging
25
25
 
26
+ ###############################
27
+ # Comparing type instances.
28
+ include Comparable
29
+ def <=>(other)
30
+ # We only order against other types, not arbitrary objects.
31
+ return nil unless other.is_a? Puppet::Type
32
+ # Our natural order is based on the reference name we use when comparing
33
+ # against other type instances.
34
+ self.ref <=> other.ref
35
+ end
36
+
26
37
  ###############################
27
38
  # Code related to resource type attributes.
28
39
  class << self
@@ -107,11 +118,9 @@ class Type
107
118
  def self.ensurable?
108
119
  # If the class has all three of these methods defined, then it's
109
120
  # ensurable.
110
- ens = [:exists?, :create, :destroy].inject { |set, method|
111
- set &&= self.public_method_defined?(method)
121
+ [:exists?, :create, :destroy].all? { |method|
122
+ self.public_method_defined?(method)
112
123
  }
113
-
114
- ens
115
124
  end
116
125
 
117
126
  def self.apply_to_device
@@ -1500,11 +1509,14 @@ class Type
1500
1509
 
1501
1510
  # We need to add documentation for each provider.
1502
1511
  def self.doc
1503
- @doc + " Available providers are:\n\n" + parenttype.providers.sort { |a,b|
1512
+ # Since we're mixing @doc with text from other sources, we must normalize
1513
+ # its indentation with scrub. But we don't need to manually scrub the
1514
+ # provider's doc string, since markdown_definitionlist sanitizes its inputs.
1515
+ scrub(@doc) + "Available providers are:\n\n" + parenttype.providers.sort { |a,b|
1504
1516
  a.to_s <=> b.to_s
1505
1517
  }.collect { |i|
1506
- "* **#{i}**: #{parenttype().provider(i).doc}"
1507
- }.join("\n")
1518
+ markdown_definitionlist( i, scrub(parenttype().provider(i).doc) )
1519
+ }.join
1508
1520
  end
1509
1521
 
1510
1522
  defaultto {
@@ -170,7 +170,7 @@ module Puppet
170
170
  desc "The group to run the command as. This seems to work quite
171
171
  haphazardly on different platforms -- it is a platform issue
172
172
  not a Ruby or Puppet one, since the same variety exists when
173
- running commnands as different users in the shell."
173
+ running commands as different users in the shell."
174
174
  # Validation is handled by the SUIDManager class.
175
175
  end
176
176
 
@@ -9,11 +9,14 @@ require 'puppet/network/handler'
9
9
  require 'puppet/util/diff'
10
10
  require 'puppet/util/checksums'
11
11
  require 'puppet/util/backups'
12
+ require 'puppet/util/symbolic_file_mode'
12
13
 
13
14
  Puppet::Type.newtype(:file) do
14
15
  include Puppet::Util::MethodHelper
15
16
  include Puppet::Util::Checksums
16
17
  include Puppet::Util::Backups
18
+ include Puppet::Util::SymbolicFileMode
19
+
17
20
  @doc = "Manages local files, including setting ownership and
18
21
  permissions, creation of both files and directories, and
19
22
  retrieving entire files from remote servers. As Puppet matures, it
@@ -734,7 +737,7 @@ Puppet::Type.newtype(:file) do
734
737
 
735
738
  mode = self.should(:mode) # might be nil
736
739
  umask = mode ? 000 : 022
737
- mode_int = mode ? mode.to_i(8) : nil
740
+ mode_int = mode ? symbolic_mode_to_int(mode, 0644) : nil
738
741
 
739
742
  content_checksum = Puppet::Util.withumask(umask) { ::File.open(path, 'wb', mode_int ) { |f| write_content(f) } }
740
743
 
@@ -1,6 +1,10 @@
1
+
1
2
  module Puppet
2
3
  Puppet::Type.type(:file).ensurable do
3
4
  require 'etc'
5
+ require 'puppet/util/symbolic_file_mode'
6
+ include Puppet::Util::SymbolicFileMode
7
+
4
8
  desc <<-EOT
5
9
  Whether to create files that don't currently exist.
6
10
  Possible values are *absent*, *present*, *file*, and *directory*.
@@ -63,7 +67,7 @@ module Puppet
63
67
  end
64
68
  if mode
65
69
  Puppet::Util.withumask(000) do
66
- Dir.mkdir(@resource[:path], mode.to_i(8))
70
+ Dir.mkdir(@resource[:path], symbolic_mode_to_int(mode, 755, true))
67
71
  end
68
72
  else
69
73
  Dir.mkdir(@resource[:path])
@@ -3,6 +3,9 @@
3
3
  # specifying the full mode.
4
4
  module Puppet
5
5
  Puppet::Type.type(:file).newproperty(:mode) do
6
+ require 'puppet/util/symbolic_file_mode'
7
+ include Puppet::Util::SymbolicFileMode
8
+
6
9
  desc "Mode the file should be. Currently relatively limited:
7
10
  you must specify the exact mode the file should be.
8
11
 
@@ -23,23 +26,32 @@ module Puppet
23
26
  mode 644, and all of the directories will have mode 755."
24
27
 
25
28
  validate do |value|
26
- if value.is_a?(String) and value !~ /^[0-7]+$/
27
- raise Puppet::Error, "File modes can only be octal numbers, not #{should.inspect}"
29
+ unless value.nil? or valid_symbolic_mode?(value)
30
+ raise Puppet::Error, "The file mode specification is invalid: #{value.inspect}"
28
31
  end
29
32
  end
30
33
 
31
- munge do |should|
32
- if should.is_a?(String)
33
- should.to_i(8).to_s(8)
34
- else
35
- should.to_s(8)
34
+ munge do |value|
35
+ return nil if value.nil?
36
+
37
+ unless valid_symbolic_mode?(value)
38
+ raise Puppet::Error, "The file mode specification is invalid: #{value.inspect}"
36
39
  end
40
+
41
+ normalize_symbolic_mode(value)
42
+ end
43
+
44
+ def desired_mode_from_current(desired, current)
45
+ current = current.to_i(8) if current.is_a? String
46
+ is_a_directory = @resource.stat and @resource.stat.directory?
47
+ symbolic_mode_to_int(desired, current, is_a_directory)
37
48
  end
38
49
 
39
50
  # If we're a directory, we need to be executable for all cases
40
51
  # that are readable. This should probably be selectable, but eh.
41
52
  def dirmask(value)
42
- if FileTest.directory?(resource[:path])
53
+ orig = value
54
+ if FileTest.directory?(resource[:path]) and value =~ /^\d+$/ then
43
55
  value = value.to_i(8)
44
56
  value |= 0100 if value & 0400 != 0
45
57
  value |= 010 if value & 040 != 0
@@ -61,6 +73,13 @@ module Puppet
61
73
  end
62
74
  end
63
75
 
76
+ def property_matches?(current, desired)
77
+ return false unless current
78
+ current_bits = normalize_symbolic_mode(current)
79
+ desired_bits = desired_mode_from_current(desired, current).to_s(8)
80
+ current_bits == desired_bits
81
+ end
82
+
64
83
  # Ideally, dirmask'ing could be done at munge time, but we don't know if 'ensure'
65
84
  # will eventually be a directory or something else. And unfortunately, that logic
66
85
  # depends on the ensure, source, and target properties. So rather than duplicate
@@ -74,12 +93,28 @@ module Puppet
74
93
  super
75
94
  end
76
95
 
96
+ # Finally, when we sync the mode out we need to transform it; since we
97
+ # don't have access to the calculated "desired" value here, or the
98
+ # "current" value, only the "should" value we need to retrieve again.
99
+ def sync
100
+ current = @resource.stat ? @resource.stat.mode : 0644
101
+ set(desired_mode_from_current(@should[0], current).to_s(8))
102
+ end
103
+
104
+ def change_to_s(old_value, desired)
105
+ return super if desired =~ /^\d+$/
106
+
107
+ old_bits = normalize_symbolic_mode(old_value)
108
+ new_bits = normalize_symbolic_mode(desired_mode_from_current(desired, old_bits))
109
+ super(old_bits, new_bits) + " (#{desired})"
110
+ end
111
+
77
112
  def should_to_s(should_value)
78
- should_value.rjust(4,"0")
113
+ should_value.rjust(4, "0")
79
114
  end
80
115
 
81
116
  def is_to_s(currentvalue)
82
- currentvalue.rjust(4,"0")
117
+ currentvalue.rjust(4, "0")
83
118
  end
84
119
  end
85
120
  end