Organise your site-cookbooks with Berkshelf and this trick
Berkshelf is a bundler-like dependency manager for Chef cookbooks. The approach it encourages is to treat your cookbooks as libraries or applications.
- Library cookbooks should be focused on a particular component, reusable and configurable.
- Application cookbooks should be stitching the library ones together to achieve specific business goals.
As much as Berkshelf advocates you to move Chef cookbooks to their own git repositories, a Chef Solo user is still very likely to end up with a few application cookbooks (or site-cookbooks if we follow Librarian terminology).
chef-repo
| Berksfile
|_ site-cookbooks
|_ my-wordpress
|_ my-rails
|_ my-sinatra
Unfortunately the way Berkshelf is designed is that it will ignore Berksfiles for application cookbooks, i.e. this layout won't work:
chef-repo
|_ site-cookbooks
|_ my-wordpress
| metadata.rb
| Berksfile
|_ my-rails
| metadata.rb
| Berksfile
|_ my-sinatra
metadata.rb
Berksfile
That is, even if you create a top-level Berksfile
like this:
site :opscode
metadata
cookbook 'my-wordpress', :path => './site-cookbooks/my-wordpress'
cookbook 'my-rails', :path => './site-cookbooks/my-rails'
cookbook 'my-sinatra', :path => './site-cookbooks/my-sinatra'
Only metadata.rb
dependencies of site-cookbook are going to be satisfied with Berkshelf.
Why? Because of a design decision. Which you can get around if you're using Chef Server for cookbooks storage, but that's a different story.
Fortunately, I found a compromise for my use case. This is the Berksfile
I've got in the root of my Chef Solo repo:
# vi:ft=ruby:
site :opscode
def dependencies(path)
berks = "#{path}/Berksfile.in"
instance_eval(File.read(berks)) if File.exists?(berks)
end
Dir.glob('./site-cookbooks/*').each do |path|
dependencies path
cookbook File.basename(path), :path => path
end
And this is the layout I have got:
chef-repo
| Berksfile
|_ site-cookbooks
|_ my-wordpress
| metadata.rb
| Berksfile.in
|_ my-rails
| metadata.rb
| Berksfile.in
|_ my-sinatra
metadata.rb
Berksfile.in
This way,
-
./site-cookbooks
get noticed by Berkshelf which means that theirmetadata.rb
dependencies are satisfied - Their specific
Berksfile.in
files will be evaluated so that all cookbook dependencies make it nicely into the mainBerksfile
(thanks god, it's Ruby).
Berksfile.in
files are like this:
cookbook 'nodejs', :github => 'locomote-cookbooks/nodejs-cookbook'
cookbook 'npm', :github => 'locomote-cookbooks/chef-npm'
cookbook 'forever', :github => 'trabian/chef-forever'
They look like normal Berksfiles
sans the site
and metadata
sections - seeing them will make Berkshelf complain. Fortunately, you don't need them anyway because of the Berksfile in the root.
Hopefully this saves you from some Berkshelf rage that I've been through. Also, we all have ambitions and different opinions, let's listen to each other and not be fanatical. Peace.
Written by Vasily Mikhaylichenko
Related protips
4 Responses
You are fucking awesome.
This is badass, thank you so much!
smart)
badass rock star tech!