View Source

{section}
{column:width=70%}

Chef Solo allows you to run Chef [Cookbooks] in the absence of a [Chef Server]. To do this, the complete cookbook needs to be present on disk. This document will show you how to set up cookbooks and Chef Solo.

We're going to look at three of the options for {{chef-solo}}

{code}
-c, --config CONFIG
-j, --json-attributes JSON_ATTRIBS
-r, --recipe-url RECIPE_URL
{code}

And then we'll look at some examples of actually running {{chef-solo}}.

{column}
{column:width=30%}
{panel:title=Table of Contents}
{toc:minLevel=1|maxLevel=2}
{panel}
{column}
{section}

h1. Configure Chef Solo

The first option is {{\-c}} or {{\--config}}, which takes a filename as a configuration file. If this option is not specified, by default Chef Solo will look in {{/etc/chef/solo.rb}} for its configuration. This configuration file has two required variables: {{file_cache_path}} and {{cookbook_path}}. For example, in our instructions for [Chef Configuration Settings], we use the following {{~/solo.rb}}:

{code:ruby|linenos=false|title=~/solo.rb}
file_cache_path "/tmp/chef-solo"
cookbook_path "/tmp/chef-solo/cookbooks"
{code}

For your own systems, you can change this to reflect any directory you like, but you'll need to specify absolute paths and the {{cookbook_path}} directory should be a subdirectory of the {{file_cache_path}}.

h2. Multiple Cookbooks Directories

You can also specify {{cookbook_path}} as an array, passing multiple locations to search for cookbooks.
{code:ruby|linenos=false|title=~/solo.rb}
file_cache_path "/tmp/chef-solo"
cookbook_path ["/tmp/chef-solo/cookbooks", "/tmp/chef-solo/site-cookbooks"]
{code}

Note that the order is significant, and [changed in chef 0.8|Breaking Changes from 0.7.x to 0.8.x]; earlier entries are now overridden by later ones. When you create the cookbooks tarball below, you'll need both directories to extract into the {{file_cache_path}} directory.

h1. JSON, Attributes and Recipes

Since {{chef-solo}} doesn't have any interaction with a [Chef Server], you'll need to specify node-specifc [attributes|Attributes] in a JSON file. This can be located on the target system itself, or it can be stored on a remote server such as S3, or a web server on your network.

Within the JSON file, you'll also specify the recipes that Chef should run in the "run_list". An example JSON file, which sets a resolv.conf:

{code:javascript|linenos=false|title=~/node.json}
{
"resolver": {
"nameservers": [ "10.0.0.1" ],
"search":"int.example.com"
},
"run_list": [ "recipe[resolver]" ]
}
{code}

(See the [opscode/cookbook, resolver|http://github.com/opscode/cookbooks/tree/master/resolver])

h1. Preparing your [Cookbooks]

You can point {{chef-solo}} at a target directory on the local system, or at a URL containing a tarball archive.

h2. Running from a Directory

Now that you have {{chef-solo}} configured for a directory, you can store the cookbooks there directly and run {{chef-solo}} against that directory.

h2. Running from a URL

Running {{chef-solo}} against a URL containing a tarball is probably more common than running against a directory, however. First create the cookbooks tarball.

{code:bash|linenos=false|title=Creating a Chef Solo Tarball}
tar zcvf chef-solo.tar.gz ./cookbooks
{code}

Or if you're using multiple cookbook directories (make sure you've modified the cookbook_path variable in solo.rb to include both paths as described above):

{code:bash|linenos=false|title=Using Multiple Chef Cookbook Directories}
tar zcvf chef-solo.tar.gz ./cookbooks ./site-cookbooks
{code}

Then, upload the resulting {{chef-solo.tar.gz}} to a web server that is accessible by the servers you wish to run {{chef-solo}} on. We do this for the bootstrap tarball that [Configures Chef Server and Clients|Bootstrap Chef RubyGems Installation].

h1. Examples of Running {{chef-solo}}

Now that you have configured {{chef-solo}}, prepared JSON data for your system(s), and prepared your [Cookbooks], it's time to run it!

{code:bash|linenos=false|title=Running Solo with URL}
chef-solo -c ~/solo.rb -j ~/node.json -r http://www.example.com/chef-solo.tar.gz
{code}

This actually uses the Chef remote_file resource type to retrieve the specified {{chef-solo.tar.gz}} into the {{file_cache_path}}, and extracts it to {{cookbooks_path}}, then runs Chef with those cookbooks. So once this has occurred, you can modify the cookbooks on the local system and rerun Chef with the directory:

{code:bash|linenos=false|title=Running Solo with Directory}
chef-solo -c ~/solo.rb -j ~/node.json
{code}

Simply remove the '{{\-r URL}}', and the configuration file tells Solo where to look.

You can also specify the JSON data via URL.

{code:bash|linenos=false|title=Running Solo with URL for Cookbooks and JSON}
chef-solo -c ~/solo.rb -j http://www.example.com/node.json -r http://www.example.com/chef-solo.tar.gz
{code}

These two options, {{\-r}} and {{\-j}} correspond to the {{recipe_url}} and {{json_attribs}} config file options, respectively.

{code:ruby|title=solo.rb}
file_cache_path "/tmp/chef-solo"
cookbook_path "/tmp/chef-solo/cookbooks"
json_attribs "http://www.example.com/node.json"
recipe_url "http://www.example.com/chef-solo.tar.gz"
{code}

You can create the solo.rb in {{/etc/chef/solo.rb}} instead, as {{chef-solo}} will look there by default, thus making the '{{\-c ~/solo.rb}}' optional.

{tip:title=A Gentle Reminder}
Remember, Chef Solo is *totally disconnected from the chef server*. There is no authentication, no authorization, no search indexes, no persistent attributes. It's just the bare ability to execute [Cookbooks].
{tip}

h1. Roles

Chef Solo can also use Roles. They can be defined in the [JSON format|Roles#As JSON] or with the [Ruby DSL|Roles#The Ruby DSL], and you need to tell the solo config file where the roles live. Using the earlier example:

{code:ruby|linenos=false|title=~/solo.rb}
file_cache_path "/tmp/chef-solo"
cookbook_path "/tmp/chef-solo/cookbooks"
role_path "/tmp/chef-solo/roles"
{code}

The JSON file for the role would look something like:

{code:javascript|linenos=false|title=/tmp/chef-solo/roles/test.json}
{
"name": "test",
"default_attributes": { },
"override_attributes": { },
"json_class": "Chef::Role",
"description": "This is just a test role, no big deal.",
"chef_type": "role",
"run_list": [ "recipe[test]" ]
}
{code}

The above file using the Ruby DSL would look like:

{code:javascript|linenos=false|title=/tmp/chef-solo/roles/test.rb}
name 'test'
description 'This is just a test role, no big deal.'
run_list 'recipe[test]'
{code}

Finally, the JSON data passed to chef-solo:

{code:javascript|linenos=false|title=~/chef.json}
{ "run_list": "role[test]" }
{code}

See how to [set the run_list in JSON|Setting the run_list in JSON during run time].