roundsman 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 +18 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +22 -0
- data/README.md +236 -0
- data/Rakefile +18 -0
- data/lib/roundsman.rb +4 -0
- data/lib/roundsman/capistrano.rb +275 -0
- data/lib/roundsman/version.rb +3 -0
- data/roundsman.gemspec +20 -0
- data/test/ubuntu-lucid/Capfile +8 -0
- data/test/ubuntu-lucid/Rakefile +5 -0
- data/test/ubuntu-lucid/Vagrantfile +99 -0
- data/test/ubuntu-lucid/config/cookbooks/main/recipes/cold.rb +1 -0
- data/test/ubuntu-lucid/config/deploy.rb +20 -0
- data/test/ubuntu-lucid/test.sh +4 -0
- metadata +90 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.3@roundsman
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 iain
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
# Roundsman
|
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
|
+
The only thing you need is SSH access and a supported OS. At this time only
|
7
|
+
Ubuntu is supported.
|
8
|
+
|
9
|
+
## Introduction
|
10
|
+
|
11
|
+
You can skip this if you already know about Capistrano and Chef.
|
12
|
+
|
13
|
+
Installing servers can be tedious work. Keeping your configuration in sync can
|
14
|
+
be hard too. Chef is an excellent tool for managing this. It can provision your
|
15
|
+
server from scratch. It can also be run again and again to check and update
|
16
|
+
your configuration if needed.
|
17
|
+
|
18
|
+
Capistrano is an excellent tool for deployment. It can deploy your code on
|
19
|
+
multiple machines, with clever defaults, limited downtime and the ability to
|
20
|
+
quickly roll back your deployment if something has gone wrong.
|
21
|
+
|
22
|
+
Roundsman aims to integrate Capistrano and Chef. This means that with every
|
23
|
+
deploy, it can check and update your configuration if needed. Are you using a
|
24
|
+
new version of Ruby in your next release? It will automatically install when
|
25
|
+
you deploy! Adding a new machine to your cluster? No problem! Roundsman will go
|
26
|
+
from a bare bones Linux machine to a working server in minutes!
|
27
|
+
|
28
|
+
Before you can use Roundsman, you need to know how to use Capistrano and how to
|
29
|
+
write Chef recipes. Here are some resources you might want to check out:
|
30
|
+
|
31
|
+
* [Capistrano's homepage](http://capify.org)
|
32
|
+
* [Opscode, the company behind Chef](http://www.opscode.com)
|
33
|
+
* [The wiki page on Chef Solo](http://wiki.opscode.com/display/chef/Chef+Solo)
|
34
|
+
* [The wiki page on creating Chef recipes](http://wiki.opscode.com/display/chef/Resources)
|
35
|
+
* [Railscast on Chef Solo](http://railscasts.com/episodes/339-chef-solo-basics) (paid)
|
36
|
+
* [Railscast on Capistrano Tasks](http://railscasts.com/episodes/133-capistrano-tasks-revised)
|
37
|
+
* [Railscast on digging deeper into Capistrano](http://railscasts.com/episodes/337-capistrano-recipes) (paid)
|
38
|
+
|
39
|
+
Feeling comfortable you can tackle deploying your application with Capistrano
|
40
|
+
and Chef? Now you can use Roundsman to combine them.
|
41
|
+
|
42
|
+
## Installing
|
43
|
+
|
44
|
+
Roundsman runs on Ruby 1.8.7 and above.
|
45
|
+
|
46
|
+
If you're using Bundler, you can add Roundsman to your Gemfile:
|
47
|
+
|
48
|
+
``` ruby
|
49
|
+
# Gemfile
|
50
|
+
|
51
|
+
gem 'roundsman', :require => false
|
52
|
+
```
|
53
|
+
|
54
|
+
Run `bundle install` to get it.
|
55
|
+
|
56
|
+
If you're not using Bundler, you can install Roundsman by hand:
|
57
|
+
|
58
|
+
``` bash
|
59
|
+
$ gem install roundsman
|
60
|
+
```
|
61
|
+
|
62
|
+
And "capify" your project:
|
63
|
+
|
64
|
+
``` bash
|
65
|
+
$ capify .
|
66
|
+
```
|
67
|
+
|
68
|
+
Next, load Roundsman in `Capfile`
|
69
|
+
|
70
|
+
``` ruby
|
71
|
+
# Capfile
|
72
|
+
|
73
|
+
require 'roundsman/capistrano'
|
74
|
+
```
|
75
|
+
|
76
|
+
## Usage
|
77
|
+
|
78
|
+
By default, Roundsman assumes you put your Chef cookbooks inside
|
79
|
+
`config/cookbooks`. If you don't like this, see the
|
80
|
+
[Configuration](#Configuration) chapter. But here we're going to use that.
|
81
|
+
|
82
|
+
I'm also going to assume that you put all Capistano configuration inside
|
83
|
+
`config/deploy.rb`. When you have a lot of configuration or use the multistage
|
84
|
+
extension, you might want to place it elsewhere.
|
85
|
+
|
86
|
+
After configuring Capistrano and writing and downloading Chef recipes, you can
|
87
|
+
hook them up, with a Capistrano hook. Simply provide provide a run list. Let's
|
88
|
+
say you want to run the default recipe of your own cookbook, called `main`.
|
89
|
+
|
90
|
+
``` ruby
|
91
|
+
# config/deploy.rb
|
92
|
+
|
93
|
+
before "deploy:update_code" do
|
94
|
+
roundsman.run_list "recipe[main]"
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
I'm hooking it up before the `update_code` command, and not before `deploy` so
|
99
|
+
it will also run when running `cap deploy:migrations`.
|
100
|
+
|
101
|
+
Setting up a webserver usually requires that you have the code already there;
|
102
|
+
otherwise restarting nginx or Apache will fail, because it cannot find your
|
103
|
+
application yet. To remedy that you can make another recipe that will configure
|
104
|
+
your webserver and have it run after deploying your new code:
|
105
|
+
|
106
|
+
``` ruby
|
107
|
+
# config/deploy.rb
|
108
|
+
|
109
|
+
after "deploy:create_symlink" do
|
110
|
+
roundsman.run_list "recipe[main::webserver]"
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
If you want a recipe to only run on a specific role, you can do so like this:
|
115
|
+
|
116
|
+
``` ruby
|
117
|
+
# config/deploy.rb
|
118
|
+
|
119
|
+
namespace :install do
|
120
|
+
task :postgres, :roles => [:db] do
|
121
|
+
roundsman.run_list "recipe[main::postgres]"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
before "deploy:update_code", "install:postgres"
|
126
|
+
```
|
127
|
+
|
128
|
+
## Configuration
|
129
|
+
|
130
|
+
By default, Roundsman will make a lot of Capistrano's configuration available to chef.
|
131
|
+
|
132
|
+
So, you might have these settings:
|
133
|
+
|
134
|
+
``` ruby
|
135
|
+
# config/deploy.rb
|
136
|
+
|
137
|
+
set :application, "my-awesome-blog"
|
138
|
+
set :rails_env, "production"
|
139
|
+
set :deploy_to, "/var/www/#{application}-#{rails_env}"
|
140
|
+
set :user, "deployer"
|
141
|
+
```
|
142
|
+
|
143
|
+
Here's how you can use them inside your recipes:
|
144
|
+
|
145
|
+
``` ruby
|
146
|
+
# config/cookbooks/main/recipes/default.rb
|
147
|
+
|
148
|
+
directory File.join(node[:deploy_to], "uploads") do
|
149
|
+
owner node[:user]
|
150
|
+
owner node[:user]
|
151
|
+
recursive true
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
Every configuration option from Capistrano is available in Chef. If your using
|
156
|
+
the [passenger_apache2](https://github.com/opscode-cookbooks/passenger_apache2)
|
157
|
+
cookbook for example, you can set the attributes like this:
|
158
|
+
|
159
|
+
``` ruby
|
160
|
+
# config/deploy.rb
|
161
|
+
|
162
|
+
set :passenger, :version => "3.0.12", :max_pool_size => 4
|
163
|
+
```
|
164
|
+
|
165
|
+
There are also a set of configuration options for Roundsman itself. They all
|
166
|
+
have sensible defaults, but you can override them if needed. To read all the
|
167
|
+
default configuration:
|
168
|
+
|
169
|
+
``` bash
|
170
|
+
$ cap roundsman:configuration
|
171
|
+
```
|
172
|
+
|
173
|
+
|
174
|
+
You can also perform a lot of tasks by hand if you need to. Here's how to get
|
175
|
+
information:
|
176
|
+
|
177
|
+
``` bash
|
178
|
+
$ cap --tasks roundsman
|
179
|
+
```
|
180
|
+
|
181
|
+
To get more information, use the `--explain` flag and specify a task name, like
|
182
|
+
this:
|
183
|
+
|
184
|
+
``` bash
|
185
|
+
$ cap --explain roundsman:install_ruby
|
186
|
+
```
|
187
|
+
|
188
|
+
## How does it work?
|
189
|
+
|
190
|
+
What Roundsman does is this:
|
191
|
+
|
192
|
+
It will determine if you have the right version of Ruby installed. Your machine
|
193
|
+
might already have an older version of Ruby installed, so if it needs to, it
|
194
|
+
will use [ruby-build](https://github.com/sstephenson/ruby-build) to install the
|
195
|
+
version of Ruby you need for your application.
|
196
|
+
|
197
|
+
Then, it will install check the version of chef-solo and install or upgrade as
|
198
|
+
needed.
|
199
|
+
|
200
|
+
It will then copy over the cookbooks from your local machine to your deployment
|
201
|
+
machine. This means that you don't need to commit every change while your still
|
202
|
+
working on it.
|
203
|
+
|
204
|
+
It will create your node.json file based upon your Capistrano configuration and
|
205
|
+
run the recipes needed.
|
206
|
+
|
207
|
+
This is all done in Capistrano hooks, using Capistrano methods like `run`, so
|
208
|
+
you can determine when and how your recipes are run.
|
209
|
+
|
210
|
+
## Tips
|
211
|
+
|
212
|
+
### Colors
|
213
|
+
|
214
|
+
Capistrano and Chef both give a lot of output. Check out
|
215
|
+
[capistrano_colors](https://github.com/stjernstrom/capistrano_colors)
|
216
|
+
to colorize your output for better readability.
|
217
|
+
|
218
|
+
### Vagrant
|
219
|
+
|
220
|
+
If you want to test out your configuration locally, you should take a look at
|
221
|
+
[Vagrant](http://vagrantup.com). It makes managing a VirtualBox a breeze. You
|
222
|
+
can even create a stage just for Vagrant with the Capistrano multistage
|
223
|
+
extension.
|
224
|
+
|
225
|
+
## Contributing
|
226
|
+
|
227
|
+
If you want to help out, please! Create an issue or do a pull request and I
|
228
|
+
will take a look at it.
|
229
|
+
|
230
|
+
To get this project up and running, make sure you have VirtualBox, because we
|
231
|
+
use vagrant. Then all you need to do is:
|
232
|
+
|
233
|
+
``` bash
|
234
|
+
bundle install
|
235
|
+
rake
|
236
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
|
5
|
+
namespace :test do
|
6
|
+
|
7
|
+
desc "Run integration test for Ubuntu 10.04 LTE"
|
8
|
+
task :lucid do
|
9
|
+
result = system "cd test/ubuntu-lucid && ./test.sh"
|
10
|
+
exit 1 unless result
|
11
|
+
end
|
12
|
+
|
13
|
+
task :all => [ :lucid ]
|
14
|
+
|
15
|
+
end
|
16
|
+
task :test => "test:all"
|
17
|
+
|
18
|
+
task :default => :test
|
data/lib/roundsman.rb
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
::Capistrano::Configuration.instance(:must_exist).load do
|
5
|
+
|
6
|
+
namespace :roundsman do
|
7
|
+
|
8
|
+
def run_list(*recipes)
|
9
|
+
if recipes.any?
|
10
|
+
set :run_list, recipes
|
11
|
+
install_ruby
|
12
|
+
run_chef
|
13
|
+
else
|
14
|
+
Array(fetch(:run_list))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_default(name, *args, &block)
|
19
|
+
@_defaults ||= []
|
20
|
+
@_overridden_defaults ||= []
|
21
|
+
@_defaults << name
|
22
|
+
if exists?(name)
|
23
|
+
@_overridden_defaults << name
|
24
|
+
else
|
25
|
+
set(name, *args, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def roundsman_working_dir(*path)
|
30
|
+
ensure_roundsman_working_dir
|
31
|
+
File.join(fetch(:roundsman_working_dir), *path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def sudo(command, *args)
|
35
|
+
run "#{top.sudo} #{command}", *args
|
36
|
+
end
|
37
|
+
|
38
|
+
def run(*args)
|
39
|
+
if fetch(:stream_roundsman_output)
|
40
|
+
top.stream *args
|
41
|
+
else
|
42
|
+
top.run *args
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
set_default :roundsman_working_dir, "/tmp/roundsman"
|
47
|
+
set_default :stream_roundsman_output, true
|
48
|
+
|
49
|
+
desc "Lists configuration"
|
50
|
+
task :configuration do
|
51
|
+
@_defaults.sort.each do |name|
|
52
|
+
display_name = ":#{name},".ljust(30)
|
53
|
+
if variables[name].is_a?(Proc)
|
54
|
+
value = "<block>"
|
55
|
+
else
|
56
|
+
value = fetch(name).inspect
|
57
|
+
value = "#{value[0..40]}... (truncated)" if value.length > 40
|
58
|
+
end
|
59
|
+
overridden = @_overridden_defaults.include?(name) ? "(overridden)" : ""
|
60
|
+
puts "set #{display_name} #{value} #{overridden}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "Prepares the server for chef"
|
65
|
+
task :install_ruby do
|
66
|
+
install.default
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "Runs chef"
|
70
|
+
task :run_chef do
|
71
|
+
chef.default
|
72
|
+
end
|
73
|
+
|
74
|
+
def ensure_roundsman_working_dir
|
75
|
+
unless @ensured_roundsman_working_dir
|
76
|
+
run "mkdir -p #{fetch(:roundsman_working_dir)}"
|
77
|
+
sudo "chown -R #{user} #{fetch(:roundsman_working_dir)}"
|
78
|
+
@ensured_roundsman_working_dir = true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
namespace :install do
|
84
|
+
|
85
|
+
set_default :ruby_version, "1.9.3-p125"
|
86
|
+
set_default :care_about_ruby_version, true
|
87
|
+
set_default :ruby_install_dir, "/usr/local"
|
88
|
+
|
89
|
+
set_default :ruby_dependencies do
|
90
|
+
%w(git-core curl build-essential bison openssl
|
91
|
+
libreadline6 libreadline6-dev zlib1g zlib1g-dev libssl-dev
|
92
|
+
libyaml-dev libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev
|
93
|
+
vim wget tree)
|
94
|
+
end
|
95
|
+
|
96
|
+
set_default :ruby_install_script do
|
97
|
+
%Q{
|
98
|
+
set -e
|
99
|
+
cd #{roundsman_working_dir}
|
100
|
+
rm -rf ruby-build
|
101
|
+
git clone -q git://github.com/sstephenson/ruby-build.git
|
102
|
+
cd ruby-build
|
103
|
+
./install.sh
|
104
|
+
ruby-build #{fetch(:ruby_version)} #{fetch(:ruby_install_dir)}
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
task :default, :except => { :no_release => true } do
|
109
|
+
if install_ruby?
|
110
|
+
dependencies
|
111
|
+
ruby
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
desc "Installs ruby."
|
116
|
+
task :ruby, :except => { :no_release => true } do
|
117
|
+
put fetch(:ruby_install_script), roundsman_working_dir("install_ruby.sh"), :via => :scp
|
118
|
+
sudo "bash #{roundsman_working_dir("install_ruby.sh")}"
|
119
|
+
end
|
120
|
+
|
121
|
+
desc "Installs the dependencies needed for Ruby"
|
122
|
+
task :dependencies, :except => { :no_release => true } do
|
123
|
+
ensure_supported_distro
|
124
|
+
sudo "aptitude -yq update"
|
125
|
+
sudo "aptitude -yq install #{fetch(:ruby_dependencies).join(' ')}"
|
126
|
+
end
|
127
|
+
|
128
|
+
desc "Checks if the ruby version installed matches the version specified"
|
129
|
+
task :check_ruby_version do
|
130
|
+
abort if install_ruby?
|
131
|
+
end
|
132
|
+
|
133
|
+
def distribution
|
134
|
+
@distribution ||= capture("cat /etc/issue").strip
|
135
|
+
end
|
136
|
+
|
137
|
+
def ensure_supported_distro
|
138
|
+
unless @ensured_supported_distro
|
139
|
+
logger.info "Using Linux distribution #{distribution}"
|
140
|
+
abort "This distribution is not (yet) supported." unless distribution.include?("Ubuntu")
|
141
|
+
@ensured_supported_distro = true
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def install_ruby?
|
146
|
+
installed_version = capture("ruby --version || true").strip
|
147
|
+
if installed_version.include?("not found")
|
148
|
+
logger.info "No version of Ruby could be found."
|
149
|
+
return true
|
150
|
+
end
|
151
|
+
required_version = fetch(:ruby_version).gsub("-", "")
|
152
|
+
if installed_version.include?(required_version)
|
153
|
+
if fetch(:care_about_ruby_version)
|
154
|
+
logger.info "Ruby #{installed_version} matches the required version: #{required_version}."
|
155
|
+
return false
|
156
|
+
else
|
157
|
+
logger.info "Already installed Ruby #{installed_version}, not #{required_version}. Set :care_about_ruby_version if you want to fix this."
|
158
|
+
return false
|
159
|
+
end
|
160
|
+
else
|
161
|
+
logger.info "Ruby version mismatch. Installed version: #{installed_version}, required is #{required_version}"
|
162
|
+
return true
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
namespace :chef do
|
169
|
+
|
170
|
+
set_default :chef_version, "~> 0.10.8"
|
171
|
+
set_default :cookbooks_directory, ["config/cookbooks"]
|
172
|
+
set_default :copyfile_disable, false
|
173
|
+
|
174
|
+
task :default, :except => { :no_release => true } do
|
175
|
+
ensure_cookbooks_exists
|
176
|
+
prepare_chef
|
177
|
+
chef_solo
|
178
|
+
end
|
179
|
+
|
180
|
+
desc "Generates the config and copies over the cookbooks to the server"
|
181
|
+
task :prepare_chef, :except => { :no_release => true } do
|
182
|
+
install if install_chef?
|
183
|
+
ensure_cookbooks_exists
|
184
|
+
generate_config
|
185
|
+
generate_attributes
|
186
|
+
copy_cookbooks
|
187
|
+
end
|
188
|
+
|
189
|
+
desc "Installs chef"
|
190
|
+
task :install, :except => { :no_release => true } do
|
191
|
+
sudo "gem uninstall -xaI chef || true"
|
192
|
+
sudo "gem install chef -v #{fetch(:chef_version).inspect} --quiet --no-ri --no-rdoc"
|
193
|
+
sudo "gem install ruby-shadow --quiet --no-ri --no-rdoc"
|
194
|
+
end
|
195
|
+
|
196
|
+
desc "Runs the existing chef configuration"
|
197
|
+
task :chef_solo, :except => { :no_release => true } do
|
198
|
+
logger.info "Now running #{fetch(:run_list).join(', ')}"
|
199
|
+
sudo "chef-solo -c #{roundsman_working_dir("solo.rb")} -j #{roundsman_working_dir("solo.json")}"
|
200
|
+
end
|
201
|
+
|
202
|
+
def ensure_cookbooks_exists
|
203
|
+
abort "You must specify at least one recipe when running roundsman.chef" if fetch(:run_list, []).empty?
|
204
|
+
abort "No cookbooks found in #{fetch(:cookbooks_directory).inspect}" if cookbooks_paths.empty?
|
205
|
+
end
|
206
|
+
|
207
|
+
def cookbooks_paths
|
208
|
+
Array(fetch(:cookbooks_directory)).select { |path| File.exist?(path) }
|
209
|
+
end
|
210
|
+
|
211
|
+
def install_chef?
|
212
|
+
required_version = fetch(:chef_version).inspect
|
213
|
+
output = capture("gem list -i -v #{required_version} || true").strip
|
214
|
+
output == "false"
|
215
|
+
end
|
216
|
+
|
217
|
+
def generate_config
|
218
|
+
cookbook_string = cookbooks_paths.map { |c| "File.join(root, #{c.to_s.inspect})" }.join(', ')
|
219
|
+
solo_rb = <<-RUBY
|
220
|
+
root = File.expand_path(File.dirname(__FILE__))
|
221
|
+
file_cache_path File.join(root, "cache")
|
222
|
+
cookbook_path [ #{cookbook_string} ]
|
223
|
+
RUBY
|
224
|
+
put solo_rb, roundsman_working_dir("solo.rb"), :via => :scp
|
225
|
+
end
|
226
|
+
|
227
|
+
def generate_attributes
|
228
|
+
attrs = remove_procs_from_hash variables.dup
|
229
|
+
put attrs.to_json, roundsman_working_dir("solo.json"), :via => :scp
|
230
|
+
end
|
231
|
+
|
232
|
+
# Recursively removes procs from hashes. Procs can exist because you specified them like this:
|
233
|
+
#
|
234
|
+
# set(:root_password) { Capistrano::CLI.password_prompt("Root password: ") }
|
235
|
+
def remove_procs_from_hash(hash)
|
236
|
+
new_hash = {}
|
237
|
+
hash.each do |key, value|
|
238
|
+
real_value = if value.respond_to?(:call)
|
239
|
+
begin
|
240
|
+
value.call
|
241
|
+
rescue ::Capistrano::CommandError => e
|
242
|
+
logger.debug "Could not get the value of #{key}: #{e.message}"
|
243
|
+
nil
|
244
|
+
end
|
245
|
+
else
|
246
|
+
value
|
247
|
+
end
|
248
|
+
|
249
|
+
if real_value.is_a?(Hash)
|
250
|
+
real_value = remove_procs_from_hash(real_value)
|
251
|
+
end
|
252
|
+
unless real_value.class.to_s.include?("Capistrano") # skip capistrano tasks
|
253
|
+
new_hash[key] = real_value
|
254
|
+
end
|
255
|
+
end
|
256
|
+
new_hash
|
257
|
+
end
|
258
|
+
|
259
|
+
def copy_cookbooks
|
260
|
+
tar_file = Tempfile.new("cookbooks.tar")
|
261
|
+
begin
|
262
|
+
tar_file.close
|
263
|
+
env_vars = fetch(:copyfile_disable) && RUBY_PLATFORM.downcase.include?('darwin') ? "COPYFILE_DISABLE=true" : ""
|
264
|
+
system "#{env_vars} tar -cjf #{tar_file.path} #{cookbooks_paths.join(' ')}"
|
265
|
+
upload tar_file.path, roundsman_working_dir("cookbooks.tar"), :via => :scp
|
266
|
+
run "cd #{roundsman_working_dir} && tar -xjf cookbooks.tar"
|
267
|
+
ensure
|
268
|
+
tar_file.unlink
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
end
|
data/roundsman.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/roundsman/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["iain"]
|
6
|
+
gem.email = ["iain@iain.nl"]
|
7
|
+
gem.description = %q{Combine the awesome powers of Capistrano and Chef. The only thing you need is SSH access.}
|
8
|
+
gem.summary = %q{Various Capistrano tasks for bootstrapping servers with Chef}
|
9
|
+
gem.homepage = "https://github.com/iain/roundsman"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "roundsman"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Roundsman::VERSION
|
17
|
+
|
18
|
+
gem.add_runtime_dependency "capistrano", "~> 2.12"
|
19
|
+
gem.add_development_dependency "vagrant", "~> 1.0"
|
20
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant::Config.run do |config|
|
5
|
+
# All Vagrant configuration is done here. The most common configuration
|
6
|
+
# options are documented and commented below. For a complete reference,
|
7
|
+
# please see the online documentation at vagrantup.com.
|
8
|
+
|
9
|
+
# Every Vagrant virtual environment requires a box to build off of.
|
10
|
+
config.vm.box = "lucid32"
|
11
|
+
|
12
|
+
# The url from where the 'config.vm.box' box will be fetched if it
|
13
|
+
# doesn't already exist on the user's system.
|
14
|
+
config.vm.box_url = "http://files.vagrantup.com/lucid32.box"
|
15
|
+
|
16
|
+
# Boot with a GUI so you can see the screen. (Default is headless)
|
17
|
+
# config.vm.boot_mode = :gui
|
18
|
+
|
19
|
+
# Assign this VM to a host-only network IP, allowing you to access it
|
20
|
+
# via the IP. Host-only networks can talk to the host machine as well as
|
21
|
+
# any other machines on the same network, but cannot be accessed (through this
|
22
|
+
# network interface) by any external networks.
|
23
|
+
config.vm.network :hostonly, "192.168.33.10"
|
24
|
+
|
25
|
+
# Assign this VM to a bridged network, allowing you to connect directly to a
|
26
|
+
# network using the host's network device. This makes the VM appear as another
|
27
|
+
# physical device on your network.
|
28
|
+
# config.vm.network :bridged
|
29
|
+
|
30
|
+
# Forward a port from the guest to the host, which allows for outside
|
31
|
+
# computers to access the VM, whereas host only networking does not.
|
32
|
+
# config.vm.forward_port 80, 8080
|
33
|
+
|
34
|
+
# Share an additional folder to the guest VM. The first argument is
|
35
|
+
# an identifier, the second is the path on the guest to mount the
|
36
|
+
# folder, and the third is the path on the host to the actual folder.
|
37
|
+
# config.vm.share_folder "v-data", "/vagrant_data", "../data"
|
38
|
+
|
39
|
+
# Enable provisioning with Puppet stand alone. Puppet manifests
|
40
|
+
# are contained in a directory path relative to this Vagrantfile.
|
41
|
+
# You will need to create the manifests directory and a manifest in
|
42
|
+
# the file base.pp in the manifests_path directory.
|
43
|
+
#
|
44
|
+
# An example Puppet manifest to provision the message of the day:
|
45
|
+
#
|
46
|
+
# # group { "puppet":
|
47
|
+
# # ensure => "present",
|
48
|
+
# # }
|
49
|
+
# #
|
50
|
+
# # File { owner => 0, group => 0, mode => 0644 }
|
51
|
+
# #
|
52
|
+
# # file { '/etc/motd':
|
53
|
+
# # content => "Welcome to your Vagrant-built virtual machine!
|
54
|
+
# # Managed by Puppet.\n"
|
55
|
+
# # }
|
56
|
+
#
|
57
|
+
# config.vm.provision :puppet do |puppet|
|
58
|
+
# puppet.manifests_path = "manifests"
|
59
|
+
# puppet.manifest_file = "base.pp"
|
60
|
+
# end
|
61
|
+
|
62
|
+
# Enable provisioning with chef solo, specifying a cookbooks path, roles
|
63
|
+
# path, and data_bags path (all relative to this Vagrantfile), and adding
|
64
|
+
# some recipes and/or roles.
|
65
|
+
#
|
66
|
+
# config.vm.provision :chef_solo do |chef|
|
67
|
+
# chef.cookbooks_path = "../my-recipes/cookbooks"
|
68
|
+
# chef.roles_path = "../my-recipes/roles"
|
69
|
+
# chef.data_bags_path = "../my-recipes/data_bags"
|
70
|
+
# chef.add_recipe "mysql"
|
71
|
+
# chef.add_role "web"
|
72
|
+
#
|
73
|
+
# # You may also specify custom JSON attributes:
|
74
|
+
# chef.json = { :mysql_password => "foo" }
|
75
|
+
# end
|
76
|
+
|
77
|
+
# Enable provisioning with chef server, specifying the chef server URL,
|
78
|
+
# and the path to the validation key (relative to this Vagrantfile).
|
79
|
+
#
|
80
|
+
# The Opscode Platform uses HTTPS. Substitute your organization for
|
81
|
+
# ORGNAME in the URL and validation key.
|
82
|
+
#
|
83
|
+
# If you have your own Chef Server, use the appropriate URL, which may be
|
84
|
+
# HTTP instead of HTTPS depending on your configuration. Also change the
|
85
|
+
# validation key to validation.pem.
|
86
|
+
#
|
87
|
+
# config.vm.provision :chef_client do |chef|
|
88
|
+
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
|
89
|
+
# chef.validation_key_path = "ORGNAME-validator.pem"
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# If you're using the Opscode platform, your validator client is
|
93
|
+
# ORGNAME-validator, replacing ORGNAME with your organization name.
|
94
|
+
#
|
95
|
+
# IF you have your own Chef Server, the default validation client name is
|
96
|
+
# chef-validator, unless you changed the configuration.
|
97
|
+
#
|
98
|
+
# chef.validation_client_name = "ORGNAME-validator"
|
99
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
gem_package "bundler"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
set :application, "my-awesome-blog"
|
2
|
+
|
3
|
+
set :repository, "."
|
4
|
+
set :scm, :none # not recommended in production
|
5
|
+
set :deploy_via, :copy
|
6
|
+
|
7
|
+
server "192.168.33.10", :web, :app, :db, :primary => true
|
8
|
+
|
9
|
+
set :user, "vagrant"
|
10
|
+
set :password, "vagrant" # not recommended in production
|
11
|
+
|
12
|
+
set :deploy_to, "/home/#{user}/#{application}"
|
13
|
+
|
14
|
+
set :use_sudo, false
|
15
|
+
default_run_options[:pty] = true
|
16
|
+
|
17
|
+
before "deploy:cold" do
|
18
|
+
deploy.setup
|
19
|
+
roundsman.run_list "recipe[main::cold]"
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roundsman
|
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: 2012-04-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: capistrano
|
16
|
+
requirement: &70276376984320 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.12'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70276376984320
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: vagrant
|
27
|
+
requirement: &70276376983820 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70276376983820
|
36
|
+
description: Combine the awesome powers of Capistrano and Chef. The only thing you
|
37
|
+
need is SSH access.
|
38
|
+
email:
|
39
|
+
- iain@iain.nl
|
40
|
+
executables: []
|
41
|
+
extensions: []
|
42
|
+
extra_rdoc_files: []
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- .rvmrc
|
46
|
+
- Gemfile
|
47
|
+
- MIT-LICENSE
|
48
|
+
- README.md
|
49
|
+
- Rakefile
|
50
|
+
- lib/roundsman.rb
|
51
|
+
- lib/roundsman/capistrano.rb
|
52
|
+
- lib/roundsman/version.rb
|
53
|
+
- roundsman.gemspec
|
54
|
+
- test/ubuntu-lucid/Capfile
|
55
|
+
- test/ubuntu-lucid/Rakefile
|
56
|
+
- test/ubuntu-lucid/Vagrantfile
|
57
|
+
- test/ubuntu-lucid/config/cookbooks/main/recipes/cold.rb
|
58
|
+
- test/ubuntu-lucid/config/deploy.rb
|
59
|
+
- test/ubuntu-lucid/test.sh
|
60
|
+
homepage: https://github.com/iain/roundsman
|
61
|
+
licenses: []
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.8.15
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Various Capistrano tasks for bootstrapping servers with Chef
|
84
|
+
test_files:
|
85
|
+
- test/ubuntu-lucid/Capfile
|
86
|
+
- test/ubuntu-lucid/Rakefile
|
87
|
+
- test/ubuntu-lucid/Vagrantfile
|
88
|
+
- test/ubuntu-lucid/config/cookbooks/main/recipes/cold.rb
|
89
|
+
- test/ubuntu-lucid/config/deploy.rb
|
90
|
+
- test/ubuntu-lucid/test.sh
|