Chef Concept
Chef Concept
Chef Concept
Chef - Architecture
Chef works on a three-tier client server model wherein the working units such as
cookbooks are developed on the Chef workstation. From the command line utilities such
as knife, they are uploaded to the Chef server and all the nodes which are present in the
architecture are registered with the Chef server.
In order to get the working Chef infrastructure in place, we need to set up multiple things
in sequence.
In the above setup, we have the following components.
Chef Workstation
This is the location where all the configurations are developed. Chef workstation is
installed on the local machine. Detailed configuration structure is discussed in the later
chapters of this tutorial.
Chef Server
This works as a centralized working unit of Chef setup, where all the configuration files
are uploaded post development. There are different kinds of Chef server, some are
hosted Chef server whereas some are built-in premise.
Chef Nodes
They are the actual machines which are going to be managed by the Chef server. All the
nodes can have different kinds of setup as per requirement. Chef client is the key
component of all the nodes, which helps in setting up the communication between the
Chef server and Chef node. The other components of Chef node is Ohai, which helps in
getting the current state of any node at a given point of time.
Chef - Version Control System Setup
Using Version Control system is a fundamental part of infrastructure automation. There
are multiple kinds of version control system such as SVN, CVS, and GIT. Due to the
popularity of GIT among the Chef community, we will use the GIT setup.
Note − Don’t think of building an infrastructure as a code without a version control
system.
On Windows
Step 1 − Download the Windows installer from www.git-scm.org and follow the
installation steps.
Step 2 − Sign up for a central repository on GitHub.
Step 3 − Upload the ssh key to the GitHub account, so that one can interact with it easily.
For details on ssh key visit the following
link https://help.github.com/articles/generatingssh-keys.
Step 4− Finally create a repo on the github account by
visiting https://github.com/new with the name of chef-repo.
Before actually starting to write a cookbook, one can set up an initial GIT repository on
the development box and clone the empty repository provided by Opscode.
Step 1 − Download Opscode Chef repository empty structure.
$ wget https://github.com/opscode/chef-repo/tarball/master
Step 2 − Extract the tar ball.
$ tar –xvf master
Step 3 − Rename the directory.
$ mv opscode-chef-repo-2c42c6a/ chef-repo
Step 4 − Change the current working directory to chef repo.
$ cd chef-repo
Step 5 − Initialize a fresh get repo.
$ git init.
Step 6 − Connect to your repo on the git hub.
$ git remote add origin git@github.com:vipin022/chef-
Step 7 − Push the local repo to github.
$ git add.
$ git commit –m “empty repo structure added”
$ git push –u origin maste
By using the above procedure, you will get an empty chef repo in place. You can then
start working on developing the recipes and cookbooks. Once done, you can push the
changes to the GitHub.
In the above program, you need to update the <YOUR_ORG> name with the correct or
required organization name.
Step 3 − Next step after the configuration is, to get the vagrant box up. For this, you
need to move to the location where Vagrant box is located and run the following
command.
$ vagrant up
Step 4 − Once the machine is up, you can login to the machine using the following
command.
$ vagrant ssh
In the above command, vagrantfile is written in a Ruby Domain Specific Language (DSL)
for configuring the vagrant virtual machine.
In the vagrant file, we have the config object. Vagrant will use this config object to
configure the VM.
Vagrant.configure("2") do |config|
…….
End
Inside the config block, you will tell vagrant which VM image to use, in order to boot the
node.
config.vm.box = "opscode-ubuntu-12.04"
config.vm.box_url = https://opscode-vm-bento.s3.amazonaws.com/
vagrant/opscode_ubuntu-12.04_provisionerless.box
In the next step, you will tell Vagrant to download the omnibus plugin.
config.omnibus.chef_version = :latest
After selecting the VM box to boot, configure how to provision the box using Chef.
config.vm.provision :chef_client do |chef|
…..
End
Inside this, you need to set up instruction on how to hook up the virtual node to the Chef
server. You need to tell Vagrant where you need to store all the Chef stuff on the node.
chef.provisioning_path = "/etc/chef"
Chef - Test Kitchen Setup
Test Kitchen is Chef’s integrated testing framework. It enables writing test recipes, which
will run on the VMs once they are instantiated and converged using the cookbook. The
test recipes run on that VM and can verify if everything works as expected.
ChefSpec is something which only simulates a Chef run. Test kitchen boots up real node
and runs Chef on it.
Step 1 − Install test kitchen Ruby gem and test kitchen vagrant gem to enable test
kitchen to use vagrant for spinning up test.
$ gem install kitchen
$ gem install kitchen-vagrant
Step 2 − Set up test kitchen. This can be done by creating .kitchen.yml in the cookbook
directory.
driver_plugin: vagrant
driver_config:
require_chef_omnibus: true
platforms:
- name: ubuntu-12.04
driver_config:
box: opscode-ubuntu-12.04
box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_
ubuntu-12.04_provisionerless.box
suites:
- name: default
run_list:
- recipe[minitest-handler]
- recipe[my_cookbook_test]
attributes: { my_cookbook: { greeting: 'Ohai, Minitest!'} }
In the above code, one part defines that vagrant needs to spin up the VMs and it defines
that you want Omnibus to install Chef on the target node.
The second part defines which platform you want to test the cookbooks. Vagrant will
always create and destroy new instances. You do not have to fear about the side effects
with vagrant VMs you spin up using Vagrant file.
Test kitchen can be considered as a temporary environment that helps to run and test
cookbooks in a temporary environment that is similar to production. With test kitchen on,
one can make sure that the given piece of code is working, before it is actually getting
deployed on to testing, preproduction, and production environment. This feature of test
kitchen is followed by many organizations as a set before putting the cookbooks in an
actual working environment.
Test Kitchen Workflow
Following are the steps involved in Test Kitchen Workflow.
Creating a Cookbook Using Chef
Use the following code to create a cookbook.
$ chef generate cookbook motd_rhel
Installing Cookbook Gems:
Compiling Cookbooks...
Recipe: code_generator::cookbook
* directory[C:/chef/cookbooks/motd_rhel] action create
- create new directory C:/chef/cookbooks/motd_rhel
* template[C:/chef/cookbooks/motd_rhel/metadata.rb] action
create_if_missing
- create new file C:/chef/cookbooks/motd_rhel/metadata.rb
- update content in file
C:/chef/cookbooks/motd_rhel/metadata.rb from none to
d6fcc2 (diff output suppressed by config)
* template[C:/chef/cookbooks/motd_rhel/README.md] action
create_if_missing
- create new file C:/chef/cookbooks/motd_rhel/README.md
- update content in file
C:/chef/cookbooks/motd_rhel/README.md from none to 50deab
(diff output suppressed by config)
* cookbook_file[C:/chef/cookbooks/motd_rhel/chefignore] action
create
- create new file C:/chef/cookbooks/motd_rhel/chefignore
- update content in file
C:/chef/cookbooks/motd_rhel/chefignore from none to 15fac5
(diff output suppressed by config)
* cookbook_file[C:/chef/cookbooks/motd_rhel/Berksfile] action
create_if_missing
- create new file C:/chef/cookbooks/motd_rhel/Berksfile
- update content in file
C:/chef/cookbooks/motd_rhel/Berksfile from none to 9f08dc
(diff output suppressed by config)
* template[C:/chef/cookbooks/motd_rhel/.kitchen.yml] action
create_if_missing
- create new file C:/chef/cookbooks/motd_rhel/.kitchen.yml
- update content in file
C:/chef/cookbooks/motd_rhel/.kitchen.yml
from none to 49b92b (diff output suppressed by config)
*
directory[C:/chef/cookbooks/motd_rhel/test/integration/default/serv
erspec]
action create
- create new directory
C:/chef/cookbooks/motd_rhel/test/integration/default/serverspec
*
directory[C:/chef/cookbooks/motd_rhel/test/integration/helpers/serv
erspec]
action create
- create new directory
C:/chef/cookbooks/motd_rhel/test/integration/helpers/serverspec
* cookbook_file
[C:/chef/cookbooks/motd_rhel/test/integration/helpers/serverspec/sp
ec_helper.rb]
action create_if_missing
- create new file
C:/chef/cookbooks/motd_rhel/test/integration/helpers/serverspec/spe
c_helper.rb
- update content in file
C:/chef/cookbooks/motd_rhel/test/integration/helpers/serverspec/spe
c_helper.rb
from none to d85df4 (diff output suppressed by config)
* template
[C:/chef/cookbooks/motd_rhel/test/integration/default/serverspec/de
faul t_spec.rb]
action create_if_missing
- create new file
C:/chef/cookbooks/motd_rhel/test/integration/default/serverspec/def
ault_spec.rb
- update content in file
C:/chef/cookbooks/motd_rhel/test/integration/default/serverspec/def
ault_spec.rb
from none to 3fbdbd (diff output suppressed by config)
* directory[C:/chef/cookbooks/motd_rhel/spec/unit/recipes]
action create
- create new directory
C:/chef/cookbooks/motd_rhel/spec/unit/recipes
* cookbook_file
[C:/chef/cookbooks/motd_rhel/spec/spec_helper.rb] action
create_if_missing
- create new file
C:/chef/cookbooks/motd_rhel/spec/spec_helper.rb
- update content in file
C:/chef/cookbooks/motd_rhel/spec/spec_helper.rb from none
to 587075
(diff output suppressed by config)
* template
[C:/chef/cookbooks/motd_rhel/spec/unit/recipes/default_spec.rb]
action create_if_missing
- create new file
C:/chef/cookbooks/motd_rhel/spec/unit/recipes/default_spec.rb
- update content in file
C:/chef/cookbooks/motd_rhel/spec/unit/recipes/default_spec.rb
from none to ff3b17 (diff output suppressed by config)
* directory[C:/chef/cookbooks/motd_rhel/recipes] action create
- create new directory C:/chef/cookbooks/motd_rhel/recipes
* template[C:/chef/cookbooks/motd_rhel/recipes/default.rb]
action create_if_missing
- create new file
C:/chef/cookbooks/motd_rhel/recipes/default.rb
- update content in file
C:/chef/cookbooks/motd_rhel/recipes/default.rb from none
to c4b029
(diff output suppressed by config)
* cookbook_file[C:/chef/cookbooks/motd_rhel/.gitignore] action
create
- create new file C:/chef/cookbooks/motd_rhel/.gitignore
- update content in file
C:/chef/cookbooks/motd_rhel/.gitignore from none to 33d469
(diff output suppressed by config)
• Chef nodes
• Cookbook
• Recipe
• Environments
• Cloud Resources
• Cloud Provisioning
• Installation on Chef client on Chef nodes
Knife provides a set of commands to manage Chef infrastructure.
Bootstrap Commands
In the above code, we are using the hosted Chef server which uses the following two
keys.
validation_client_name 'ORG_NAME-validator'
validation_key "#{current_dir}/ORGANIZATION-
validator.pem"
Here, knife.rb tells knife which organization to use and where to find the private key. It
tells knife where to find the users’ private key.
client_key "#{current_dir}/USER.pem"
The following line of code tells knife we are using the hosted server.
chef_server_url 'https://api.chef.io/organizations/ORG_NAME'
Using the knife.rb file, the validator knife can now connect to your organization’s hosted
Opscode.
Step 4 − Get the ntp cookbook inside the chef repo using knife.
vipin@laptop:~/chef-repo $ knife cookbook site install ntp
Installing ntp to /Users/mma/work/chef-repo/cookbooks
…TRUNCATED OUTPUT…
Cookbook ntp version 1.3.0 successfully installed
Step 5 − Add the node.json file to Git.
$ git add node.json
Step 6 − Commit and push the files to git repo.
vipin@laptop:~/chef-repo $ git commit -m "initial setup for Chef
Solo"
vipin@laptop:~/chef-repo $ git push
Counting objects: 4, done.
Delta compression using up to 4 threads.
...TRUNCATED OUTPUT...
To git@github.com:mmarschall/chef-repo.git
b930647..5bcfab6 master -> master
Running the Cookbook on the Node
Step 1 − Login to the node where one wants to provision the Chef-Solo.
Step 2 − Clone the Chef repo on the machine.
$ git clone $URL_PATH
Step 3 − cd to the chef repo.
$ cd chef-repo
Finally, run the Chef-Solo to converge the node −
$ sudo chef-solo -c solo.rb -j node.json
[2017-20-08T22:54:13+01:00] INFO: *** Chef 11.0.0 ***
[2017-20-08T22:54:13+01:00] INFO: Setting the run_list to
["recipe[ntp]"] from JSON
...TRUNCATED OUTPUT...
[2012-12-08T22:54:16+01:00] INFO: Chef Run complete in 2.388374
seconds
[2012-12-08T22:54:16+01:00] INFO: Running report handlers
solo.rb configures Chef-Solo to look for its cookbooks, roles, and data bags inside the
current directory: the Chef repository.
Chef-Solo takes its node configuration from a JSON file. In our example, we called it
node.json. If you're going to manage multiple servers, you'll need a separate file for each
node. Then, Chef-Solo just executes a Chef run based on the configuration data found
in solo.rb and node.json.
Chef - Cookbooks
Cookbooks are fundamental working units of Chef, which consists of all the details
related to working units, having the capability to modify configuration and the state of
any system configured as a node on Chef infrastructure. Cookbooks can perform
multiple tasks. Cookbooks contain values about the desired state of node. This is
achieved in Chef by using the desired external libraries.
Key Components of a Cookbook
• Recipes
• Metadata
• Attributes
• Resources
• Templates
• Libraries
• Anything else that helps to create a system
Creating a Cookbook
There are two ways to dynamically create a cookbook.
Compiling Cookbooks...
Recipe: code_generator::cookbook
* directory[C:/Users/vipinkumarm/VTest] action create
- create new directory C:/Users/vipinkumarm/VTest
* template[C:/Users/vipinkumarm/VTest/metadata.rb] action
create_if_missing
- create new file C:/Users/vipinkumarm/VTest/metadata.rb
- update content in file
C:/Users/vipinkumarm/VTest/metadata.rb
from none to 4b9435 (diff output suppressed by config)
* template[C:/Users/vipinkumarm/VTest/README.md] action
create_if_missing
- create new file C:/Users/vipinkumarm/VTest/README.md
- update content in file C:/Users/vipinkumarm/VTest/README.md
from none to 482077 (diff output suppressed by config)
* cookbook_file[C:/Users/vipinkumarm/VTest/chefignore] action
create
- create new file C:/Users/vipinkumarm/VTest/chefignore
- update content in file
C:/Users/vipinkumarm/VTest/chefignore
from none to 15fac5 (diff output suppressed by config)
* cookbook_file[C:/Users/vipinkumarm/VTest/Berksfile] action
create_if_missing
- create new file C:/Users/vipinkumarm/VTest/Berksfile
- update content in file C:/Users/vipinkumarm/VTest/Berksfile
from none to 9f08dc (diff output suppressed by config)
* template[C:/Users/vipinkumarm/VTest/.kitchen.yml] action
create_if_missing
- create new file C:/Users/vipinkumarm/VTest/.kitchen.yml
- update content in file
C:/Users/vipinkumarm/VTest/.kitchen.yml
from none to 93c5bd (diff output suppressed by config)
*
directory[C:/Users/vipinkumarm/VTest/test/integration/default/serve
rspec]
action create
- create new directory
C:/Users/vipinkumarm/VTest/test/integration/default/serverspec
*
directory[C:/Users/vipinkumarm/VTest/test/integration/helpers/serve
rspec]
action create
- create new directory
C:/Users/vipinkumarm/VTest/test/integration/helpers/serverspec
* cookbook_file
[C:/Users/vipinkumarm/VTest/test/integration/helpers/serverspec/sp
ec_helper.rb]
action create_if_missing
- create new file
C:/Users/vipinkumarm/VTest/test/integration/helpers/serverspec/spec
_helper.rb
- update content in file
C:/Users/vipinkumarm/VTest/test/integration/helpers/serverspec/spec
_helper.rb
from none to d85df4 (diff output suppressed by config)
* template
[C:/Users/vipinkumarm/VTest/test/integration/default/serverspec/def
ault _spec.rb]
action create_if_missing
- create new file
C:/Users/vipinkumarm/VTest/test/integration/default/serverspec/defa
ult_spec.rb
- update content in file
C:/Users/vipinkumarm/VTest/test/integration/default/serverspec/defa
ult_spec.rb
from none to 758b94 (diff output suppressed by config)
* directory[C:/Users/vipinkumarm/VTest/spec/unit/recipes] action
create
- create new directory
C:/Users/vipinkumarm/VTest/spec/unit/recipes
* cookbook_file[C:/Users/vipinkumarm/VTest/spec/spec_helper.rb]
action create_if_missing
- create new file
C:/Users/vipinkumarm/VTest/spec/spec_helper.rb
- update content in file
C:/Users/vipinkumarm/VTest/spec/spec_helper.rb
from none to 587075 (diff output suppressed by config)
*
template[C:/Users/vipinkumarm/VTest/spec/unit/recipes/default_spec.
rb]
action create_if_missing
- create new file
C:/Users/vipinkumarm/VTest/spec/unit/recipes/default_spec.rb
- update content in file
C:/Users/vipinkumarm/VTest/spec/unit/recipes/default_spec.rb
from none to 779503 (diff output suppressed by config)
- create new file
C:/Users/vipinkumarm/VTest/recipes/default.rb
- update content in file
C:/Users/vipinkumarm/VTest/recipes/default.rb
from none to 8cc381 (diff output suppressed by config)
* cookbook_file[C:/Users/vipinkumarm/VTest/.gitignore] action
create
- create new file C:/Users/vipinkumarm/VTest/.gitignore
- update content in file
C:/Users/vipinkumarm/VTest/.gitignore from none to 33d469
(diff output suppressed by config)
The cookbook structure with the name VTest will be created in the directory and following
will be the structure for the same.
Using Knife Utility
Use the following command to create a cookbook using knife utility.
C:\Users\vipinkumarm\VTest>knife cookbook create VTest2
WARNING: No knife configuration file found
** Creating cookbook VTest2 in C:/chef/cookbooks
** Creating README for cookbook: VTest2
** Creating CHANGELOG for cookbook: VTest2
** Creating metadata for cookbook: VTest2
Following will be the structure of the cookbook.
Chef - Cookbook Dependencies
The features of defining cookbook dependencies help in managing cookbook. This
feature is used when we want to use the functionality of one cookbook in other
cookbooks.
For example, if one wants to compile C code then one needs to make sure that all the
dependencies required to compile are installed. In order to do so, there might be
separate cookbook which can perform such a function.
When we are using chef-server, we need to know such dependencies in cookbooks
which should be decelerated in the cookbooks metadata file. This file is located at the
top on the cookbook directory structure. It provides hints to the Chef server which helps
in deploying cookbooks on the correct node.
Features of metadata.rb File
• Located at the top in the cookbook directory structure.
• Compiled when the cookbook is uploaded to Chef server using knife command.
• Compiled with knife cookbook metadata subcommand.
• Created automatically when the knife cookbook create command is run.
Configuration of metadata.rb
Following is the default content of a metadata file.
Chef - Roles
Roles in Chef are a logical way of grouping nodes. Typical cases are to have roles for
web servers, database servers, and so on. One can set custom run list for all the nodes
and override attribute value within roles.
Create a Role
vipin@laptop:~/chef-repo $ subl roles/web_servers.rb
name "web_servers"
description "This role contains nodes, which act as web servers"
run_list "recipe[ntp]"
default_attributes 'ntp' => {
'ntpdate' => {
'disable' => true
}
}
Once we have the role created, we need to upload to the Chef server.
Upload Role to Chef Server
vipin@laptop:~/chef-repo $ knife role from file web_servers.rb
Now, we need to assign a role to a node called server.
Assign a Role to Node
vipin@laptop:~/chef-repo $ knife node edit server
"run_list": [
"role[web_servers]"
]
Saving updated run_list on node server
Run the Chef-Client
user@server:~$ sudo chef-client
...TRUNCATED OUTPUT...
[2013-07-25T13:28:24+00:00] INFO: Run List is [role[web_servers]]
[2013-07-25T13:28:24+00:00] INFO: Run List expands to [ntp]
...TRUNCATED OUTPUT...
How It Works
• Define a role in a Ruby file inside the roles folder of Chef repository.
• A role consists of a name and a description attribute.
• A role consists of role-specific run list and role-specific attribute settings.
• Every node that has a role in its run list will have the role’s run list exacted into its
own.
• All the recipes in the role’s run list will be executed on the node.
• The role will be uploaded to Chef server using the knife role from file command.
• The role will be added to the node run list.
• Running Chef client on a node having the role in its run list will execute all the
recipes listed in the role.
Chef - Environment
Chef helps in performing environment specific configuration. It is always a good idea to
have a separate environment for development, testing, and production.
Chef enables grouping nodes into separate environments to support an ordered
development flow.
Creating an Environment
Creation of environment on the fly can be done using the knife utility. Following command
will open a Shell’s default editor, so that one can modify the environment definition.
vipin@laptop:~/chef-repo $ knife environment create book {
"name": "book",
"description": "",
"cookbook_versions": {
},
"json_class": "Chef::Environment",
"chef_type": "environment",
"default_attributes": {
},
"override_attributes": {
}
}
Created book
Testing a Created Environment
vipin@laptop:~/chef-repo $ knife environment list
_default
book
List Node for All Environments
vipin@laptop:~/chef-repo $ knife node list
my_server
_default Environment
Each organization will always start with at least a single environment called default
environment, which is always available to the Chef server. A default environment cannot
be modified in anyway. Any kind of changes can only be accommodated in the custom
environment that we create.
Environment Attributes
An attribute can be defined in an environment and then used to override the default
settings in the node. When the Chef client run takes place, then these attributes are
compared with the default attributes that are already present in the node. When the
environment attributes take precedence over the default attributes, Chef client will apply
these settings and values when the Chef client run takes place on each node.
An environment attribute can only be either default_attribute or override_attribute. It
cannot be a normal attribute. One can use default_attribute or override_attribute
methods.
Attribute Type
Default − A default attribute is always reset at the start of every Chef client run and have
the lowest attribute precedence.
Override − An override attribute is always reset at the start of every Chef client run and
has a higher attribute precedence than default, force_default and normal. An override
attribute is most often defined in the recipe but can also be specified in an attribute file
for a role or for an environment.
Order of Applying an Attribute
Chef - Chef-Shell
Writing Chef cookbooks is always hard. It makes it even harder because of long
feedback cycle of uploading them to the Chef server, provisioning a vagrant VM,
checking how they failed there, rinsing and repeating. It would be easier if we could try
to test some pieces or recipes before we do all this heavy lifting at once.
Chef comes with Chef-Shell, which is essentially an interactive Ruby session with Chef.
In the Chef-Shell, we can create −
• Attributes
• Write Recipes
• Initializing Chef runs
It is used to evaluate parts of recipes on the fly, before uploading them to Chef server
and execute complete cookbooks on the node.
Running Shell
Step 1 − Run Chef-Shell in a standalone mode.
mma@laptop:~/chef-repo $ chef-shell
loading configuration: none (standalone chef-shell session)
Session type: standalone
Loading...[2017-01-12T20:48:01+01:00] INFO: Run List is []
[2017-01-12T20:48:01+01:00] INFO: Run List expands to []
done.
This is chef-shell, the Chef Shell.
Chef Version: 11.0.0
http://www.opscode.com/chef
http://wiki.opscode.com/display/chef/Home
run `help' for help, `exit' or ^D to quit.
Ohai2u mma@laptop!
chef >
Step 2 − Switch to attribute mode in the Chef-Shell
• chef > attributes_mode
Step 3 − Setting attribute value.
• chef:attributes > set[:title] = "Chef Cookbook"
o "Chef Cookbook"
• chef:attributes > quit
o :attributes
• chef >
Step 4 − Switch to recipe mode.
• chef > recipe_mode
Step 5 − Create a file resource.
chef:recipe > file "/tmp/book.txt" do
chef:recipe > content node.title
chef:recipe ?> end
chef:recipe >
Step 6 − Commence Chef run to create the file with the given content.
• chef:recipe > run_chef
[2017-01-12T21:07:49+01:00] INFO: Processing file[/tmp/book.txt]
action create ((irb#1) line 1)
---
/var/folders/1r/_35fx24d0y5g08qs131c33nw0000gn/T/cheftempfile201212
12-
11348-dwp1zs 2012-12-12 21:07:49.000000000
+0100
+++
/var/folders/1r/_35fx24d0y5g08qs131c33nw0000gn/T/chefdiff20121212-
11348-hdzcp1 2012-12-12 21:07:49.000000000 +0100
@@ -0,0 +1 @@
+Chef Cookbook
\ No newline at end of file
[2017-01-12T21:07:49+01:00] INFO: entered create
[2017-01-12T21:07:49+01:00] INFO: file[/tmp/book.txt] created file
/tmp/book.txt
How it Works
• Chef-Shell starts with an Interactive Ruby (IRB) session enhanced with some
specific features.
• It offers modes such as attributes_mode and interactive_mode.
• It helps in writing commands, which are written inside a recipe or cookbook.
• It runs everything in an interactive mode.
We can run Chef-Shell in three different modes: Standalone mode, Client mode,
and Solo mode.
• Standalone mode − It is the default mode. No cookbooks are loaded, and the
run-list is empty.
• Client mode − Here, the chef-shell acts as a chef-client.
• Solo mode − Here, the chef-shell acts as a chef-solo client.
Chef - Foodcritic
Writing good cookbooks without any issue is quite a difficult task. But there are ways
which can help in identifying the pitfalls. Flagging in Chef Cookbook is possible.
Foodcritic is one of the best way of archiving it, which tries to identify possible issues
with the logic and style of cookbooks.
Foodcritic Setup
Step 1 − Add Foodcritic gem.
vipin@laptop:~/chef-repo $ subl Gemfile
source 'https://rubygems.org'
gem 'foodcritic', '~>2.2.0'
Step 2 − Install the gem.
vipin@laptop:~/chef-repo $ bundle install
Fetching gem metadata from https://rubygems.org/
...TRUNCATED OUTPUT...
Installing foodcritic (2.2.0)
Foodcritic Gem
Step 1 − Run Foodcritic on the cookbook.
vipin@laptop:~/chef-repo $ foodcritic ./cookbooks/<Cookbook Name>
FC002: Avoid string interpolation where not required: ./cookbooks/
mysql/attributes/server.rb:220
...TRUNCATED OUTPUT...
FC024: Consider adding platform equivalents: ./cookbooks/<Cookbook
Name>/
recipes/server.rb:132
Step 2 − Generate a detailed report.
vipin@laptop:~/chef-repo $ foodcritic -C ./cookbooks/mysql
cookbooks/<cookbook Name>/attributes/server.rb
FC002: Avoid string interpolation where not required
[...]
85| default['<Cookbook Name>']['conf_dir'] = "#{mysql['basedir']}"
[...]
cookbooks/<Cookbook Name>/recipes/client.rb
FC007: Ensure recipe dependencies are reflected in cookbook
metadata
40| end
41|when "mac_os_x"
42| include_recipe 'homebrew'
43|end
44|
Working Method
Foodcritic defines a set of rules and checks recipe agents, each one of them. It comes
with multiple rules concerning various areas: styles, connectedness, attributes, string,
probability, search, services, files, metadata, and so on.
Chef - ChefSpec
Test Driven Development (TDD) is a way to write unit test before writing any actual
recipe code. The test should be real and should validate what a recipe does. It should
actually fail as there was no recipe developed. Once the recipe is developed, the test
should pass.
ChefSpec is built on the popular RSpec framework and offers a tailored syntax for testing
Chef recipe.
Creating ChefSpec
Step 1 − Create a gem file containing the chefSpec gem.
vipin@laptop:~/chef-repo $ subl Gemfile
source 'https://rubygems.org'
gem 'chefspec'
Step 2 − Install the gem.
vipin@laptop:~/chef-repo $ bundler install
Fetching gem metadata from https://rubygems.org/
...TRUNCATED OUTPUT...
Installing chefspec (1.3.1)
Using bundler (1.3.5)
Your bundle is complete!
Step 3 − Create a spec directory.
vipin@laptop:~/chef-repo $ mkdir cookbooks/<Cookbook Name>/spec
Step 4 − Create a Spec
vipin@laptop:~/chef-repo $ subl
cookbooks/my_cookbook/spec/default_spec.rb
require 'chefspec'
describe 'my_cookbook::default' do
let(:chef_run) {
ChefSpec::ChefRunner.new(
platform:'ubuntu', version:'12.04'
).converge(described_recipe)
}
Failed examples:
rspec ./cookbooks/my_cookbook/spec/default_spec.rb:10 # my_
cookbook::default creates a greetings file, containing the
platform name
Step 6 − Edit Cookbooks default recipe.
vipin@laptop:~/chef-repo $ subl cookbooks/<Cookbook
Name>/recipes/default.rb
template '/tmp/greeting.txt' do
variables greeting: 'Hello!'
end
vipin@laptop:~/chef-repo/cookbooks/my_cookbook $ subl
test/cookbooks/my_cookbook_test/files/default/tests/minitest/defaul
t_test.rb
require 'minitest/spec'
describe_recipe 'my_cookbook::default' do
describe "greeting file" do
it "creates the greeting file" do
file("/tmp/greeting.txt").must_exist
end
Install multiple Ruby gems using an array, a loop, and string expansion to construct the
gem names.
chef > %w{ec2 essentials}.each do |gem|
chef > gem_package "knife-#{gem}"
chef ?> end => ["ec2", "essentials"]
Working Method
Chef recipes are Ruby files, which gets evaluated in the context of Chef run. They can
contain plain Ruby code such as if statement and loops as well as Chef DSL elements
such as resources.
Inside the recipe, one can simply declare Ruby variables and assign values to it.
Chef - Libraries
Libraries in Chef provides a place to encapsulate compiled logic so that the cookbook
recipes remain neat and clean.
Creating the Library
Step 1 − Create a helper method in cookbook’s library.
vipin@laptop:~/chef-repo $ subl
cookbooks/my_cookbook/libraries/ipaddress.rb
class Chef::Recipe
def netmask(ipaddress)
IPAddress(ipaddress).netmask
end
end
Note − Setting an environment variable using ENV will make that variable available
during the whole Chef run. In contrast, passing it to the execute resource will only make
it available for that one command executed by the resource.
Chef - Data Bugs
Chef data bags can be defined as an arbitrary collection of data which one can use with
cookbooks. Using data bags is very helpful when one does not wish to hardcode
attributes in recipes nor to store attributes in cookbooks.
Working Method
In the following setup, we are trying to communicate to http endpoint URL. For this, we
need to create a data bag, which will hold the endpoint URL detail and use it in our
recipe.
Step 1 − Create a directory for our data bag.
mma@laptop:~/chef-repo $ mkdir data_bags/hooks
Step 2 − Create a data bag item for request bin. One needs to make sure one is using
a defined requestBin URL.
vipi@laptop:~/chef-repo $ subl data_bags/hooks/request_bin.json {
"id": "request_bin",
"url": "http://requestb.in/1abd0kf1"
}
Uploading the modified cookbook and running Chef client on Ubuntu node will show the
following result.
[2013-03-03T20:16:14+00:00] INFO: Running on a debian
derivative
Workflow of Scripts
In the above command, Ohai will discover the current status of the node’s operating
system and store it as a platform attribute with the node object.
node['platform']
Or, you can use method style syntax −
node.platform
Setting Platform Specific Values
In order to set platform specific values chef offers convenience methods
value_for_platform and value_for_platform_family. They can be used to avoid complex
case statement and use a simple hash instead.
Example cookbook
execute "start-runsvdir" do
command value_for_platform(
"debian" => { "default" => "runsvdir-start" },
"ubuntu" => { "default" => "start runsvdir" },
"gentoo" => { "default" => "/etc/init.d/runit-start start" }
)
action :nothing
end
In the above syntax, ‘type’ is the resource type and ‘name’ is the name that we are going
to use. In the ‘do’ and ‘end’ block, we have the attribute of that resource and the action
that we need to take for that particular resource.
Every resource that we use in the recipe has its own set of actions, which is defined
inside the ‘do’ and ‘end’ block.
Example
type 'name' do
attribute 'value'
action :type_of_action
end
Available Resources
apt_package
Use the apt_package resource to manage packages for the Debian and Ubuntu
platforms.
Bash
Use the bash resource to execute scripts using the Bash interpreter. This resource may
also use any of the actions and properties that are available to the execute resource.
Commands that are executed with this resource are (by their nature) not idempotent, as
they are typically unique to the environment in which they are run. Use not_if and only_if
to guard this resource for idempotence.
Batch
Use the batch resource to execute a batch script using the cmd.exe interpreter.
The batch resource creates and executes a temporary file (similar to how
the script resource behaves), rather than running the command inline.
This resource inherits actions (:run and :nothing) and properties (creates, cwd,
environment, group, path, timeout, and user) from the execute resource. Commands
that are executed with this resource are (by their nature) not idempotent, as they are
typically unique to the environment in which they are run. Use not_if and only_if to
guard this resource for idempotence.
bff_package
Use the bff_package resource to manage packages for the AIX platform using
the installp utility. When a package is installed from a local file, it must be added to the
node using the remote_file or cookbook_file resources.
chef_gem
Use the chef_gem resource to install a gem only for the instance of Ruby that is
dedicated to the Chef-Client. When a gem is installed from a local file, it must be added
to the node using the remote_file or cookbook_file resources.
The chef_gem resource works with all of the same properties and options as
the gem_package resource, but does not accept the gem_binary property because it
always uses the CurrentGemEnvironment under which the Chef-Client is running. In
addition to performing actions similar to the gem_package resource,
the chef_gem resource does the above.
cookbook_file
Use the cookbook_file resource to transfer files from a sub-directory of
COOKBOOK_NAME/files/ to a specified path located on a host that is running the
ChefClient.
The file is selected according to file specificity, which allows different source files to be
used based on the hostname, host platform (operating system, distro, or as appropriate),
or platform version. Files that are located in the COOKBOOK_NAME/files/default
subdirectory may be used on any platform.
Cron
Use the cron resource to manage cron entries for time-based job scheduling. Properties
for a schedule will default to * if not provided. The cron resource requires access to a
crontab program, typically cron.
Csh
Use the csh resource to execute scripts using the csh interpreter. This resource may
also use any of the actions and properties that are available to the execute resource.
Commands that are executed with this resource are (by their nature) not idempotent, as
they are typically unique to the environment in which they are run. Use not_if and only_if
to guard this resource for idempotence.
Deploy
Use the deploy resource to manage and control deployments. This is a popular
resource, but is also complex, having the most properties, multiple providers, the added
complexity of callbacks, plus four attributes that support layout modifications from within
a recipe.
Directory
Use the directory resource to manage a directory, which is a hierarchy of folders that
comprises all of the information stored on a computer. The root directory is the top-level,
under which the rest of the directory is organized.
The directory resource uses the name property to specify the path to a location in a
directory. Typically, permission to access that location in the directory is required.
dpkg_package
Use the dpkg_package resource to manage packages for the dpkg platform. When a
package is installed from a local file, it must be added to the node using
the remote_file or cookbook_file resources.
easy_install_package
Use the easy_install_package resource to manage packages for the Python platform.
Env
Use the env resource to manage environment keys in Microsoft Windows. After an
environment key is set, Microsoft Windows must be restarted before the environment
key is available to the Task Scheduler.
erl_call
Use the erl_call resource to connect to a node located within a distributed Erlang
system. Commands that are executed with this resource are (by their nature) not
idempotent, as they are typically unique to the environment in which they are run. Use
not_if and only_if to guard this resource for idempotence.
Execute
Use the execute resource to execute a single command. Commands that are executed
with this resource are (by their nature) not idempotent, as they are typically unique to the
environment in which they are run. Use not_if and only_if to guard this resource for
idempotence.
File
Use the file resource to manage the files directly on a node.
freebsd_package
Use the freebsd_package resource to manage packages for the FreeBSD platform.
gem_package
Use the gem_package resource to manage gem packages that are only included in
recipes. When a package is installed from a local file, it must be added to the node using
the remote_file or cookbook_file resources.
Git
Use the git resource to manage source control resources that exist in a git repository.
git version 1.6.5 (or higher) is required to use all of the functionality in the git resource.
Group
Use the group resource to manage a local group.
homebrew_package
Use the homebrew_package resource to manage packages for the Mac OS X platform.
http_request
Use the http_request resource to send an HTTP request (GET, PUT, POST, DELETE,
HEAD, or OPTIONS) with an arbitrary message. This resource is often useful when
custom callbacks are necessary.
Ifconfig
Use the ifconfig resource to manage interfaces.
ips_package
Use the ips_package resource to manage packages (using Image Packaging System
(IPS)) on the Solaris 11 platform.
Ksh
Use the ksh resource to execute scripts using the Korn shell (ksh) interpreter. This
resource may also use any of the actions and properties that are available to the execute
resource.
Commands that are executed with this resource are (by their nature) not idempotent, as
they are typically unique to the environment in which they are run. Use not_if and only_if
to guard this resource for idempotence.
Link
Use the link resource to create symbolic or hard links.
Log
Use the log resource to create log entries. The log resource behaves like any other
resource: built into the resource collection during the compile phase, and then run during
the execution phase. (To create a log entry that is not built into the resource collection,
use Chef::Log instead of the log resource)
macports_package
Use the macports_package resource to manage packages for the Mac OS X platform.
Mdadm
Use the mdadm resource to manage RAID devices in a Linux environment using the
mdadm utility. The mdadm provider will create and assemble an array, but it will not
create the config file that is used to persist the array upon reboot.
If the config file is required, it must be done by specifying a template with the correct
array layout, and then by using the mount provider to create a file systems table (fstab)
entry.
Mount
Use the mount resource to manage a mounted file system.
Ohai
Use the ohai resource to reload the Ohai configuration on a node. This allows recipes
that change system attributes (like a recipe that adds a user) to refer to those attributes
later on during the chef-client run.
Package
Use the package resource to manage packages. When the package is installed from a
local file (such as with RubyGems, dpkg, or RPM Package Manager), the file must be
added to the node using the remote_file or cookbook_file resources.
pacman_package
Use the pacman_package resource to manage packages (using pacman) on the Arch
Linux platform.
powershell_script
Use the powershell_script resource to execute a script using the Windows PowerShell
interpreter, much like how the script and script-based resources—bash, csh, perl,
python, and ruby—are used. The powershell_script is specific to the Microsoft Windows
platform and the Windows PowerShell interpreter.
Python
Use the python resource to execute scripts using the Python interpreter. This resource
may also use any of the actions and properties that are available to the execute resource.
Commands that are executed with this resource are (by their nature) not idempotent, as
they are typically unique to the environment in which they are run. Use not_if and only_if
to guard this resource for idempotence.
Reboot
Use the reboot resource to reboot a node, a necessary step with some installations on
certain platforms. This resource is supported for use on the Microsoft Windows, Mac OS
X, and Linux platforms.
registry_key
Use the registry_key resource to create and delete registry keys in Microsoft Windows.
remote_directory
Use the remote_directory resource to incrementally transfer a directory from a
cookbook to a node. The directory that is copied from the cookbook should be located
under COOKBOOK_NAME/files/default/REMOTE_DIRECTORY.
The remote_directory resource will obey file specificity.
remote_file
Use the remote_file resource to transfer a file from a remote location using file
specificity. This resource is similar to the file resource.
Route
Use the route resource to manage the system routing table in a Linux environment.
rpm_package
Use the rpm_package resource to manage packages for the RPM Package Manager
platform.
Ruby
Use the ruby resource to execute scripts using the Ruby interpreter. This resource may
also use any of the actions and properties that are available to the execute resource.
Commands that are executed with this resource are (by their nature) not idempotent, as
they are typically unique to the environment in which they are run. Use not_if and only_if
to guard this resource for idempotence.
ruby_block
Use the ruby_block resource to execute Ruby code during a Chef-Client run. Ruby
code in the ruby_block resource is evaluated with other resources during convergence,
whereas Ruby code outside of a ruby_block resource is evaluated before other
resources, as the recipe is compiled.
Script
Use the script resource to execute scripts using a specified interpreter, such as Bash,
csh, Perl, Python, or Ruby. This resource may also use any of the actions and properties
that are available to the execute resource.
Commands that are executed with this resource are (by their nature) not idempotent, as
they are typically unique to the environment in which they are run. Use not_if and only_if
to guard this resource for idempotence.
Service
Use the service resource to manage a service.
smart_os_package
Use the smartos_package resource to manage packages for the SmartOS platform.
solaris_package
The solaris_package resource is used to manage packages for the Solaris platform.
Subversion
Use the subversion resource to manage source control resources that exist in a
Subversion repository.
Template
Use the template resource to manage the contents of a file using an Embedded Ruby
(ERB) template by transferring files from a sub-directory of
COOKBOOK_NAME/templates/ to a specified path located on a host that is running the
Chef-Client. This resource includes actions and properties from the file resource.
Template files managed by the template resource follow the same file specificity rules
as the remote_file and file resources.
User
Use the user resource to add users, update existing users, remove users, and to
lock/unlock user passwords.
windows_package
Use the windows_package resource to manage Microsoft Installer Package (MSI)
packages for the Microsoft Windows platform.
windows_service
Use the windows_service resource to manage a service on the Microsoft Windows
platform.
yum_package
Use the yum_package resource to install, upgrade, and remove packages with Yum for
the Red Hat and CentOS platforms. The yum_package resource is able to resolve
provides data for packages much like Yum can do when it is run from the command line.
This allows a variety of options for installing packages, like minimum versions, virtual
provides, and library names.
Chef - Blueprints
In Chef, blueprints are the tools to find out and record exactly what is present on the
server. Blueprints record all the things required such as directors, packages,
configuration files, and so on. Blueprints have the capability to split server information in
various formats. One of them is Chef recipe. This helps to configure unique server using
Chef.
Woring Method
We need to have Python and Git installed on the node where we need to run the
blueprint.
Step 1 − Install the blueprint.
vipin@server:~$ pip install blueprint
Step 2 − Create a blueprint.
user@server:~$ sudo blueprint create internal-cookbook
# [blueprint] using cached blueprintignore(5) rules
# [blueprint] searching for Python packages
# [blueprint] searching for PEAR/PECL packages
# [blueprint] searching for Yum packages
# [blueprint] searching for Ruby gems
# [blueprint] searching for npm packages
# [blueprint] searching for software built from source
# [blueprint] searching for configuration files
# [blueprint] /etc/ssl/certs/AC_Ra\xc3\xadz_Certic\xc3\
xa1mara_S.A..pem not UTF-8 - skipping it
# [blueprint] /etc/ssl/certs/NetLock_Arany_=Class_Gold=_F\xc5\
x91tan\xc3\xbas\xc3\xadtv\xc3\xa1ny.pem not UTF-8 - skipping it
# [blueprint] /etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sa\
xc4\x9flay\xc4\xb1c\xc4\xb1s\xc4\xb1.pem not UTF-8 - skipping it
# [blueprint] /etc/ssl/certs/Certinomis_-_Autorit\xc3\xa9_Racine.
pem not UTF-8 - skipping it
# [blueprint] /etc/ssl/certs/T\xc3\x9cB\xc4\xb0TAK_UEKAE_K\xc3\
xb6k_Sertifika_Hizmet_Sa\xc4\x9flay\xc4\xb1c\xc4\xb1s\xc4\xb1_-_S\
xc3\xbcr\xc3\xbcm_3.pem not UTF-8 - skipping it
# [blueprint] searching for APT packages
# [blueprint] searching for service dependencies
Step 3 − Create a cookbook from the blueprint.
user@server:~$ blueprint show -C internal-cookbook my-
server/recipes/default.rb
Step 4 − Validate the content of the generated file.
user@server:~$ cat internal-cookbook /recipes/default.rb
#
# Automatically generated by blueprint(7). Edit at your own risk.
#
cookbook_file('/tmp/96468fd1cc36927a027045b223c61065de6bc575.tar')
do
backup false
group 'root'
mode '0644'
owner 'root'
source 'tmp/96468fd1cc36927a027045b223c61065de6bc575.tar'
end
execute('/tmp/96468fd1cc36927a027045b223c61065de6bc575.tar') do
command 'tar xf
"/tmp/96468fd1cc36927a027045b223c61065de6bc575.tar"'
cwd '/usr/local'
end
directory('/etc/apt/apt.conf.d') do
...TRUNCATED OUTPUT...
service('ssh') do
action [:enable, :start]
subscribes :restart, resources('cookbook_file[/etc/default/
keyboard]', 'cookbook_file[/etc/default/console-setup]',
'cookbook_file[/etc/default/ntfs-3g]', 'package[openssh-
server]',
'execute[96468fd1cc36927a027045b223c61065de6bc575.tar]')
end
Workflow Script
Blueprint is a Python package that finds out all the relevant configuration data of the
server and stores it in a Git repo. Each blueprint has its own name.
One can ask the blueprint to show the content of its Git repo in various formants.
user@server:~$ ls -l internal-cookbook /
total 8
drwxrwxr-x 3 vagrant vagrant 4096 Jun 28 06:01 files
-rw-rw-r-- 1 vagrant vagrant 0 Jun 28 06:01 metadata.rb
drwxrwxr-x 2 vagrant vagrant 4096 Jun 28 06:01 recipes
Blueprints Show Commands
user@server:~$ blueprint show-packages my-server
...TRUNCATED OUTPUT...
apt wireless-regdb 2011.04.28-1ubuntu3
apt zlib1g-dev 1:1.2.3.4.dfsg-3ubuntu4
python2.7 distribute 0.6.45
python2.7 pip 1.3.1
pip blueprint 3.4.2
pip virtualenv 1.9.1
The preceding command shows all kinds of installed packages. Other show commands
are as follows −
• show-files
• show-services
• show-sources
Chef - Files & Packages
In Chef, creating configuration files and moving packages are the key components.
There are multiple ways how Chef manages the same. There are multiple ways how
Chef supports in dealing with the files and software packages.
Installing Packages from Third-Party Repo
Step 1 − Edit the default recipe of the cookbook.
vipin@laptop:~/chef-repo $ subl
cookbooks/test_cookbook/recipes/default.rb
include_recipe "apt"
apt_repository "s3tools" do
uri "http://s3tools.org/repo/deb-all"
components ["stable/"]
key "http://s3tools.org/repo/deb-all/stable/s3tools.key"
action :add
end
package "s3cmd"