capistrano_chef_solo 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []