Using chef-shell
Writing cookbooks is hard. Being able to try out parts of a recipe interactively and using breakpoints really helps to understand how your recipes work.
Chef comes with chef-shell, which is essentially an interactive Ruby session with Chef. In chef-shell, you can create attributes, write recipes, and initialize Chef runs, among other things. Chef-shell allows you to evaluate parts of your recipes on the fly before uploading them to your Chef server and executeing complete cookbooks on your nodes.
How to do it...
Running chef-shell is straightforward.
- Start chef-shell in standalone mode:
mma@laptop:~/chef-repo $ chef-shell loading configuration: none (standalone chef-shell session) Session type: standalone Loading......done. This is the chef-shell. Chef Version: 11.18.0 http://www.chef.io/chef http://docs.chef.io/ run `help' for help, `exit' or ^D to quit. Ohai2u mma@laptop! chef >
- Switch to the attributes mode in chef-shell:
chef > attributes_mode
- Set an attribute value to be used inside the recipe later:
chef:attributes > set[:title] = "Chef Cookbook" => "Chef Cookbook"
chef:attributes > quit => :attributes chef >
- Switch to the recipe mode:
chef > recipe_mode
- Create a file resource inside a recipe, using the title attribute as content:
chef:recipe > file "/tmp/book.txt" do chef:recipe > content node.title chef:recipe ?> end => <file[/tmp/book.txt] @name: "/tmp/book.txt" @noop: nil @before: nil @params: {} @provider: Chef::Provider::File @allowed_actions: [:nothing, :create, :delete, :touch, :create_if_missing] @action: "create" @updated: false @updated_by_last_action: false @supports: {} @ignore_failure: false @retries: 0 @retry_delay: 2 @source_line: "(irb#1):1:in `irb_binding'" @elapsed_time: 0 @resource_name: :file @path: "/tmp/book.txt" @backup: 5 @diff: nil @cookbook_name: nil @recipe_name: nil @content: "Chef Cookbook"> chef:recipe >
- Initiate a Chef run to create the file with the given content:
chef:recipe > run_chef
[2014-12-12T22:26:42+01:00] INFO: Processing file[/tmp/book.txt] action create ((irb#1) line 1) ...TRUNCATED OUTPUT... => true
How it works...
Chef-shell starts an interactive Ruby Shell (IRB) session, which is enhanced with some Chef-specific features. It offers certain modes, such as attributes_mode
or recipe_mode
, which enable you to write commands like you would put them into attributes file or recipes.
Entering a resource command into the recipe context will create the given resource, but not run it yet. It's like Chef reading your recipe files and creating the resources but not yet running them. You can run all the resources you created within the recipe context using the run_chef
command. This will execute all the resources on your local box and physically change your system. To play around with temporary files, your local box might do, but if you're going to do more invasive stuff, such as installing or removing packages, installing services, and so on, you might want to use chef-shell from within a Vagrant VM.
There's more...
Not only can you run chef-shell in standalone mode but you can also in Chef client mode. If you run it in Chef client mode, it will load the complete run list of your node and you'll be able to tweak it inside the chef-shell. You start the Chef client mode by using the run it --client
parameter:
mma@laptop:~/chef-repo $ chef-shell --client
You can configure which Chef server to connect it to in a file called chef-shell.rb
, in the same way as you do in the client.rb
file on your local workstation.
You can use chef-shell to manage your Chef server, for example, listing all nodes:
chef > nodes.list [node[my_server]]
You can put breakpoints into your recipes. If it hits a breakpoint resource, chef-shell will stop the execution of the recipe and you'll be able to inspect the current state of your Chef run:
breakpoint "name" do action :break end
See also
- Read more about the chef-shell at https://docs.chef.io/chef_shell.html