Chef - solo (chef-solo and knife-solo)

summary from book ‘Cooking infrastructure by Chef’ by Alexey Vasiliev and official chef documentation.


participants:

  1. chef node (deployment target - this is what configured, has chef-client or chef-solo installed)
  2. chef server (combined with chef node when using chef-solo)
  3. workstation (from which knife or knife-solo is run - can be remote host as well)

core principles:

chef-client

CHEF SOLO

chef-solo

knife

knife-solo

$ gem install knife-solo

berkshelf

kitchen

create a new kitchen in current directory:

$ knife solo init .

file structure:

directory or file usage
.chef/ stores .pem files and knife.rb
cookbooks/ vendor cookbooks installed with berkshelf
data_bags/ data bags
environments/ environments
nodes/ nodes
roles/ roles
site-cookbooks/ custom cookbooks
Berksfile like Gemfile for rubygems

.chef/knife.rb

VENDOR COOKBOOKS

Berksfile:

cookbook 'apache2'

install cookbook globally into ~/.berkshelf/cookbooks/:

$ berks install

install cookbook both locally into cookbooks/ and globally into ~/.bershelf/cookbooks/:

$ berks vendor cookbooks

NOTE: command berks install --path cookbooks does the same but is deprecated.

it’s necessary to specify directory (cookbooks/) - otherwise berkshelf will install cookbook into berks-cookbooks/.

knife[:berkshelf_path] option has no effect on where berkshelf installs cookbooks

NODES

NOTE: nodes are configured in node files for chef-solo only - chef-client interacts with chef server to retrieve node configuration.

node

run_list

sample node file:

{run_list: ['recipe[apache2]']}

ATTRIBUTES

attribute

accessor methods are automatically defined for attributes in Ruby files (that is it’s possible to use dot syntax instead of hash keys):

default['apache']['dir'] = '/etc/apache2'
default.apache.dir = '/etc/apache2'

or else it’s possible to use symbols instead of strings as hash keys:

default['apache']['dir'] = '/etc/apache2'
default[:apache][:dir] = '/etc/apache2'

attribute precedence

in general attribute precedence is organized in such a way as:

attribute precendence table

attribute types

see also http://stackoverflow.com/a/20835500

attribute type is specified when using attributes by calling appropriate function of node object:

# default
node.default['apache']['dir'] = '/etc/apache2'

# override
node.override['apache']['dir'] = '/etc/apache2'

NOTE: cookbook attribute files are evaluated in the context of node object - that is why it’s not necessary (but possible) to use it explicitly:

# default
default['apache']['dir'] = '/etc/apache2'

# override
override['apache']['dir'] = '/etc/apache2'

normal attribute

syntax in recipe or node file:

node.normal['apache']['dir'] = '/etc/apache2'
node.set['apache']['dir']    = '/etc/apache2' # set is an alias of normal
node['apache']['dir']        = '/etc/apache2' # same as above

syntax in cookbook attribute file:

# use of node object is implicit
normal['apache']['dir']      = '/etc/apache2'
set['apache']['dir']         = '/etc/apache2'

# use of node object is explicit
node.normal['apache']['dir'] = '/etc/apache2'
node.set['apache']['dir']    = '/etc/apache2'
node['apache']['dir']        = '/etc/apache2'

TODO: the same syntax node['cookbook']['attribute'] is used to read final node attribute value after all precedence rules have been applied.

ROLES

role

structure:

key required? description
name yes unique name (usually the same as file name)
description yes  
chef_type yes ‘role’
json_class yes ‘Chef::Role’
default_attributes   role-specific attributes, can be overidden in node files
override_attributes   role-specific forced attributes, cannot be overidden in node files
run_list yes role-specific run-list (may include other roles)
env_run_lists   environment-specific run-lists

use role in node file:

{run_list: ['role[web]']}

ENVIRONMENTS

environment

structure:

key required? description
name yes unique name (usually the same as file name)
description yes  
chef_type yes ‘environment’
json_class yes ‘Chef::Environment’
default_attributes   environment-specific attributes, can be overidden in node files
override_attributes   environment-specific forced attributes, cannot be overidden in node files

set environment in node file:

{'run_list': ['recipe[apache2]'], 'chef_environment': 'development'}

or else environment can be set using -E knife argument:

$ knife solo cook -E development

DATA BAGS

data bag

structure (according to official docs data bag item should contain only the contents of raw_data):

key required? description
name yes unique name (usually the same as file name)
chef_type yes ‘data_bag_item’
json_class yes ‘Chef::DataBagItem’
data_bag yes data bag name
raw_data yes attributes of data bag item (id attribute is required)

SITE COOKBOOK

cookbook

create custom cookbook:

$ cd site-cookbooks/
$ knife cookbook create COOKBOOK

structure:

directory or file deprecated?
attributes/  
definitions/ yes
files/  
libraries/  
providers/ yes
recipes/  
resources/  
templates/  
metadata.rb  

ATTRIBUTE FILES

sample attribute file:

default['apache']['dir']          = '/etc/apache2'
default['apache']['listen_ports'] = [ '80','443' ]

default is attribute type here - it has nothing to do with attribute file name (see Chef Solo/ATTRIBUTES section for more information).

use of node object (node) is implicit here though it can be used explicitly (see Chef Solo/ATTRIBUTES section for more information).

RECIPES

recipe

default recipe - default.rb (see Chef Solo/NODES for information about default recipe).

include other recipes

recipe can include other recipes from other cookbooks using include_recipe method:

include_recipe 'apache2::mod_ssl'

included recipe must be declared as dependency in metadata.rb:

depends 'apache2'

write to log from within a recipe

log levels:

Chef::Log.info 'some useful information'

RESOURCES

resource

2 types of resources:

  1. platform resource (built-in)
  1. custom resource (provided by cookbook)

usage and definition:

NOTE: this section describes how to use platform and custom resources. see custom resource files on how to define custom resources.

usage syntax:

TYPE 'NAME' do
  PROPERTY_NAME 'PROPERTY_VALUE'
  action :TYPE_OF_ACTION
end

only non-default properties and actions must be specified.

sample resource usage:

directory '/tmp/something' do
  owner 'root'
  group 'root'
  mode 00755
  action :create
end
resource description
script execute script using specified interpretor
bash execute script using Bash interpretor
ruby execute script using Ruby interpretor
link create sym or hard links
directory manage directories
cookbook_file transfer files from subdirectory of files/ (PLATFORM or default for any platform)
template transfer files from subdirectory of templates/ (PLATFORM or default for any platform)
package install package (rpm, deb, etc.)
gem_package install gem system-wide
chef_gem install gem into the instance of Ruby dedicated to chef-client (can be required immediatelly after it’s installed)
cron modify cron entries
user manage users

NOTE: for template resource transfer not ERB templates themselves but static files generated from those templates.

NOTE: for directory resource try not to use recursive option since group, owner and mode properties are not applied to parent directories - they are owned by root:root!

custom resource files

NOTE: LWRP/HWRP paradigm is replaced with custom resources - see Custom Resources in Chef Client 12.5 for details.

NOTE: definitions are also deprecated in favor of custom resources.

resource file

syntax:

resource_name :httpd

property :instance_name, String, name_property: true
property :name, RubyType, default: 'value'

default_action :action_2

load_current_value do
  # some Ruby
end

action :action_1 do
 # a mix of built-in Chef resources and Ruby
end

action :action_2 do
 # a mix of built-in Chef resources and Ruby
end

usage of all these methods and parameters is optional:

TEMPLATES

template

to use template:

ERB basics:

syntax description
<%= %> expressions (=)
<% %> statements (-)

variables inside template file

  1. defined in template resource’s variables parameter:
template '/etc/sudoers' do
  ...
  variables(
    {
      sudoers_groups: node[:authorization][:sudo][:groups],
      sudoers_users: node[:authorization][:sudo][:users]
    }
  )
end

these variables are accessible in template file as instance variables (@).

  1. node object properties (using the same syntax as in recipe)

sample template file:

<% if @username.present? %>
  Site <%= node[:fqdn] %> welcomes new user <%= @username %>!
<% end %>

file specificity

specific template file might be targeted for specific platform.

template file is looked up in the following locations within templates/ (the first one that matches wins):

NOTE: FQDN must match literally!

partials

partial

render

render partial from top-level template file:

<%= render 'another_template.erb', variables: { user: @user } %>

METADATA.RB

metadata.rb

setting description
name cookbook name (main setting)
maintainer  
maintainer_email  
description  
long_description usually the contents of README.md
version three-number version sequence
chef_version range of chef-client versions supported by cookbook
attribute attribute required to configure cookbook
provides recipe or resource provided by cookbook
recipe description for recipe (cosmetic value)
depends cookbook dependency on another cookbook
conflicts FIO. conflicting cookbook or cookbook version
recommends FIO. recommended cookbook
suggests FIO. suggested cookbook (weaker than recommends)
replaces FIO. cookbook to be replaced by this cookbook
supports supported platform