capistrano_chef_solo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
7
+ environment_id="ruby-1.9.2-p290@capistrano_chef_solo"
8
+
9
+ #
10
+ # Uncomment following line if you want options to be set only for given project.
11
+ #
12
+ # PROJECT_JRUBY_OPTS=( --1.9 )
13
+
14
+ #
15
+ # First we attempt to load the desired environment directly from the environment
16
+ # file. This is very fast and efficient compared to running through the entire
17
+ # CLI and selector. If you want feedback on which environment was used then
18
+ # insert the word 'use' after --create as this triggers verbose mode.
19
+ #
20
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
21
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
22
+ then
23
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
24
+
25
+ if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
26
+ then
27
+ . "${rvm_path:-$HOME/.rvm}/hooks/after_use"
28
+ fi
29
+ else
30
+ # If the environment file has not yet been created, use the RVM CLI to select.
31
+ if ! rvm --create "$environment_id"
32
+ then
33
+ echo "Failed to create RVM environment '${environment_id}'."
34
+ exit 1
35
+ fi
36
+ fi
37
+
38
+ #
39
+ # If you use an RVM gemset file to install a list of gems (*.gems), you can have
40
+ # it be automatically loaded. Uncomment the following and adjust the filename if
41
+ # necessary.
42
+ #
43
+ # filename=".gems"
44
+ # if [[ -s "$filename" ]]
45
+ # then
46
+ # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
47
+ # fi
48
+
49
+ # If you use bundler, this might be useful to you:
50
+ # if command -v bundle && [[ -s Gemfile ]]
51
+ # then
52
+ # bundle
53
+ # fi
54
+
55
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in capistrano_chef_solo.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Capistrano Chef-solo
2
+
3
+ This is an attempt to combine the powers of [Capistrano](http://capify.org) and
4
+ [chef-solo](http://wiki.opscode.com/display/chef/Chef+Solo).
5
+
6
+ You can easily specify run lists:
7
+
8
+ before "deploy" do
9
+ chef.solo "recipe[foo]", "recipe[bar]"
10
+ end
11
+
12
+ And set some node attributes:
13
+
14
+ set :chef_attributes, :foo => { :bar => "baz" }
15
+
16
+ Cookbooks will be automatically be copied from `config/cookbooks` and `vendor/cookbooks`.
17
+
18
+ Then an empty VM can be installed, configured and deployed in one single command:
19
+
20
+ cap deploy
21
+
22
+ ## Installation
23
+
24
+ Add to your `Gemfile`:
25
+
26
+ gem 'capistrano_chef_solo', :require => false, :group => :development
27
+
28
+ And run `bundle install`.
29
+
30
+ Next, require me from your `Capfile`:
31
+
32
+ require 'capistrano_chef_solo'
33
+
34
+ ## Usage
35
+
36
+ Read the full documentation by typing:
37
+
38
+ cap --explain chef | less
39
+
40
+ ## Note
41
+
42
+ This gem is in very early stage of development and should be considered as just a spike at this
43
+ moment. Feel free to use it, and give me feedback on your experiences. But please, try it out on
44
+ a simple VM first.
45
+
46
+ ## Todo
47
+
48
+ * Support roles in both Capistrano and Chef.
49
+
50
+ ## Tips
51
+
52
+ ### Colors
53
+
54
+ Capistrano and chef both give a lot of output. It helps to install
55
+ [capistrano_colors](https://github.com/stjernstrom/capistrano_colors)
56
+
57
+ ### Vagrant
58
+
59
+ Using [Vagrant](http://vagrantup.com) is a good way for testing out chef recipes.
60
+
61
+ ---
62
+ Copyright Iain Hecker, 2011. Released under the MIT License.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "capistrano_chef_solo/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "capistrano_chef_solo"
7
+ s.version = CapistranoChefSolo::VERSION
8
+ s.authors = ["iain"]
9
+ s.email = ["iain@iain.nl"]
10
+ s.homepage = ""
11
+ s.summary = %q{Combining the awesome powers of Capistrano and chef-solo}
12
+ s.description = %q{This gem provides Capistrano tasks to run chef-solo with Capistrano, with hardly any configuration needed.}
13
+
14
+ s.rubyforge_project = "capistrano_chef_solo"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "capistrano", "~> 2.8.0"
24
+ end
@@ -0,0 +1,3 @@
1
+ module CapistranoChefSolo
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,335 @@
1
+ require "capistrano_chef_solo/version"
2
+ require 'json'
3
+ require 'tempfile'
4
+
5
+ Capistrano::Configuration.instance(:must_exist).load do
6
+
7
+ namespace :chef do
8
+
9
+ desc <<-DESC
10
+ Installs chef-solo and everything it needs if chef-solo hasn't been installed yet.
11
+
12
+ This does not run any chef recipes. You need to make your own tasks and hooks for that. \
13
+ This task will automatically run when running any chef recipes, \
14
+ so you normally won't need to run this task yourself anyway.
15
+
16
+ == Run lists
17
+
18
+ You'll need to tell capistrano which recipes to run and when. \
19
+ You can define a task for this:
20
+
21
+ task :run_recipes do
22
+ chef.solo "recipe[foo]", "recipe[bar]"
23
+ end
24
+
25
+ Or, preferrably, you can hook them up to your normal deployment proces:
26
+
27
+ before "deploy" do
28
+ chef.solo "recipe[foo]", "recipe[bar]"
29
+ end
30
+
31
+ Sometimes you need to split up your run list, because some chef recipes will fail \
32
+ if they are run at the wrong moment. \
33
+ For example, you need to install the database before deploying, \
34
+ because some of your gems won't compile if you don't have the proper header files. \
35
+ You probably want to run the apache recipe after you've completed normal deployment, \
36
+ because it would fail if there is no current/public directory available. \
37
+ So, for example, you can think in the lines of this setup:
38
+
39
+ before "deploy" do
40
+ chef.solo "recipe[myapp::mysql]"
41
+ end
42
+
43
+ after "deploy:symlink" do
44
+ chef.solo "recipe[myapp::apache2]"
45
+ end
46
+
47
+ You'll probably wind up creating your own cookbook, so it is wise to split it up into \
48
+ recipes that can run at the appropriate time.
49
+
50
+ == Cookbooks
51
+
52
+ Cookbooks are what power Chef. In order to use it, you must have some. \
53
+ By default, Capistrano will look in `config/cookbooks` and `vendor/cookbooks`. \
54
+ They will be copied over when you run them, so there is no need to commit and push \
55
+ changes in your cookbooks just to try them out. \
56
+ You don't need to specify individual cookbooks, but the directories containing them. \
57
+ To change the location of the cookbooks:
58
+
59
+ set :cookbooks, [ "vendor/cookbooks", "config/cookbooks" ]
60
+
61
+ == Node attributes
62
+
63
+ You can set node attributes by setting :chef_attributes to a hash. \
64
+ This will be converted to JSON and fed to chef-solo.
65
+
66
+ Example:
67
+
68
+ set :chef_attributes, :foo => { :bar => "baz" }
69
+
70
+ You can access these attributes from within your recipes:
71
+
72
+ node[:foo][:bar] # => bar
73
+
74
+ Some attributes will automatically be set with values from Capistrano:
75
+
76
+ {
77
+ :application => application,
78
+ :deploy_to => deploy_to,
79
+ :user => user,
80
+ :password => password,
81
+ :main_server => main_server,
82
+ :migrate_env => migrate_env,
83
+ :scm => scm,
84
+ :repository => repository,
85
+ :current_path => current_path,
86
+ :release_path => release_path,
87
+ :shared_path => shared_path
88
+ }
89
+
90
+ These values are only set if you didn't set themself in :chef_attributes. \
91
+ You can turn them off completely by setting :default_chef_attributes to false.
92
+
93
+ == Streaming
94
+
95
+ Some of the commands that are run are very long, so by default, their outputs \
96
+ are streamed to your console (i.e. not prefixed). If you don't want that:
97
+
98
+ set :chef_streaming, false
99
+
100
+ == Ruby
101
+
102
+ Ruby is a dependency of chef, so rather than installing ruby through a cookbook, \
103
+ Capistrano needs to install Ruby before being able to install and run Chef. \
104
+ The default Ruby is 1.9.2-p290 with some performance patches. \
105
+ To see how to configure this, run:
106
+
107
+ cap --explain chef:install:ruby | less
108
+
109
+
110
+ DESC
111
+ task :default, :except => { :no_release => true } do
112
+ unless installed?("chef-solo")
113
+ logger.info "Bootstrapping host to install chef-solo"
114
+ install
115
+ end
116
+ end
117
+
118
+ namespace :install do
119
+
120
+ desc <<-DESC
121
+ Install chef-solo, whether it has been installed or not.
122
+
123
+ This will do:
124
+
125
+ * Perform a dist-upgrade (chef:install:dist_upgrade)
126
+ * Install the dependencies for installing Ruby (chef:install:dependencies)
127
+ * Compile and install Ruby (chef:install:ruby)
128
+ * Install chef (chef:install:chef)
129
+
130
+ Be sure to check out the documentation of these tasks.
131
+ DESC
132
+ task :default, :except => { :no_release => true } do
133
+ dist_upgrade
134
+ dependencies
135
+ ruby unless installed?("ruby")
136
+ chef
137
+ end
138
+
139
+ desc "Performs a dist-upgrade on your system"
140
+ task :dist_upgrade, :except => { :no_release => true } do
141
+ stream_or_run "#{sudo} aptitude update"
142
+ stream_or_run "#{sudo} apt-get -o Dpkg::Options::=\"--force-confnew\" --force-yes -fuy dist-upgrade"
143
+ end
144
+
145
+ desc "Installs the dependencies to compile Ruby"
146
+ task :dependencies, :except => { :no_release => true } do
147
+ stream_or_run "#{sudo} aptitude install -y git-core curl build-essential bison openssl \
148
+ libreadline6 libreadline6-dev git-core zlib1g zlib1g-dev libssl-dev \
149
+ libyaml-dev libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev \
150
+ vim wget tree" # this line not really dependencies, but who can live without them?
151
+ end
152
+
153
+ desc <<-DESC
154
+ Compiles Ruby from source and applies 1.9.2 patches to speed it up.
155
+
156
+ This usually gives a lot of output, so most of the compiling output is saved \
157
+ to a file on the server. The path will appear in the output.
158
+
159
+ This is done globally, by hand, because Ubuntu ships with an old Ruby version, \
160
+ and using RVM with stuff like passenger has a bit too many caveats. \
161
+ If this is not your cup of tea, feel free to override this task completely. \
162
+ There are however a couple of configuration options to this method:
163
+
164
+ == Ruby version
165
+
166
+ It defaults to ruby-1.9.2-p290, but you can change it here.
167
+
168
+ set :ruby_version, "ruby-1.9.2-p189"
169
+
170
+ == The URL of the tarball
171
+
172
+ If the Ruby version is not 1.9.x, or, if it is not hosted on ruby-lang.org, \
173
+ you also need to set :ruby_url, to point to the url the tar-file can be downloaded. \
174
+ You don't need to set :ruby_url, if you're using Ruby 1.9.x.
175
+
176
+ set :ruby_url, "http://some-other-location.com/rubies/ruby.tar.gz"
177
+
178
+ == The directory to which it expands
179
+
180
+ If the tar to be downloaded does not extract a directory named after :ruby_version, \
181
+ you need to set :ruby_dir.
182
+
183
+ set :ruby_dir, "ruby-src-snapshot"
184
+
185
+ == Patches
186
+
187
+ Two performance patches will be applied by default. One is the optimized require patch, \
188
+ the other one is an implementation of REE's GC tuning. \
189
+ Both of these patches have been applied to 1.9.3. \
190
+ If your Ruby is 1.9.2, but you don't want the patches, set it to false.
191
+
192
+ set :apply_ruby_patches, false
193
+
194
+ If the Ruby version is not 1.9.2, the patches won't applied anyway. \
195
+ See more on GC tuning here:
196
+ http://www.rubyenterpriseedition.com/documentation.html#_garbage_collector_performance_tuning
197
+ DESC
198
+ task :ruby, :except => { :no_release => true } do
199
+ ruby_version = fetch :ruby_version, "ruby-1.9.2-p290"
200
+ ruby_url = fetch :ruby_url, "http://ftp.ruby-lang.org/pub/ruby/1.9/#{ruby_version}.tar.gz"
201
+ ruby_dir = fetch :ruby_dir, ruby_version
202
+ tar_name = File.basename(ruby_url)
203
+ on_rollback { run "rm /tmp/#{tar_name}" }
204
+ script = <<-BASH
205
+ set -e
206
+ cd /tmp
207
+
208
+ log=/tmp/install-ruby-`date +%s`.log
209
+ echo "=== Note: output is saved to $log"
210
+ touch $log
211
+
212
+ if [[ ! -f #{tar_name} ]]; then
213
+ echo "=== Downloading #{ruby_version} from #{ruby_url}"
214
+ curl -s -o #{tar_name} #{ruby_url}
215
+ else
216
+ echo "=== $(pwd)/#{tar_name} already present, using that one instead of downloading a new one"
217
+ fi
218
+
219
+ rm -rf #{ruby_dir}
220
+ tar -zxf #{tar_name}
221
+ cd #{ruby_dir}
222
+ BASH
223
+
224
+ if ruby_version =~ /^ruby-1.9.2/ && fetch(:apply_ruby_patches, true)
225
+ script << <<-BASH
226
+ echo "=== Applying Ruby patches"
227
+ curl -s -o ree_gc_tuning.diff https://raw.github.com/michaeledgar/ruby-patches/master/1.9/ree_gc_tuning/ree_gc_tuning.diff
228
+ curl -s -o by_xavier_shay.diff https://raw.github.com/michaeledgar/ruby-patches/master/1.9/optimized_require/by_xavier_shay.diff
229
+ patch -p 1 < ree_gc_tuning.diff >> $log
230
+ patch -p 1 < by_xavier_shay.diff >> $log
231
+ BASH
232
+ end
233
+
234
+ script << <<-BASH
235
+ echo "=== Configuring #{ruby_version}"
236
+ ./configure --disable-install-doc >> $log
237
+
238
+ echo "=== Compiling #{ruby_version}"
239
+ make >> $log 2>&1
240
+
241
+ echo "=== Installing #{ruby_version}"
242
+ #{sudo} make install >> $log
243
+ BASH
244
+ put script, "/tmp/install-ruby.sh", :via => :scp
245
+ run "bash /tmp/install-ruby.sh"
246
+ end
247
+
248
+ desc "Install the gems needed for chef-solo"
249
+ task :chef, :except => { :no_release => true } do
250
+ run "#{sudo} gem install chef ruby-shadow --no-ri --no-rdoc"
251
+ end
252
+
253
+ end
254
+
255
+ def solo(*run_list)
256
+ if run_list.empty?
257
+ abort "Please specify a run list, before('deploy') { chef.solo('recipe[foo]', 'recipe[bar]') }"
258
+ end
259
+ default
260
+ deploy.setup
261
+ run "mkdir -p /tmp/chef"
262
+ generate_config
263
+ generate_attributes(run_list)
264
+ copy_cookbooks
265
+ stream_or_run "#{sudo} chef-solo -c /tmp/chef/solo.rb -j /tmp/chef/solo.json"
266
+ end
267
+
268
+ def cookbooks
269
+ fetch :cookbooks do
270
+ [ "config/cookbooks", "vendor/cookbooks" ].select { |path| File.exist?(path) }
271
+ end
272
+ end
273
+
274
+ def generate_config
275
+ cookbook_paths = Array(cookbooks).map { |c| "File.join(root, #{c.to_s.inspect})" }.join(', ')
276
+ solo_rb = <<-RUBY
277
+ root = File.absolute_path(File.dirname(__FILE__))
278
+ file_cache_path File.join(root, "cache")
279
+ cookbook_path [ #{cookbook_paths} ]
280
+ RUBY
281
+ put solo_rb, "/tmp/chef/solo.rb", :via => :scp
282
+ end
283
+
284
+ def generate_attributes(run_list = [])
285
+ attrs = fetch(:chef_attributes, {})
286
+ if fetch(:default_chef_attributes, true)
287
+ attrs[:application] ||= fetch(:application, nil)
288
+ attrs[:deploy_to] ||= fetch(:deploy_to, nil)
289
+ attrs[:user] ||= fetch(:user, nil)
290
+ attrs[:password] ||= fetch(:password, nil)
291
+ attrs[:main_server] ||= fetch(:main_server, nil)
292
+ attrs[:migrate_env] ||= fetch(:migrate_env, nil)
293
+ attrs[:scm] ||= fetch(:scm, nil)
294
+ attrs[:repository] ||= fetch(:repository, nil)
295
+ attrs[:current_path] ||= current_path
296
+ attrs[:release_path] ||= release_path
297
+ attrs[:shared_path] ||= shared_path
298
+ end
299
+ attrs[:run_list] = run_list
300
+ put attrs.to_json, "/tmp/chef/solo.json", :via => :scp
301
+ end
302
+
303
+ def copy_cookbooks
304
+ tar_file = Tempfile.new("cookbooks.tar")
305
+ begin
306
+ tar_file.close
307
+ system "tar -cjf #{tar_file.path} #{Array(cookbooks).join(' ')}"
308
+ upload tar_file.path, "/tmp/chef/cookbooks.tar", :via => :scp
309
+ run "cd /tmp/chef && tar -xjf cookbooks.tar"
310
+ ensure
311
+ tar_file.unlink
312
+ end
313
+ end
314
+
315
+ def stream_or_run(*args)
316
+ if fetch(:chef_streaming, true)
317
+ stream *args
318
+ else
319
+ run *args
320
+ end
321
+ end
322
+
323
+ def installed?(cmd)
324
+ capture("which #{cmd}")
325
+ rescue Capistrano::CommandError
326
+ logger.info "#{cmd} has not been installed"
327
+ false
328
+ else
329
+ logger.info "#{cmd} has been installed"
330
+ true
331
+ end
332
+
333
+ end
334
+
335
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano_chef_solo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - iain
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-10 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: &2173516120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.8.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2173516120
25
+ description: This gem provides Capistrano tasks to run chef-solo with Capistrano,
26
+ with hardly any configuration needed.
27
+ email:
28
+ - iain@iain.nl
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - .gitignore
34
+ - .rvmrc
35
+ - Gemfile
36
+ - README.md
37
+ - Rakefile
38
+ - capistrano_chef_solo.gemspec
39
+ - lib/capistrano_chef_solo.rb
40
+ - lib/capistrano_chef_solo/version.rb
41
+ homepage: ''
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project: capistrano_chef_solo
61
+ rubygems_version: 1.8.6
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Combining the awesome powers of Capistrano and chef-solo
65
+ test_files: []