Capistrano Provisioning
Capistrano Provisioning is an extension to Capistrano that allows you to define clusters of servers and run provisioning tasks on them, such as installing users. It is a replacement for the fabric gem (http://rubygems.org/gems/fabric).
A word of caution
This software is in alpha - we're releasing early so we can start using this gem in anger.
Installation
With bundler
Add the following to your Gemfile:
gem 'capistrano-provisioning'
If your bundler environment isn't initialised yet, you'll need to add something like this to your deploy.rb/Capfile:
require 'rubygems'
require 'bundler'
Bundler.setup
require 'capistrano-provisioning/recipes'
Without bundler
gem install capistrano-provisioning
Either within your Capfile, or your deploy.rb, add:
require 'capistrano-provisioning/recipes'
Usage
Once you have required the gem, the cluster
command is available to you within capistrano recipes.
The simplest usage of this would be something like:
cluster :web, 'web1.example.com'
In fact, this is shorthand for the following:
cluster :web do
servers 'web1.example.com'
end
Both of these would add a cap task called 'web'; calling this will mean any task specified later in the chain will run on the 'web' cluster. Eg:
cap web invoke COMMAND='uptime'
Which will run the 'uptime' command on 'web1.example.com'.
You can specify multiple remote hosts like so:
cluster :web, 'web1.example.com', 'web2.example.com'
So... this far it's quite similar to cap's own 'role' syntax. After this, however, life gets interesting...
Chaining
If you want to run a task on multiple clusters, simply chain them as so:
cap web db invoke COMMAND='uptime'
... Assuming that you've defined a web and a db cluster!
This will also work with namespaced clusters.
Installing users
Specify the users that belong on a cluster as so:
cluster :web do
servers 'web1.example.com'
users 'bob', 'joe'
end
And put these users' public ssh keys in config/keys directory as so config/keys/bob.pub
and config/keys/joe.pub
Running:
cap web install_users
... will now create these users on the servers if they don't exist, and add the keys to their authorized_keys file.
You can specify groups as so:
cluster :web do
servers 'web1.example.com'
users 'bob', 'joe', :groups => ['some_group']
users 'rupert'
end
This will add Bob and Joe to some_group (:groups is an array, so add as many as you like), but won't add Rupert.
Bootstrapping
To specify a block of code that is to be run to 'bootstrap' a server, do this:
cluster :web do
servers 'web1.example.com'
bootstrap do
run 'some_command'
end
end
Run the following:
cap web run_bootstrap
And some_command
will be run on the servers.
Namespaces and default users
Namespaces work as you would expect:
namespace :system1 do
cluster :web do
# ...
end
cluster :db do
# ...
end
end
This block will create the following tasks:
cap system1:web
cap system1:db
As well as
cap system1:all
Which will load all of the clusters defined in system1
.
It is also possible to define a default group of users for a namespace:
namespace :system1 do
default_users 'bob', 'joe', :groups => ['some_group']
default_users 'rupert'
cluster :web do
# ...
end
cluster :db do
# ...
end
end
Which would mean that running:
cap system1:web install_users
... would add Bob, Joe and Rupert to the web cluster, with the appropriate groups.
To only install specific users, specify them in a hosts variable:
cap system1:web install_users USERS='bob'
This will only install bob - useful for if you're just adding one user and don't want to do a fullscale pass of all the keys. Note, though, that this user still needs to be defined within the recipe.
Inheriting default users
By default, namespaces do not inherit default users from the namespace above. If you want this inheritance, it's easy:
namespace :nested_namespace do
inherit_default_users
end
If you want those users to have an additional group within this namespace only, use the following:
namespace :nested_namespace do
inherit_default_users :additional_groups => 'additional_group'
end
You can also pass an array of additional groups:
namespace :nested_namespace do
inherit_default_users :additional_groups => ['additional_group_1', 'additional_group_2']
end
Inheriting specific default users
These groups of default users can also be named, so you can atomically specify inheritance:
namespace :system1 do
default_users 'bob', 'joe', :groups => ['some_group']
default_users 'rupert'
cluster :web do
# ...
end
cluster :db do
# ...
end
end
Clusters can also inherit these named groups:
namespace :system1 do
default_users :admins, 'bob', 'joe'
cluster :web do
user :admins
end
end
These can be mixed in with normal user names:
namespace :system1 do
default_users :admins, 'bob', 'joe'
cluster :web do
user :admins, 'sam'
end
end
Features we guess we're probably going to need
- Ability to output business-friendly documentation of how the clusters are set up (and what user access exists)
- A way to remove user accounts that don't belong
Note on Patches/Pull Requests
- Fork the project.
- Make your feature addition or bug fix.
- Add tests for it. This is important so I don't break it in a future version unintentionally.
- Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
- Send me a pull request. Bonus points for topic branches.
Copyright
Copyright (c) 2010 Sam Phillips. See LICENSE for details.