chef 0.7.10 → 0.7.12

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of chef might be problematic. Click here for more details.

Files changed (70) hide show
  1. data/distro/debian/etc/init.d/chef-client +175 -0
  2. data/distro/debian/etc/init.d/chef-indexer +175 -0
  3. data/distro/debian/etc/init.d/chef-server +120 -0
  4. data/distro/debian/man/man1/chef-indexer.1 +42 -0
  5. data/distro/debian/man/man1/chef-server.1 +108 -0
  6. data/distro/debian/man/man8/chef-client.8 +61 -0
  7. data/distro/debian/man/man8/chef-solo.8 +58 -0
  8. data/distro/redhat/etc/chef/client.rb +16 -0
  9. data/distro/redhat/etc/chef/indexer.rb +10 -0
  10. data/distro/redhat/etc/chef/server.rb +22 -0
  11. data/distro/redhat/etc/init.d/chef-client +74 -0
  12. data/distro/redhat/etc/init.d/chef-indexer +76 -0
  13. data/distro/redhat/etc/init.d/chef-server +77 -0
  14. data/lib/chef.rb +1 -1
  15. data/lib/chef/client.rb +33 -8
  16. data/lib/chef/compile.rb +34 -2
  17. data/lib/chef/cookbook.rb +29 -2
  18. data/lib/chef/cookbook_loader.rb +61 -49
  19. data/lib/chef/couchdb.rb +7 -3
  20. data/lib/chef/mixin/command.rb +67 -32
  21. data/lib/chef/mixin/convert_to_class_name.rb +48 -0
  22. data/lib/chef/mixin/find_preferred_file.rb +5 -14
  23. data/lib/chef/mixin/from_file.rb +14 -0
  24. data/lib/chef/mixin/generate_url.rb +2 -1
  25. data/lib/chef/mixin/recipe_definition_dsl_core.rb +77 -0
  26. data/lib/chef/platform.rb +1 -1
  27. data/lib/chef/provider.rb +63 -2
  28. data/lib/chef/provider/cron.rb +75 -25
  29. data/lib/chef/provider/deploy.rb +281 -0
  30. data/lib/chef/provider/deploy/revision.rb +70 -0
  31. data/lib/chef/provider/deploy/timestamped.rb +33 -0
  32. data/lib/chef/provider/git.rb +194 -0
  33. data/lib/chef/provider/group.rb +2 -2
  34. data/lib/chef/provider/group/gpasswd.rb +50 -0
  35. data/lib/chef/provider/group/groupadd.rb +2 -16
  36. data/lib/chef/provider/group/usermod.rb +57 -0
  37. data/lib/chef/provider/ifconfig.rb +3 -3
  38. data/lib/chef/provider/mount.rb +0 -4
  39. data/lib/chef/provider/mount/mount.rb +2 -2
  40. data/lib/chef/provider/package.rb +2 -2
  41. data/lib/chef/provider/package/apt.rb +4 -4
  42. data/lib/chef/provider/package/dpkg.rb +9 -13
  43. data/lib/chef/provider/package/freebsd.rb +6 -6
  44. data/lib/chef/provider/package/macports.rb +4 -4
  45. data/lib/chef/provider/package/portage.rb +3 -3
  46. data/lib/chef/provider/package/rpm.rb +4 -4
  47. data/lib/chef/provider/package/rubygems.rb +10 -4
  48. data/lib/chef/provider/package/yum.rb +6 -6
  49. data/lib/chef/provider/remote_file.rb +14 -7
  50. data/lib/chef/provider/service.rb +8 -2
  51. data/lib/chef/provider/service/freebsd.rb +1 -1
  52. data/lib/chef/provider/service/init.rb +8 -63
  53. data/lib/chef/provider/service/redhat.rb +2 -2
  54. data/lib/chef/provider/service/simple.rb +115 -0
  55. data/lib/chef/provider/subversion.rb +145 -0
  56. data/lib/chef/provider/template.rb +2 -0
  57. data/lib/chef/provider/user.rb +2 -2
  58. data/lib/chef/recipe.rb +9 -75
  59. data/lib/chef/resource.rb +131 -7
  60. data/lib/chef/resource/cron.rb +36 -0
  61. data/lib/chef/resource/deploy.rb +360 -0
  62. data/lib/chef/resource/deploy_revision.rb +35 -0
  63. data/lib/chef/resource/git.rb +36 -0
  64. data/lib/chef/resource/group.rb +2 -0
  65. data/lib/chef/resource/scm.rb +129 -0
  66. data/lib/chef/resource/subversion.rb +33 -0
  67. data/lib/chef/resource/timestamped_deploy.rb +31 -0
  68. data/lib/chef/resource_collection.rb +32 -4
  69. data/lib/chef/runner.rb +35 -28
  70. metadata +40 -11
@@ -25,8 +25,8 @@ class Chef
25
25
  class Cron < Chef::Provider
26
26
  include Chef::Mixin::Command
27
27
 
28
- def initialize(node, new_resource)
29
- super(node, new_resource)
28
+ def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
29
+ super(node, new_resource, collection, definitions, cookbook_loader)
30
30
  @cron_exists = false
31
31
  @cron_empty = false
32
32
  end
@@ -35,17 +35,46 @@ class Chef
35
35
  def load_current_resource
36
36
  crontab = String.new
37
37
  @current_resource = Chef::Resource::Cron.new(@new_resource.name)
38
+ @current_resource.user(@new_resource.user)
38
39
  status = popen4("crontab -l -u #{@new_resource.user}") do |pid, stdin, stdout, stderr|
39
40
  stdout.each { |line| crontab << line }
40
41
  end
41
42
  if status.exitstatus > 1
42
43
  raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
43
44
  elsif status.exitstatus == 0
45
+ cron_found = false
44
46
  crontab.each do |line|
45
47
  case line
46
48
  when /^# Chef Name: #{@new_resource.name}/
47
49
  Chef::Log.debug("Found cron '#{@new_resource.name}'")
50
+ cron_found = true
48
51
  @cron_exists = true
52
+ next
53
+ when /^MAILTO=(\S*)/
54
+ @current_resource.mailto($1) if cron_found
55
+ next
56
+ when /^PATH=(\S*)/
57
+ @current_resource.path($1) if cron_found
58
+ next
59
+ when /^SHELL=(\S*)/
60
+ @current_resource.shell($1) if cron_found
61
+ next
62
+ when /^HOME=(\S*)/
63
+ @current_resource.home($1) if cron_found
64
+ next
65
+ when /([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*(.*)/
66
+ if cron_found
67
+ @current_resource.minute($1)
68
+ @current_resource.hour($2)
69
+ @current_resource.day($3)
70
+ @current_resource.month($4)
71
+ @current_resource.weekday($5)
72
+ @current_resource.command($6)
73
+ cron_found=false
74
+ end
75
+ next
76
+ else
77
+ next
49
78
  end
50
79
  end
51
80
  Chef::Log.debug("Cron '#{@new_resource.name}' not found") unless @cron_exists
@@ -57,36 +86,53 @@ class Chef
57
86
  @current_resource
58
87
  end
59
88
 
89
+ def compare_cron
90
+ [ :minute, :hour, :day, :month, :weekday, :command, :mailto, :path, :shell, :home ].any? do |cron_var|
91
+ !@new_resource.send(cron_var).nil? && @new_resource.send(cron_var) != @current_resource.send(cron_var)
92
+ end
93
+ end
94
+
60
95
  def action_create
61
96
  crontab = String.new
97
+ newcron = String.new
62
98
  cron_found = false
99
+
100
+ newcron << "# Chef Name: #{new_resource.name}\n"
101
+ [ :mailto, :path, :shell, :home ].each do |v|
102
+ newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
103
+ end
104
+ newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
105
+
63
106
  if @cron_exists
107
+ unless compare_cron
108
+ Chef::Log.debug("Skipping existing cron entry '#{@new_resource.name}'")
109
+ return
110
+ end
64
111
  status = popen4("crontab -l -u #{@new_resource.user}") do |pid, stdin, stdout, stderr|
65
112
  stdout.each_line do |line|
66
- if cron_found
67
- cronline = "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
68
- if (line == cronline)
69
- Chef::Log.debug("Skipping existing cron entry '#{@new_resource.name}'")
70
- return
71
- end
72
- crontab << cronline
73
- cron_found = false
74
- next
75
- end
76
113
  case line
77
- when /^# Chef Name: #{new_resource.name}\n/
114
+ when /^# Chef Name: #{@new_resource.name}\n/
78
115
  cron_found = true
116
+ next
117
+ when /([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*(.*)/
118
+ if cron_found
119
+ cron_found = false
120
+ crontab << newcron
121
+ next
122
+ end
123
+ else
124
+ next if cron_found
79
125
  end
80
126
  crontab << line
81
127
  end
82
128
  end
83
129
 
84
-
85
130
  status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
86
131
  crontab.each { |line| stdin.puts "#{line}" }
87
- stdin.close
132
+ stdin.close rescue nil
88
133
  end
89
134
  Chef::Log.info("Updated cron '#{@new_resource.name}'")
135
+ @new_resource.updated = true
90
136
  else
91
137
  unless @cron_empty
92
138
  status = popen4("crontab -l -u #{@new_resource.user}") do |pid, stdin, stdout, stderr|
@@ -94,14 +140,14 @@ class Chef
94
140
  end
95
141
  end
96
142
 
97
- crontab << "# Chef Name: #{new_resource.name}\n"
98
- crontab << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
99
-
143
+ crontab << newcron
144
+
100
145
  status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
101
146
  crontab.each { |line| stdin.puts "#{line}" }
102
- stdin.close
147
+ stdin.close rescue nil
103
148
  end
104
149
  Chef::Log.info("Added cron '#{@new_resource.name}'")
150
+ @new_resource.updated = true
105
151
  end
106
152
  end
107
153
 
@@ -111,14 +157,17 @@ class Chef
111
157
  cron_found = false
112
158
  status = popen4("crontab -l -u #{@new_resource.user}") do |pid, stdin, stdout, stderr|
113
159
  stdout.each_line do |line|
114
- if cron_found
115
- cron_found = false
116
- next
117
- end
118
160
  case line
119
- when /^# Chef Name: #{new_resource.name}\n/
161
+ when /^# Chef Name: #{@new_resource.name}\n/
120
162
  cron_found = true
121
163
  next
164
+ when /([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*([0-9\*]+)\s*(.*)/
165
+ if cron_found
166
+ cron_found = false
167
+ next
168
+ end
169
+ else
170
+ next if cron_found
122
171
  end
123
172
  crontab << line
124
173
  end
@@ -126,9 +175,10 @@ class Chef
126
175
 
127
176
  status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
128
177
  crontab.each { |line| stdin.puts "#{line}" }
129
- stdin.close
178
+ stdin.close rescue nil
130
179
  end
131
180
  Chef::Log.debug("Deleted cron '#{@new_resource.name}'")
181
+ @new_resource.updated = true
132
182
  end
133
183
  end
134
184
 
@@ -0,0 +1,281 @@
1
+ #
2
+ # Author:: Daniel DeLeo (<dan@kallistec.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "chef/mixin/command"
20
+ require "chef/mixin/from_file"
21
+ require "chef/provider/git"
22
+ require "chef/provider/subversion"
23
+
24
+ class Chef
25
+ class Provider
26
+ class Deploy < Chef::Provider
27
+
28
+ include Chef::Mixin::FromFile
29
+ include Chef::Mixin::Command
30
+
31
+ attr_reader :scm_provider, :release_path
32
+
33
+ def initialize(node, new_resource, collection=nil, definitions=nil, cookbook_loader=nil)
34
+ super(node, new_resource, collection, definitions, cookbook_loader)
35
+
36
+ # NOTE: workaround for CHEF-577
37
+ @definitions ||= Hash.new
38
+ @collection = Chef::ResourceCollection.new
39
+
40
+ @scm_provider = @new_resource.scm_provider.new(@node, @new_resource)
41
+
42
+ # @configuration is not used by Deploy, it is only for backwards compat with
43
+ # chef-deploy or capistrano hooks that might use it to get environment information
44
+ @configuration = @new_resource.to_hash
45
+ @configuration[:environment] = @configuration[:environment] && @configuration[:environment]["RAILS_ENV"]
46
+ end
47
+
48
+ def load_current_resource
49
+ @release_path = @new_resource.deploy_to + "/releases/#{release_slug}"
50
+ end
51
+
52
+ def sudo(command,&block)
53
+ execute(command, &block)
54
+ end
55
+
56
+ def run(command, &block)
57
+ exec = execute(command, &block)
58
+ exec.user(@new_resource.user)
59
+ exec
60
+ end
61
+
62
+ def action_deploy
63
+ if all_releases.include?(release_path)
64
+ Chef::Log.info("Already deployed app at #{release_path}, skipping. Use action :force_deploy to force.")
65
+ else
66
+ deploy
67
+ end
68
+ end
69
+
70
+ def action_force_deploy
71
+ if all_releases.include?(release_path)
72
+ Chef::Log.info("Already deployed app at #{release_path}, forcing.")
73
+ FileUtils.rm_rf(release_path)
74
+ end
75
+ deploy
76
+ end
77
+
78
+ def action_rollback
79
+ @release_path = all_releases[-2]
80
+ raise RuntimeError, "There is no release to rollback to!" unless @release_path
81
+ release_to_nuke = all_releases.last
82
+ Chef::Log.info "rolling back to previous release: #{release_path}"
83
+ symlink
84
+ Chef::Log.info "removing last release: #{release_to_nuke}"
85
+ FileUtils.rm_rf release_to_nuke
86
+ Chef::Log.info "restarting with previous release"
87
+ restart
88
+ end
89
+
90
+ def deploy
91
+ Chef::Log.info "deploying branch: #{@new_resource.branch}"
92
+ enforce_ownership
93
+ update_cached_repo
94
+ copy_cached_repo
95
+ install_gems
96
+ enforce_ownership
97
+ callback(:before_migrate, @new_resource.before_migrate)
98
+ migrate
99
+ callback(:before_symlink, @new_resource.before_symlink)
100
+ symlink
101
+ callback(:before_restart, @new_resource.before_restart)
102
+ restart
103
+ callback(:after_restart, @new_resource.after_restart)
104
+ cleanup!
105
+ end
106
+
107
+ def callback(what, callback_code=nil)
108
+ @collection = Chef::ResourceCollection.new
109
+ case callback_code
110
+ when Proc
111
+ Chef::Log.info "Running callback #{what} code block"
112
+ recipe_eval(&callback_code)
113
+ when String
114
+ callback_file = "#{release_path}/#{callback_code}"
115
+ unless ::File.exist?(callback_file)
116
+ raise RuntimeError, "Can't find your callback file #{callback_file}"
117
+ end
118
+ run_callback_from_file(callback_file)
119
+ when nil
120
+ run_callback_from_file("#{release_path}/deploy/#{what}.rb")
121
+ else
122
+ raise RuntimeError, "You gave me a callback I don't know what to do with: #{callback_code.inspect}"
123
+ end
124
+ end
125
+
126
+ def migrate
127
+ if @new_resource.migrate
128
+ enforce_ownership
129
+ link_shared_db_config_to_current_release
130
+
131
+ environment = @new_resource.environment
132
+ env_info = environment && environment.map do |key_and_val|
133
+ "#{key_and_val.first}='#{key_and_val.last}'"
134
+ end.join(" ")
135
+
136
+ Chef::Log.info "Migrating: running #{@new_resource.migration_command} as #{@new_resource.user} " +
137
+ "with environment #{env_info}"
138
+ run_command(run_options(:command => @new_resource.migration_command, :cwd=>release_path))
139
+ end
140
+ end
141
+
142
+ def symlink
143
+ Chef::Log.info "Symlinking"
144
+ purge_tempfiles_from_current_release
145
+ link_tempfiles_to_current_release
146
+ link_current_release_to_production
147
+ end
148
+
149
+ def restart
150
+ if restart_cmd = @new_resource.restart_command
151
+ if restart_cmd.kind_of?(Proc)
152
+ Chef::Log.info("Restarting app with embedded recipe")
153
+ recipe_eval(&restart_cmd)
154
+ else
155
+ Chef::Log.info("Restarting app with #{@new_resource.restart_command} in #{@new_resource.current_path}")
156
+ run_command(run_options(:command => @new_resource.restart_command, :cwd => @new_resource.current_path))
157
+ end
158
+ end
159
+ end
160
+
161
+ def cleanup!
162
+ all_releases[0..-6].each do |old_release|
163
+ Chef::Log.info "Removing old release #{old_release}"
164
+ FileUtils.rm_rf(old_release)
165
+ release_deleted(old_release)
166
+ end
167
+ end
168
+
169
+ def all_releases
170
+ Dir.glob(@new_resource.deploy_to + "/releases/*")
171
+ end
172
+
173
+ def update_cached_repo
174
+ Chef::Log.info "updating the cached checkout"
175
+ @scm_provider.action_sync
176
+ end
177
+
178
+ def copy_cached_repo
179
+ Chef::Log.info "copying the cached checkout to #{release_path}"
180
+ FileUtils.mkdir_p(@new_resource.deploy_to + "/releases")
181
+ FileUtils.cp_r("#{@new_resource.destination}.", release_path, :preserve => true)
182
+ release_created(release_path)
183
+ end
184
+
185
+ def enforce_ownership
186
+ Chef::Log.info "ensuring proper ownership"
187
+ FileUtils.chown_R(@new_resource.user, @new_resource.group, @new_resource.deploy_to)
188
+ end
189
+
190
+ def link_current_release_to_production
191
+ Chef::Log.info "Linking release #{release_path} into production at #{@new_resource.current_path}"
192
+ FileUtils.rm_f(@new_resource.current_path)
193
+ FileUtils.ln_sf(release_path, @new_resource.current_path)
194
+ enforce_ownership
195
+ end
196
+
197
+ def link_shared_db_config_to_current_release
198
+ links_info = @new_resource.symlink_before_migrate.map { |src, dst| "#{src} => #{dst}" }.join(", ")
199
+ Chef::Log.info "Making pre-migration symlinks: #{links_info}"
200
+ @new_resource.symlink_before_migrate.each do |src, dest|
201
+ FileUtils.ln_sf(@new_resource.shared_path + "/#{src}", release_path + "/#{dest}")
202
+ end
203
+ end
204
+
205
+ def link_tempfiles_to_current_release
206
+ dirs_info = @new_resource.create_dirs_before_symlink.join(",")
207
+ Chef::Log.info("creating directories before symlink: #{dirs_info}")
208
+ @new_resource.create_dirs_before_symlink.each { |dir| FileUtils.mkdir_p(release_path + "/#{dir}") }
209
+
210
+ links_info = @new_resource.symlinks.map { |src, dst| "#{src} => #{dst}" }.join(", ")
211
+ Chef::Log.info("Linking shared paths into current release: #{links_info}")
212
+ @new_resource.symlinks.each do |src, dest|
213
+ FileUtils.ln_sf(@new_resource.shared_path + "/#{src}", release_path + "/#{dest}")
214
+ end
215
+ link_shared_db_config_to_current_release
216
+ enforce_ownership
217
+ end
218
+
219
+ def create_dirs_before_symlink
220
+ end
221
+
222
+ def purge_tempfiles_from_current_release
223
+ log_info = @new_resource.purge_before_symlink.join(", ")
224
+ Chef::Log.info("Purging directories in checkout #{log_info}")
225
+ @new_resource.purge_before_symlink.each { |dir| FileUtils.rm_rf(release_path + "/#{dir}") }
226
+ end
227
+
228
+ protected
229
+
230
+ # Internal callback, called after copy_cached_repo.
231
+ # Override if you need to keep state externally.
232
+ def release_created(release_path)
233
+ end
234
+
235
+ # Internal callback, called during cleanup! for each old release removed.
236
+ # Override if you need to keep state externally.
237
+ def release_deleted(release_path)
238
+ end
239
+
240
+ def release_slug
241
+ raise Chef::Exceptions::Override, "You must override release_slug in #{self.to_s}"
242
+ end
243
+
244
+ def install_gems
245
+ gems_collection = Chef::ResourceCollection.new
246
+ gem_packages.each { |rbgem| gems_collection << rbgem }
247
+ Chef::Runner.new(@node, gems_collection).converge
248
+ end
249
+
250
+ def gem_packages
251
+ return [] unless ::File.exist?("#{release_path}/gems.yml")
252
+ gems = YAML.load(IO.read("#{release_path}/gems.yml"))
253
+
254
+ gems.map do |g|
255
+ r = Chef::Resource::GemPackage.new(g[:name], nil, node)
256
+ r.version g[:version]
257
+ r.action :install
258
+ r.source "http://gems.github.com"
259
+ r
260
+ end
261
+ end
262
+
263
+ def run_options(run_opts={})
264
+ run_opts[:user] = @new_resource.user if @new_resource.user
265
+ run_opts[:group] = @new_resource.group if @new_resource.group
266
+ run_opts[:environment] = @new_resource.environment if @new_resource.environment
267
+ run_opts
268
+ end
269
+
270
+ def run_callback_from_file(callback_file)
271
+ if ::File.exist?(callback_file)
272
+ Dir.chdir(release_path) do
273
+ Chef::Log.info "running deploy hook: #{callback_file}"
274
+ recipe_eval { from_file(callback_file) }
275
+ end
276
+ end
277
+ end
278
+
279
+ end
280
+ end
281
+ end