Idiomatic way to invoke chef-solo?

What is the idiomatic way to invoke chef-solo? Most sites do this:

chef-solo -c ~/solo.rb -j ~/node.json -r http://www.example.com/chef-solo.tar.gz

But that's long. There are a few shorter ways to do this that I can think of:

  1. A rake task (rake chef-solo).
  2. A small shell script (run-chef-solo).
  3. An alias (can override the name, like chef-solo).

What is the idiomatic way to do this? How are other chef users invoking chef?


By default, chef-solo reads its configuration from /etc/chef/solo.rb. The command-line parameters correspond to config values that can be set in this file. This is done using the mixlib-config library.

  option :config_file, 
    :short => "-c CONFIG",
    :long  => "--config CONFIG",
    :default => "/etc/chef/solo.rb",
    :description => "The configuration file to use"

  option :json_attribs,
    :short => "-j JSON_ATTRIBS",
    :long => "--json-attributes JSON_ATTRIBS",
    :description => "Load attributes from a JSON file or URL",
    :proc => nil

  option :recipe_url,
      :short => "-r RECIPE_URL",
      :long => "--recipe-url RECIPE_URL",
      :description => "Pull down a remote gzipped tarball of recipes and untar it to the cookbook ca
che.",
      :proc => nil

The 'option' is the config file value.

The actual config file, /etc/chef/solo.rb would look like:

file_cache_path "/tmp/chef-solo"
cookbook_path   "/tmp/chef-solo/cookbooks"
role_path       "/tmp/chef-solo/roles"
json_attribs    "/tmp/chef-solo/node.json"
recipe_url      "http://www.example.com/chef-solo.tar.gz"

Also note that the JSON file can be a remote URL, too.

json_attribs    "http://www.example.com/node.json"

You can use Ohai as a library within the config file as well, to detect the platform or other attributes to specify what JSON file to use.

require 'rubygems'
require 'ohai'
o = Ohai::System.new
o.all_plugins
file_cache_path "/tmp/chef-solo"
cookbook_path   "/tmp/chef-solo/cookbooks"
role_path       "/tmp/chef-solo/roles"
json_attribs    "/tmp/chef-solo/#{o[:platform]}.json"
recipe_url      "http://www.example.com/chef-solo.tar.gz"

And then you'd have "platform" specific JSON files, for example. Or you could use o[:hostname], o[:domain] or o[:fqdn] to use JSON files based on the hostname, domain or fqdn. But once you start having the scaffolding of servers to support this kind of dynamic configuration, you might look at running a Chef Server :-).


@jtimberman has already written a great answer. Here's my personal way of invoking chef-solo. This gets the basics working and you will probably need to add more attributes to /etc/chef/node.json and explore some of the options described in the other answer.

# cat > /etc/chef/solo.rb << EOF
cookbook_path    "/var/chef-solo/cookbooks"
json_attribs     "/etc/chef/node.json"
EOF

# cat > /etc/chef/node.json << EOF
{
  "run_list": ["recipe[foo]", "recipe[bar]"]
}
EOF

Either copy over your cookbooks into /var/chef-solo/cookbooks or tar.gz them up on a webserver and use the recipe_url parameter. Running chef-solo on the node is all that's required to invoke it.

If possible I try and keep everything in solo.rb as I quite like being able to run chef-solo without having to remember any extra arguments.