Chef: Local Cookbook Development

 

Generators
generator1generator2generator3

  1. Execute the command as follows:
    chef generate cookbook test_cookbook
    cd test_cookbook
    Take a look at some of the default files like README.md, spec-helper.rb, default.rb file
  2. We will now create a generator that we will use to create cookbook with our customization:
    mkdir generator
    chef generate generator generator/lcd_origin
    cd generator/lcd_origin/templates/default
    vi README.md.erb insert text of your choice. Save and close.
  3. Edit kitchen.yml.erb change the contents to match the following, as we will be using docker driver and centos 7.2 image:
    ---
    driver:
      name: docker
      privileged: true
      use_sudo: false
    
    provisioner:
      name: chef_zero
      # You may wish to disable always updating cookbooks in CI or other testing environments.
      # For example:
      #   always_update_cookbooks: <%%= !ENV['CI'] %>
      always_update_cookbooks: true
    
    verifier:
      name: inspec
    
    platforms:
      - name: centos-7.2
        driver_config:
          run_command: /usr/lib/systemd/systemd
    
    suites:
      - name: default
        run_list:
          - recipe[<%= cookbook_name %>::default]
        verifier:
          inspec_tests:
            - test/smoke/default
        attributes:
    <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
    

    Make sure you are not adding any tabs as they are invalid in ymls.

  4. Edit ../../files/default/spec_helper.rb Add the following lines:
    RSpec.configure do |config|
      config.platform = 'centos'
      config.version = '7.2.1511'
    end<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
    
  5. So to tell chef to use our generator when generating cookbooks:
    goto the lcd_origin directory
    mkdir ~/.chef
    vi ~/.chef/config.rb Add the contents as below:

    cookbook_path ['~/chef/cookbooks']
    local_mode true
    if File.basename($PROGRAM_NAME).eql?('chef') && ARGV[0].eql?('generate')
      chefdk.generator.license = "all_rights"
      chefdk.generator.copyright_holder = "Student Name"
      chefdk.generator_cookbook = "/root/cookbooks/lcd_origin"
      chefdk.generator.email = "you@example.com"
      chefdk.generator_cookbook = "~/generator/lcd_origin"
    end
    <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
    

    Create directory chef/cookbooks
    mkdir -p ~/chef/cookbooks
    And then generate a cookbook
    cd ~/chef
    chef generate cookbook cookbooks/lcd_web
    If you check the README vi cookbooks/lcd_web/README.md. You will see the text we added previously.
    We can generate attributes by following command:
    chef generate attribute cookbooks/lcd_web default
    We can genrate recipe by:
    chef generate recipe cookbooks/lcd_web users

  6. These attributes can be checked here in lcd_origin/attributes/default.rb
    The recipe can be checked with lcd_origin/recipes/users.rb

Test Driven Development

tdd1.png
tdd2tdd3tdd4tdd5

ChefSpec

chefspec1chefspec2chefspec3chefspec4chefspec5

    1. You can check the chefspec default file  spec/unit/recipes/default_spec.rb
    2. Now let’s run the default_spec
      chef exec rspec
      If you get any warning about platform and platform_version then change the following in your code:
      runner = ChefSpec::ServerRunner.new(platform: ‘centos’, version: ‘7.2.1511’)
      For some of you the platform and the platform_version might be already added. It might be ubuntu and 16.04 change it to centos and 7.2.1511 resp.
      Then execute the rspec again. This will give an output similar to below:
      Finished in 0.48374 seconds (files took 1.83 seconds to load)
      2 examples, 0 failures
    3. Now change the default_spec.rb to match the following to check if httpd package is installed or not:
      #
      # Cookbook:: lcd_web
      # Spec:: default
      #
      # Copyright:: 2017, Student Name, All Rights Reserved.
      
      require 'spec_helper'
      
      describe 'lcd_web::default' do
        context 'CentOS' do
          let(:chef_run) do
            # for a complete list of available platforms and versions see:
            # https://github.com/customink/fauxhai/blob/master/PLATFORMS.md
            runner = ChefSpec::ServerRunner.new(platform: 'centos', version: '7.2.1511')
            runner.converge(described_recipe)
          end
      
          it 'converges successfully' do
            expect { chef_run }.to_not raise_error
          end
      
          it 'installs httpd' do
            expect(chef_run).to install_package('httpd')
          end
        end
      end
      

      Then run chef exec rspec You will get an error as below:

      .F.

      Failures:

      1) lcd_web::default CentOS installs httpd
      Failure/Error: expect(chef_run).to install_package(‘httpd’)

      expected “package[httpd]” with action :install to be in Chef run. Other p ackage resources:

      # ./spec/unit/recipes/default_spec.rb:23:in `block (3 levels) in ‘

      Finished in 0.63225 seconds (files took 1.68 seconds to load)
      3 examples, 1 failure

      Failed examples:

      rspec ./spec/unit/recipes/default_spec.rb:22 # lcd_web::default CentOS installs httpd

      It failed because there was no httpd package present in the system because our cookbook doesn’t do so. Let’s add httpd installation to our default recipe.

      package ‘httpd’ do
      end
      As the default action is install we do not need to specify anything.
      Now let’s execute the rspec: chef exec rspec
      Now the output will be as follows:

      Finished in 0.73318 seconds (files took 1.67 seconds to load)
      3 examples, 0 failures

    4. Add the following below installs httpd task:
          it 'enables the httpd service' do
            expect(chef_run).to enable_service('httpd')
          end
      
          it 'starts the service' do
            expect(chef_run).to start_service('httpd')
          end
      
      Add the following in default.rb recipe:
      service 'httpd' do
        action [:start, :enable]
      end
      <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
      

      Then run: chef exec rspec

    5. Now what if I add something in the default recipe that might break my cookbook:
      add the line in default.rb
      include_recipe ‘something’
      Then run rspec you will get error as below:
      Failure/Error: runner.converge(described_recipe)Chef::Exceptions::CookbookNotFound:
      Cookbook something not found. If you’re loading something from another cookbook, make sure you configure the dependency in your metadata
      # /tmp/chefspec20170918-4764-5svx8rfile_cache_path/cookbooks/lcd_web/recipes/default.rb:7:in `from_file’
      # ./spec/unit/recipes/default_spec.rb:15:in `block (3 levels) in ‘
      # ./spec/unit/recipes/default_spec.rb:31:in `block (3 levels) in ‘Finished in 0.81827 seconds (files took 1.71 seconds to load)
      5 examples, 4 failuresFailed examples:rspec ./spec/unit/recipes/default_spec.rb:18 # lcd_web::default CentOS converges successfully
      rspec ./spec/unit/recipes/default_spec.rb:22 # lcd_web::default CentOS installs httpd
      rspec ./spec/unit/recipes/default_spec.rb:26 # lcd_web::default CentOS enables the httpd service
      rspec ./spec/unit/recipes/default_spec.rb:30 # lcd_web::default CentOS starts the service

So you can see the test will fail if the cookbook dependency failes as well. You can remove the include_recipe line and re execute the rspec.

Test Kitchen Configuration

testkit1testkit2testkit3testkit4testkit5testkit6testkit7testkit8testkit9testkit10testkit11

  1. Edit .kitchen.yml to match the following:
    ---
    driver:
      name: docker
      privileged: true
      use_sudo: false
    
    provisioner:
      name: chef_zero
      # You may wish to disable always updating cookbooks in CI or other testing environments.
      # For example:
      #   always_update_cookbooks: <%= !ENV['CI'] %>
      always_update_cookbooks: true
    
    verifier:
      name: inspec
    
    platforms:
      - name: centos-7.2
      - name: centos-6.8
    
    suites:
      - name: dev
        driver:
          run_command: /usr/sbin/init
        run_list:
          - recipe[la_java::default]
        attributes: { 'java': { 'jdk_version': '7' } }
        driver_config:
          forward:
            - 8080:80
        excludes: centos-6.8
      - name: prod
        driver:
          run_command: /sbin/init
        run_list:
          - recipe[la_java::default]
        attributes: { 'java': { 'jdk_version': '6' } }
        driver_config:
          forward:
            - 8081:80
        includes: centos-6.8
    <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
    

    Execute the command kitchen list
    If you get error as follows:
    >>>>>> ——Exception——-
    >>>>>> Class: Kitchen::ClientError
    >>>>>> Message: Could not load the ‘docker’ driver from the load path. Please en sure that your driver is installed as a gem or included in your Gemfile if using Bundler.
    >>>>>> ———————-
    >>>>>> Please see .kitchen/logs/kitchen.log for more details
    >>>>>> Also try running `kitchen diagnose –all` for configuration

    Then install the chef gem kitchen-docker with:  chef gem install kitchen-docker
    Then the kitchen list output will be as follows:
    [root@arati7111 lcd_web]# kitchen list
    Instance Driver Provisioner Verifier Transport Last Action Last Error
    dev-centos-72 Docker ChefZero Inspec Ssh
    prod-centos-68 Docker ChefZero Inspec Ssh
    Then run: kitchen converge
    Then kitchen verify
    Thus java 7 will be installed in centos 7 and java 6 on centos 6

  2. If you comment the includes and excludes statements from .kitchen.yml then we will have 4 test cases.
  3. You can download the java cookbook with
    knife cookbook site download
    and add it to the run_list

Using Test Kitchen

kitchen3kitchen4kitchen5

Execute the following commands

  1. mkdir test_kitchen
  2. cd test_kitchen
  3. kitchen init
    If you get the following error while executing kitchen init:Successfully installed kitchen-vagrant-1.2.1
    Fetching: mixlib-install-3.6.0.gem (100%)
    Successfully installed mixlib-install-3.6.0
    Fetching: ffi-1.9.18.gem (100%)
    Building native extensions. This could take a while…
    ERROR: Error installing kitchen-vagrant:
    ERROR: Failed to build gem native extension./usr/bin/ruby extconf.rb
    mkmf.rb can’t find header files for ruby at /usr/share/include/ruby.h

Gem files will remain installed in /home/user/.gem/ruby/gems/ffi-1.9.18 for inspection.
Results logged to /home/user/.gem/ruby/gems/ffi-1.9.18/ext/ffi_c/gem_make.out

Then execute the kitchen init command with sudo rights

  • If even then the issue is not resolved execute the following command:
    chef gem list kitchen-vagrant
    Then you will have output as follows:  kitchen-vagrant (1.2.1)
    chef gem uninstall kitchen-vagrant -v 1.2.1
    Then rerun kitchen init with sudo rights
  • chef generate cookbook my_cookbook
    You can see that the test/integration/default directory
    In the cookbook you can see the test/smoke/default directory
  • Execute kitchen list
    If you get an error as follows:
    >>>>>> ——Exception——-
    >>>>>> Class: Kitchen::UserError
    >>>>>> Message: Vagrant 1.1.0 or higher is not installed. Please download a package from http://www.vagrantup.com/downloads.html.
    >>>>>> ———————-
    That means you will have to install vagrant. you can use the following command:
    rpm -ivh https://releases.hashicorp.com/vagrant/2.0.0/vagrant_2.0.0_x86_64.rpmThen again execute kitchen list  you will get an output as below:
    Instance Driver Provisioner Verifier Transport Last Action Last Error
    default-ubuntu-1404 Vagrant ChefSolo Busser Ssh
    default-centos-72 Vagrant ChefSolo Busser Ssh
    kitchen7kitchen8kitchen9
  • Execute kitchen create
    You will get an error as follows: The provider ‘virtualbox’ that was requested to back the machine ‘default’
    You will need to install virtualbox first: Follow this tutorial for the same:
    https://apassionatechie.wordpress.com/2017/10/09/install-virtualbox-on-centos-7/kitchen10.png
    If you are not able to install vbox then just change the driver name from vagrant to docker in .kitchen.yml

Then execute kitchen converge
kitchen11.png
Then execute kitchen setup
Then you can execute kitchen destroy to delete the created instances
kitchen13kitchen14

InSpec
inspec1inspec2inspec3inspec4inspec5inspec6inspec7inspec8

Create a cookbook with chef generate cookbook lcd_web. Edit the following file test/smoke/default/default_test.rb. Add the following lines
[ ‘net-tools’, ‘httpd’ ].each do |pkg|
describe package(pkg) do
it { should be_installed }
end
end

Then execute kitchen verify it will fail the test as below:

System Package
∅ net-tools should be installed
expected that `System Package net-tools` is installed
System Package
∅ httpd should be installed
expected that `System Package httpd` is installed

Now lets add the chef code to install these packages
Add the following lines in recipes/default.rb
[ ‘net-tools’, ‘httpd’].each do |pkg|
package pkg do
action :install
end
end

Then execute kitchen converge
Then run kitchen verify
The output should be somthing as below:
System Package
✔ net-tools should be installed
System Package
✔ httpd should be installed

Static Code Analysis

static1static2static3static4static5static6static7static8static9
foodcritic -l
FC001: Use strings in preference to symbols to access node attributes
FC002: Avoid string interpolation where not required
FC004: Use a service resource to start and stop services
FC005: Avoid repetition of resource declarations
FC006: Mode should be quoted or fully specified when setting file permissions
FC007: Ensure recipe dependencies are reflected in cookbook metadata
FC008: Generated cookbook metadata needs updating
FC009: Resource attribute not recognised
FC010: Invalid search syntax
FC011: Missing README in markdown format
FC012: Use Markdown for README rather than RDoc
FC013: Use file_cache_path rather than hard-coding tmp paths
FC014: Consider extracting long ruby_block to library
FC015: Consider converting definition to a Custom Resource
FC016: LWRP does not declare a default action
FC017: LWRP does not notify when updated
FC018: LWRP uses deprecated notification syntax

Now cd to lcd_web cookbook
execute: foodcritic .
output: Checking 2 files
x.
FC008: Generated cookbook metadata needs updating: ./metadata.rb:3
FC064: Ensure issues_url is set in metadata: ./metadata.rb:1
FC065: Ensure source_url is set in metadata: ./metadata.rb:1
FC067: Ensure at least one platform supported in metadata: ./metadata.rb:1
FC078: Ensure cookbook shared under an OSI-approved open source license: ./metadata.rb:1

Lets check our metadata.rb file
For error FC067 add the line in metadata.rb: supports ‘centos’
The other errors are not of our concern so we will exclude them with:
foodcritic . -t ~FC008 -t ~FC064 -t ~FC065 -t ~FC078
There should be no errors.

Now we want to persist these exclusion so we will create .foodcritic file:
vi .foodcritic and add the following lines:

~FC008

~FC064

~FC065

~FC078
Save and close. Then execute foodcritic .

Lets have a look at rubocop. To install rubocop execute gem install rubocop

You can have a look at it’s help with command rubocop –help

If you run rubocop in lcd_we cookbook you might get output as follows:

init_test/lcd_web/recipes/default.rb:7:2: C: Space inside square brackets detected.
[ ‘net-tools’, ‘httpd’].each do |pkg|
^
bin/mixlib-install:11:11: C: Prefer single-quoted strings when you don’t need string interpolation or special symbols.
version = “>= 0”
^^^^^^
bin/mixlib-install:15:32: C: Prefer single-quoted strings when you don’t need string interpolation or special symbols.
str = str.dup.force_encoding(“BINARY”) if str.respond_to? :force_encoding
^^^^^^^^
bin/mixlib-install:17:15: C: Avoid the use of Perl-style backrefs.
version = $1
^^

32 files inspected, 53 offenses detected

You might have errors like “line too long” etc. By default the line length specified in 80, Now let’s see if we can override that setting.
We will be needing todo file for that let’s generate it by the command:
rubocop –auto-gen-config
Then edit the file .rubocop.yml and add the line: inherit_from: .rubocop_todo.yml
Then execute rubocop you will see that all of our offenses have been masked.
Let’s have a look at the .rubocop_todo.yml file.
Now in the code you will see code blocks like follows:

# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
Layout/IndentHeredoc:
  Exclude:
    - 'generator/lcd_origin/recipes/recipe.rb'

This denotes that there i an indentation issue with recipe.rb file.
rubocop has the feature to auto-correct small issues, you will need to comment code block one by one and then execute rubocop –auto-correct
Output will be something like: generator/lcd_origin/metadata.rb:5:1: C: [Corrected] 1 trailing blank lines detected.

So in this way we can correct some issues with rubocop. You can repeat the same for rest of the issues.
For the other issues which cannot be correct with rubo-cop you can add rules for the same in .rubocop.yml

We will change the LineLength rule. Add the following in .rubocop.yml file:
LineLength:
Max: 200
Then comment the LineLength block in .rubocop_todo.yml file.

Then execute rubocop You will see there are no offenses.

Troubleshooting
ts1ts2ts3ts4ts5ts6

Edit file recipes/default.rb. Comment everything and add the following:

lazy_message = "Hello World"

file 'lazy_message' do
  path '/tmp/lazy.txt'
  content "#{lazy_message}"
end

execute 'yum-makecache' do
  command 'yum makecache'
  notifies :create, 'file[message]', :immediately
  action :nothing
end

package 'bind-utils' do
  action :install
  notifies :run, 'execute[yum-makecache]', :before
end

file 'message' do
  path '/tmp/message.txt'
  content lazy { "#{lazy_message}" }
end

lazy_message = "Goodbye World"

In this code firstly value of lazy_meesage will be set to Hello World. Then file /tmp/lazy.txt will get generated then makecache block will ge executed which in turn will call the file “message” block. But the file content will be wriiten at last due to lazy tag. Then package bind-utils will be installed but before that yum makecache will be called.
Then execute kitchen converge
kitchen login
lazy.txt will contain “Hello World” and message.txt will contain “Goodbye world”

 

Chef: Overview

Chef is a powerful automation platform that transforms infrastructure into code. Whether you’re operating in the cloud, on-premises, or in a hybrid environment, Chef automates how infrastructure is configured, deployed, and managed across your network, no matter its size.

This diagram shows how you develop, test, and deploy your Chef code.

_images/start_chef.svg
  • The workstation is the location from which users interact with Chef. On the workstation users author and test cookbooks using tools such as Test Kitchen and interact with the Chef server using the knife and chefcommand line tools.

  • Nodes are the machines—physical, virtual, cloud, and so on—that are under management by Chef. The chef-client is installed on each node and is what performs the automation on that machine.

  • Use the Chef server as your foundation to create and manage flexible, dynamic infrastructure whether you manage 50 or 500,000 nodes, across multiple datacenters, public and private clouds, and in heterogeneous environments.

    The Chef server acts as a hub for configuration data. The Chef server stores cookbooks, the policies that are applied to nodes, and metadata that describes each registered node that is being managed by the chef-client. Nodes use the chef-client to ask the Chef server for configuration details, such as recipes, templates, and file distributions. The chef-client then does as much of the configuration work as possible on the nodes themselves (and not on the Chef server). This scalable approach distributes the configuration effort throughout the organization.

Chef Components

The following diagram shows the relationships between the various elements of Chef, including the nodes, the server, and the workstation. These elements work together to provide the chef-client the information and instruction that it needs so that it can do its job. As you are reviewing the rest of this topic, use the icons in the tables to refer back to this image.

_images/chef_overview.svg

Chef has the following major components:

Component Description
_images/icon_workstation.svg
_images/icon_cookbook.svg
_images/icon_ruby.svg

One (or more) workstations are configured to allow users to author, test, and maintain cookbooks. Cookbooks are uploaded to the Chef server from the workstation. Some cookbooks are custom to the organization and others are based on community cookbooks available from the Chef Supermarket.

Ruby is the programming language that is the authoring syntax for cookbooks. Most recipes are simple patterns (blocks that define properties and values that map to specific configuration items like packages, files, services, templates, and users). The full power of Ruby is available for when you need a programming language.

Often, a workstation is configured to use the Chef Development Kit as the development toolkit. The Chef Development Kit is a package from Chef that provides a recommended set of tooling, including Chef itself, the chef command line tool, Test Kitchen, ChefSpec, Berkshelf, and more.

_images/icon_node.svg
_images/icon_chef_client.svg

A node is any machine—physical, virtual, cloud, network device, etc.—that is under management by Chef.

A chef-client is installed on every node that is under management by Chef. The chef-client performs all of the configuration tasks that are specified by the run-list and will pull down any required configuration data from the Chef server as it is needed during the chef-client run.

_images/icon_chef_server.svg

The Chef server acts as a hub of information. Cookbooks and policy settings are uploaded to the Chef server by users from workstations. (Policy settings may also be maintained from the Chef server itself, via the Chef management console web user interface.)

The chef-client accesses the Chef server from the node on which it’s installed to get configuration data, performs searches of historical chef-client run data, and then pulls down the necessary configuration data. After the chef-client run is finished, the chef-client uploads updated run data to the Chef server.

Chef management console is the user interface for the Chef server. It is used to manage data bags, attributes, run-lists, roles, environments, and cookbooks, and also to configure role-based access for users and groups.

_images/icon_chef_supermarket.svg
Chef Supermarket is the location in which community cookbooks are shared and managed. Cookbooks that are part of the Chef Supermarket may be used by any Chef user. How community cookbooks are used varies from organization to organization.

Chef management console, chef-client run reporting, high availability configurations, and Chef server replication are available as part of Chef Automate.

The following sections discuss these elements (and their various components) in more detail.

Workstations

A workstation is a computer running the Chef Development Kit (ChefDK) that is used to author cookbooks, interact with the Chef server, and interact with nodes.

The workstation is the location from which most users do most of their work, including:

  • Developing and testing cookbooks and recipes
  • Testing Chef code
  • Keeping the chef-repo synchronized with version source control
  • Configuring organizational policy, including defining roles and environments, and ensuring that critical data is stored in data bags
  • Interacting with nodes, as (or when) required, such as performing a bootstrap operation

The Chef Development Kit tooling encourages integration and unit testing, and defines workflow around cookbook authoring and policy, but it’s important to note that you know best about how your infrastructure should be put together. Therefore, Chef makes as few decisions on its own as possible. When a decision must be made tools uses a reasonable default setting that can be easily changed. While Chef encourages the use of the tooling packaged in the Chef DK, none of these tools should be seen as a requirement or pre-requisite for being successful using Chef.

Workstation Components and Tools

Some important tools and components of Chef workstations include:

Component Description
_images/icon_devkit.svg

The Chef Development Kit is a package that contains everything that is needed to start using Chef:

  • chef-client and ohai
  • chef and knife command line tools
  • Testing tools such as Test Kitchen, ChefSpec, Cookstyle, and Foodcritic
  • InSpec
  • Everything else needed to author cookbooks and upload them to the Chef server
_images/icon_ctl_chef.svg
_images/icon_ctl_knife.svg

ChefDK includes two important command-line tools:

  • Chef: Use the chef command-line tool to work with items in a chef-repo, which is the primary location in which cookbooks are authored, tested, and maintained, and from which policy is uploaded to the Chef server
  • Knife: Use the knife command-line tool to interact with nodes or work with objects on the Chef server
_images/icon_repository.svg

The chef-repo is the repository structure in which cookbooks are authored, tested, and maintained:

  • Cookbooks contain recipes, attributes, custom resources, libraries, files, templates, tests, and metadata
  • The chef-repo should be synchronized with a version control system (such as git), and then managed as if it were source code

The directory structure within the chef-repo varies. Some organizations prefer to keep all of their cookbooks in a single chef-repo, while other organizations prefer to use a chef-repo for every cookbook.

_images/icon_kitchen.svg

Use Test Kitchen to automatically test cookbook data across any combination of platforms and test suites:

  • Defined in a .kitchen.yml file
  • Uses a driver plugin architecture
  • Supports cookbook testing across many cloud providers and virtualization technologies
  • Supports all common testing frameworks that are used by the Ruby community
  • Uses a comprehensive set of base images provided by Bento
_images/icon_chefspec.svg

Use ChefSpec to simulate the convergence of resources on a node:

  • Is an extension of RSpec, a behavior-driven development (BDD) framework for Ruby
  • Is the fastest way to test resources and recipes

Cookbooks

A cookbook is the fundamental unit of configuration and policy distribution. A cookbook defines a scenario and contains everything that is required to support that scenario:

  • Recipes that specify the resources to use and the order in which they are to be applied
  • Attribute values
  • File distributions
  • Templates
  • Extensions to Chef, such as custom resources and libraries

The chef-client uses Ruby as its reference language for creating cookbooks and defining recipes, with an extended DSL for specific resources. A reasonable set of resources are available to the chef-client, enough to support many of the most common infrastructure automation scenarios; however, this DSL can also be extended when additional resources and capabilities are required.

Components

Cookbooks are comprised of the following components:

Component Description
_images/icon_cookbook_attributes.svg
An attribute can be defined in a cookbook (or a recipe) and then used to override the default settings on a node. When a cookbook is loaded during a chef-client run, these attributes are compared to the attributes that are already present on the node. Attributes that are defined in attribute files are first loaded according to cookbook order. For each cookbook, attributes in the default.rb file are loaded first, and then additional attribute files (if present) are loaded in lexical sort order. When the cookbook attributes take precedence over the default attributes, the chef-client will apply those new settings and values during the chef-client run on the node.
_images/icon_cookbook_files.svg
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 chef-client. 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 sub-directory may be used on any platform.
_images/icon_cookbook_libraries.svg
A library allows arbitrary Ruby code to be included in a cookbook, either as a way of extending the classes that are built-in to the chef-client—Chef::Recipe, for example—or for implementing entirely new functionality, similar to a mixin in Ruby. A library file is a Ruby file that is located within a cookbook’s /libraries directory. Because a library is built using Ruby, anything that can be done with Ruby can be done in a library file.
_images/icon_cookbook_metadata.svg
Every cookbook requires a small amount of metadata. A file named metadata.rb is located at the top of every cookbook directory structure. The contents of the metadata.rb file provides hints to the Chef server to help ensure that cookbooks are deployed to each node correctly.
_images/icon_cookbook_recipes.svg
_images/icon_recipe_dsl.svg

A recipe is the most fundamental configuration element within the organization. A recipe:

  • Is authored using Ruby, which is a programming language designed to read and behave in a predictable manner
  • Is mostly a collection of resources, defined using patterns (resource names, attribute-value pairs, and actions); helper code is added around this using Ruby, when needed
  • Must define everything that is required to configure part of a system
  • Must be stored in a cookbook
  • May be included in a recipe
  • May use the results of a search query and read the contents of a data bag (including an encrypted data bag)
  • May have a dependency on one (or more) recipes
  • May tag a node to facilitate the creation of arbitrary groupings
  • Must be added to a run-list before it can be used by the chef-client
  • Is always executed in the same order as listed in a run-list

The chef-client will run a recipe only when asked. When the chef-client runs the same recipe more than once, the results will be the same system state each time. When a recipe is run against a system, but nothing has changed on either the system or in the recipe, the chef-client won’t change anything.

The Recipe DSL is a Ruby DSL that is primarily used to declare resources from within a recipe. The Recipe DSL also helps ensure that recipes interact with nodes (and node properties) in the desired manner. Most of the methods in the Recipe DSL are used to find a specific parameter and then tell the chef-client what action(s) to take, based on whether that parameter is present on a node.

_images/icon_cookbook_resources.svg

A resource is a statement of configuration policy that:

  • Describes the desired state for a configuration item
  • Declares the steps needed to bring that item to the desired state
  • Specifies a resource type—such as packagetemplate, or service
  • Lists additional details (also known as resource properties), as necessary
  • Are grouped into recipes, which describe working configurations

Chef has many built-in resources that cover all of the most common actions across all of the most common platforms. You can build your own resources to handle any situation that isn’t covered by a built-in resource.

_images/icon_cookbook_templates.svg
A cookbook template is an Embedded Ruby (ERB) template that is used to dynamically generate static text files. Templates may contain Ruby expressions and statements, and are a great way to manage configuration files. Use the template resource to add cookbook templates to recipes; place the corresponding Embedded Ruby (ERB) template file in a cookbook’s /templates directory.
_images/icon_cookbook_tests.svg
Testing cookbooks improves the quality of those cookbooks by ensuring they are doing what they are supposed to do and that they are authored in a consistent manner. Unit and integration testing validates the recipes in cookbooks. Syntax testing—often called linting—validates the quality of the code itself. The following tools are popular tools used for testing Chef recipes: Test Kitchen, ChefSpec, and Foodcritic.

Nodes

A node is any machine—physical, virtual, cloud, network device, etc.—that is under management by Chef.

Node Types

The types of nodes that can be managed by Chef include, but are not limited to, the following:

Node Type Description
_images/icon_node_type_server.svg
A physical node is typically a server or a virtual machine, but it can be any active device attached to a network that is capable of sending, receiving, and forwarding information over a communications channel. In other words, a physical node is any active device attached to a network that can run a chef-client and also allow that chef-client to communicate with a Chef server.
_images/icon_node_type_cloud_public.svg
A cloud-based node is hosted in an external cloud-based service, such as Amazon Web Services (AWS), OpenStack, Rackspace, Google Compute Engine, or Microsoft Azure. Plugins are available for knife that provide support for external cloud-based services. knife can use these plugins to create instances on cloud-based services. Once created, the chef-client can be used to deploy, configure, and maintain those instances.
_images/icon_node_virtual_machine.svg
A virtual node is a machine that runs only as a software implementation, but otherwise behaves much like a physical machine.
_images/icon_node_type_network_device.svg
A network node is any networking device—a switch, a router—that is being managed by a chef-client, such as networking devices by Juniper Networks, Arista, Cisco, and F5. Use Chef to automate common network configurations, such as physical and logical Ethernet link properties and VLANs, on these devices.
_images/icon_node_type_container.svg
Containers are an approach to virtualization that allows a single operating system to host many working configurations, where each working configuration—a container—is assigned a single responsibility that is isolated from all other responsibilities. Containers are popular as a way to manage distributed and scalable applications and services.

Chef on Nodes

The key components of nodes that are under management by Chef include:

Component Description
_images/icon_chef_client.svg

A chef-client is an agent that runs locally on every node that is under management by Chef. When a chef-client is run, it will perform all of the steps that are required to bring the node into the expected state, including:

  • Registering and authenticating the node with the Chef server
  • Building the node object
  • Synchronizing cookbooks
  • Compiling the resource collection by loading each of the required cookbooks, including recipes, attributes, and all other dependencies
  • Taking the appropriate and required actions to configure the node
  • Looking for exceptions and notifications, handling each as required

RSA public key-pairs are used to authenticate the chef-client with the Chef server every time a chef-client needs access to data that is stored on the Chef server. This prevents any node from accessing data that it shouldn’t and it ensures that only nodes that are properly registered with the Chef server can be managed.

_images/icon_ohai.svg

Ohai is a tool that is used to collect system configuration data, which is provided to the chef-client for use within cookbooks. Ohai is run by the chef-client at the beginning of every Chef run to determine system state. Ohai includes many built-in plugins to detect common configuration details as well as a plugin model for writing custom plugins.

The types of attributes Ohai collects include but are not limited to:

  • Operating System
  • Network
  • Memory
  • Disk
  • CPU
  • Kernel
  • Host names
  • Fully qualified domain names
  • Virtualization
  • Cloud provider metadata

Attributes that are collected by Ohai are automatic level attributes, in that these attributes are used by the chef-client to ensure that these attributes remain unchanged after the chef-client is done configuring the node.

The Chef Server

The Chef server acts as a hub for configuration data. The Chef server stores cookbooks, the policies that are applied to nodes, and metadata that describes each registered node that is being managed by the chef-client. Nodes use the chef-client to ask the Chef server for configuration details, such as recipes, templates, and file distributions. The chef-client then does as much of the configuration work as possible on the nodes themselves (and not on the Chef server). This scalable approach distributes the configuration effort throughout the organization.

Feature Description
_images/icon_search.svg
Search indexes allow queries to be made for any type of data that is indexed by the Chef server, including data bags (and data bag items), environments, nodes, and roles. A defined query syntax is used to support search patterns like exact, wildcard, range, and fuzzy. A search is a full-text query that can be done from several locations, including from within a recipe, by using the search subcommand in knife, the search method in the Recipe DSL, the search box in the Chef management console, and by using the /search or /search/INDEX endpoints in the Chef server API. The search engine is based on Apache Solr and is run from the Chef server.
_images/icon_manage.svg

Chef management console is a web-based interface for the Chef server that provides users a way to manage the following objects:

  • Nodes
  • Cookbooks and recipes
  • Roles
  • Stores of JSON data (data bags), including encrypted data
  • Environments
  • Searching of indexed data
  • User accounts and user data for the individuals who have permission to log on to and access the Chef server
_images/icon_data_bags.svg
A data bag is a global variable that is stored as JSON data and is accessible from a Chef server. A data bag is indexed for searching and can be loaded by a recipe or accessed during a search.
_images/icon_policy.svg
Policy defines how business and operational requirements, processes, and production workflows map to objects that are stored on the Chef server. Policy objects on the Chef server include roles, environments, and cookbook versions.

Policy

Policy maps business and operational requirements, process, and workflow to settings and objects stored on the Chef server:

  • Roles define server types, such as “web server” or “database server”
  • Environments define process, such as “dev”, “staging”, or “production”
  • Certain types of data—passwords, user account data, and other sensitive items—can be placed in data bags, which are located in a secure sub-area on the Chef server that can only be accessed by nodes that authenticate to the Chef server with the correct SSL certificates
  • The cookbooks (and cookbook versions) in which organization-specific configuration policies are maintained

Some important aspects of policy include:

Feature Description
_images/icon_roles.svg
A role is a way to define certain patterns and processes that exist across nodes in an organization as belonging to a single job function. Each role consists of zero (or more) attributes and a run-list. Each node can have zero (or more) roles assigned to it. When a role is run against a node, the configuration details of that node are compared against the attributes of the role, and then the contents of that role’s run-list are applied to the node’s configuration details. When a chef-client runs, it merges its own attributes and run-lists with those contained within each assigned role.
_images/icon_environments.svg
An environment is a way to map an organization’s real-life workflow to what can be configured and managed when using Chef server. Every organization begins with a single environment called the _default environment, which cannot be modified (or deleted). Additional environments can be created to reflect each organization’s patterns and workflow. For example, creating productionstagingtesting, and developmentenvironments. Generally, an environment is also associated with one (or more) cookbook versions.
_images/icon_cookbook_versions.svg

A cookbook version represents a set of functionality that is different from the cookbook on which it is based. A version may exist for many reasons, such as ensuring the correct use of a third-party component, updating a bug fix, or adding an improvement. A cookbook version is defined using syntax and operators, may be associated with environments, cookbook metadata, and/or run-lists, and may be frozen (to prevent unwanted updates from being made).

A cookbook version is maintained just like a cookbook, with regard to source control, uploading it to the Chef server, and how the chef-client applies that cookbook when configuring nodes.

_images/icon_run_lists.svg

A run-list defines all of the information necessary for Chef to configure a node into the desired state. A run-list is:

  • An ordered list of roles and/or recipes that are run in the exact order defined in the run-list; if a recipe appears more than once in the run-list, the chef-client will not run it twice
  • Always specific to the node on which it runs; nodes may have a run-list that is identical to the run-list used by other nodes
  • Stored as part of the node object on the Chef server
  • Maintained using knife, and then uploaded from the workstation to the Chef server, or is maintained using the Chef management console

Chef: ChefDK

chefdk1chefdk2chefdk3chefdk4

  1. Create a linux machine, login into it and execute the following command:
    curl -s https://omnitruck.chef.io/install.sh | sudo bash -s — -P chefdk
  2. Now we need to change the default ruby to point it to the chef ruby and not the system ruby. Execute the following command for it.
    echo ‘eval “$(chef shell-init bash)”‘ >> ~/.bash_profileNote:eval is part of POSIX. Its an interface which can be a shell built-in.Its described in the “POSIX Programmer’s Manual”: http://www.unix.com/man-page/posix/1posix/eval/

    eval - construct command by concatenating arguments

    It will take an argument and construct a command of it, which will be executed by the shell. This is the example of the manpage:

    1) foo=10 x=foo
    2) y='$'$x
    3) echo $y
    4) $foo
    5) eval y='$'$x
    6) echo $y
    7) 10
    1. In the first line you define $foo with the value '10' and $x with the value 'foo'.
    2. Now define $y, which consists of the string '$foo'. The dollar sign must be escaped with '$'.
    3. To check the result, echo $y.
    4. The result will be the string '$foo'
    5. Now we repeat the assignment with eval. It will first evaluate $x to the string 'foo'. Now we have the statement y=$foo which will get evaluated to y=10.
    6. The result of echo $y is now the value '10'.

    This is a common function in many languages, e.g. Perl and JavaScript.

  3. The chef shell-init bash command ouputs as follows:
    export PATH=”/opt/chefdk/bin:/root/.chefdk/gem/ruby/2.4.0/bin:/opt/chefdk/embedded/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/chefdk/gitbin”
    export GEM_ROOT=”/opt/chefdk/embedded/lib/ruby/gems/2.4.0″
    export GEM_HOME=”/root/.chefdk/gem/ruby/2.4.0″
    export GEM_PATH=”/root/.chefdk/gem/ruby/2.4.0:/opt/chefdk/embedded/lib/ruby/gems/2.4.0″
    _chef_comp() {
    local COMMANDS=”exec env gem generate shell-init install update push push-archive show-policy diff provision export clean-policy-revisions clean-policy-cookbooks delete-policy-group delete-policy undelete verify”
    COMPREPLY=($(compgen -W “$COMMANDS” — ${COMP_WORDS[COMP_CWORD]} ))
    }
    complete -F _chef_comp chef
    Thus eval command will execute the above arguments as a command and set all the necessary variables.
  4. We then add these variables in .bash_profile file so that it is loaded for all the shell termnals. So load the .bash_profile by executing source ~/.bash_profile
    Check by executing which chef and which ruby
  5.  Execute  chef -v to check chef version. Output will be as follows:
    chef-client version: 13.4.19
    delivery version: master (73ebb72a6c42b3d2ff5370c476be800fee7e5427)
    berks version: 6.3.1
    kitchen version: 1.17.0
    inspec version: 1.36.1
  6. Then execute the following:
    yum install -y git yum-utils
  7. Then configure git name and email:
    git config –global user.name “Arati”
    git config –global user.email “aratik711@gmail.com”
    git config –global core.editor vi
    git config –global color.ui auto
  8. Add the docker repo with the following command:
    yum-config-manager –add-repo https://download.docker.com/linux/centos/docker-ce.repo
    yum makecache fast
  9. Install docker container Engine with the following command:
    yum -y install docker-ce
  10. Enable and start the docker service:
    systemctl enable docker
    systemctl start docker
  11. If you are not using the root user you will need to add your user to the docker group to execute docker commands:
    sudo usermod -aG docker $USER
  12. So as to avoid the systemd issue that occurs in the containers we will have to stop and disable the getty@tty1 service.
    getty is the generic name for a program which manages a terminal line and its connected terminal. Its purpose is to protect the system from unauthorized access. Generally, each getty process is started by systemd and manages a single terminal line.
    sudo systemctl stop getty@tty1.service
    sudo systemctl mask getty@tty1.service
    Create a test network:
    docker network create –subnet=10.1.1.0/24 testnet
  13. Then install docker driver so that the test-kitchen can use it:
    gem install kitchen-docker
    You might get an error as follows:

    Fetching: mixlib-shellout-2.3.2.gem (100%)
    ERROR:  Error installing kitchen-docker:
    	mixlib-shellout requires Ruby version >= 2.2.

    Then install the individual dependencies with the following commands:

    gem install mixlib-shellout -v 2.2.7
    
    gem install test-kitchen -v 1.16.0
    
    gem install kitchen-docker

Chef: Nodes and Search

node1node2

    1. Now login to your chef-node/chef-client and type ohai. Ohai is automatically bootstraped when we install chef.
      You will get an output similar to below:
      ……
      “OPEN_MAX”: 1024,
      “PAGESIZE”: 4096,
      “PAGE_SIZE”: 4096,
      “PASS_MAX”: 8192,
      “PTHREAD_DESTRUCTOR_ITERATIONS”: 4,
      “PTHREAD_KEYS_MAX”: 1024,
      “PTHREAD_STACK_MIN”: 16384,
      “PTHREAD_THREADS_MAX”: null,
      “SCHAR_MAX”: 127,
      “SCHAR_MIN”: -128,
      “SHRT_MAX”: 32767,
      “SHRT_MIN”: -32768,
      “SSIZE_MAX”: 32767,
      “TTY_NAME_MAX”: 32,
      “TZNAME_MAX”: 6,
      “UCHAR_MAX”: 255,
      “UINT_MAX”: 4294967295,
      “UIO_MAXIOV”: 1024,
      “ULONG_MAX”: 18446744073709551615,
      “USHRT_MAX”: 65535,
      “WORD_BIT”: 32,
      “_AVPHYS_PAGES”: 768366,
      “_NPROCESSORS_CONF”: 2,
      “_NPROCESSORS_ONLN”: 2,
      “_PHYS_PAGES”: 970577,
      “_POSIX_ARG_MAX”: 2097152,
      “_POSIX_ASYNCHRONOUS_IO”: 200809,
      “_POSIX_CHILD_MAX”: 15019,
      “_POSIX_FSYNC”: 200809,
      “_POSIX_JOB_CONTROL”: 1,
      “_POSIX_MAPPED_FILES”: 200809,
      “_POSIX_MEMLOCK”: 200809,
      “_POSIX_MEMLOCK_RANGE”: 200809,
      “_POSIX_MEMORY_PROTECTION”: 200809,
      “_POSIX_MESSAGE_PASSING”: 200809,
      “_POSIX_NGROUPS_MAX”: 65536,
      “_POSIX_OPEN_MAX”: 1024,
      “_POSIX_PII”: null,
      “_POSIX_PII_INTERNET”: null,
      “_POSIX_PII_INTERNET_DGRAM”: null,
      “_POSIX_PII_INTERNET_STREAM”: null,
      “_POSIX_PII_OSI”: null,
      “_POSIX_PII_OSI_CLTS”: null,
      “_POSIX_PII_OSI_COTS”: null,
      “_POSIX_PII_OSI_M”: null,
      “_POSIX_PII_SOCKET”: null,
      “_POSIX_PII_XTI”: null,
      “_POSIX_POLL”: null,
      “_POSIX_PRIORITIZED_IO”: 200809,
      “_POSIX_PRIORITY_SCHEDULING”: 200809,
      “_POSIX_REALTIME_SIGNALS”: 200809,
      “_POSIX_SAVED_IDS”: 1,
      “_POSIX_SELECT”: null,
      “_POSIX_SEMAPHORES”: 200809,
      “_POSIX_SHARED_MEMORY_OBJECTS”: 200809,
      “_POSIX_SSIZE_MAX”: 32767,
      “_POSIX_STREAM_MAX”: 16,
      “_POSIX_SYNCHRONIZED_IO”: 200809,
      “_POSIX_THREADS”: 200809,
      “_POSIX_THREAD_ATTR_STACKADDR”: 200809,
      “_POSIX_THREAD_ATTR_STACKSIZE”: 200809,
      “_POSIX_THREAD_PRIORITY_SCHEDULING”: 200809,
      “_POSIX_THREAD_PRIO_INHERIT”: 200809,
      “_POSIX_THREAD_PRIO_PROTECT”: 200809,
      “_POSIX_THREAD_ROBUST_PRIO_INHERIT”: null,
      “_POSIX_THREAD_ROBUST_PRIO_PROTECT”: null,
      “_POSIX_THREAD_PROCESS_SHARED”: 200809,
      “_POSIX_THREAD_SAFE_FUNCTIONS”: 200809,
      “_POSIX_TIMERS”: 200809,
      “TIMER_MAX”: null,
      “_POSIX_TZNAME_MAX”: 6,
      “_POSIX_VERSION”: 200809,
      “_T_IOV_MAX”: null,
      “_XOPEN_CRYPT”: 1,
      “_XOPEN_ENH_I18N”: 1,
      “_XOPEN_LEGACY”: 1,
      “_XOPEN_REALTIME”: 1,
      “_XOPEN_REALTIME_THREADS”: 1,
      “_XOPEN_SHM”: 1,
      “_XOPEN_UNIX”: 1,
      “_XOPEN_VERSION”: 700,
      “_XOPEN_XCU_VERSION”: 4,
      “_XOPEN_XPG2”: 1,
      “_XOPEN_XPG3”: 1,
      “_XOPEN_XPG4”: 1,
      “BC_BASE_MAX”: 99,
      “BC_DIM_MAX”: 2048,
      “BC_SCALE_MAX”: 99,
      “BC_STRING_MAX”: 1000,
      “CHARCLASS_NAME_MAX”: 2048,
      “COLL_WEIGHTS_MAX”: 255,
      “EQUIV_CLASS_MAX”: null,
      “EXPR_NEST_MAX”: 32,
      “LINE_MAX”: 2048,
      “POSIX2_BC_BASE_MAX”: 99,
      “POSIX2_BC_DIM_MAX”: 2048,
      “POSIX2_BC_SCALE_MAX”: 99,
      “POSIX2_BC_STRING_MAX”: 1000,
      “POSIX2_CHAR_TERM”: 200809,
      “POSIX2_COLL_WEIGHTS_MAX”: 255,
      “POSIX2_C_BIND”: 200809,
      “POSIX2_C_DEV”: 200809,
      “POSIX2_C_VERSION”: null,
      “POSIX2_EXPR_NEST_MAX”: 32,
      “POSIX2_FORT_DEV”: null,
      “POSIX2_FORT_RUN”: null,
      “_POSIX2_LINE_MAX”: 2048,
      “POSIX2_LINE_MAX”: 2048,
      “POSIX2_LOCALEDEF”: 200809,
      “POSIX2_RE_DUP_MAX”: 32767,
      “POSIX2_SW_DEV”: 200809,
      “POSIX2_UPE”: null,
      “POSIX2_VERSION”: 200809,
      “RE_DUP_MAX”: 32767,
      “PATH”: “/usr/bin”,
      “CS_PATH”: “/usr/bin”,
      “LFS_CFLAGS”: null,
      “LFS_LDFLAGS”: null,
      “LFS_LIBS”: null,
      “LFS_LINTFLAGS”: null,
      “LFS64_CFLAGS”: “-D_LARGEFILE64_SOURCE”,
      “LFS64_LDFLAGS”: null,
      “LFS64_LIBS”: null,
      “LFS64_LINTFLAGS”: “-D_LARGEFILE64_SOURCE”,
      “_XBS5_WIDTH_RESTRICTED_ENVS”: “XBS5_LP64_OFF64”,
      “XBS5_WIDTH_RESTRICTED_ENVS”: “XBS5_LP64_OFF64”,
      “_XBS5_ILP32_OFF32”: null,
      “XBS5_ILP32_OFF32_CFLAGS”: null,
      “XBS5_ILP32_OFF32_LDFLAGS”: null,
      “XBS5_ILP32_OFF32_LIBS”: null,
      “XBS5_ILP32_OFF32_LINTFLAGS”: null,
      “_XBS5_ILP32_OFFBIG”: null,
      “XBS5_ILP32_OFFBIG_CFLAGS”: null,
      “XBS5_ILP32_OFFBIG_LDFLAGS”: null,
      “XBS5_ILP32_OFFBIG_LIBS”: null,
      “XBS5_ILP32_OFFBIG_LINTFLAGS”: null,
      “_XBS5_LP64_OFF64”: 1,
      “XBS5_LP64_OFF64_CFLAGS”: “-m64”,
      “XBS5_LP64_OFF64_LDFLAGS”: “-m64”,
      “XBS5_LP64_OFF64_LIBS”: null,
      “XBS5_LP64_OFF64_LINTFLAGS”: null,
      “_XBS5_LPBIG_OFFBIG”: null,
      “XBS5_LPBIG_OFFBIG_CFLAGS”: null,
      “XBS5_LPBIG_OFFBIG_LDFLAGS”: null,
      “XBS5_LPBIG_OFFBIG_LIBS”: null,
      “XBS5_LPBIG_OFFBIG_LINTFLAGS”: null,
      “_POSIX_V6_ILP32_OFF32”: null,
      “POSIX_V6_ILP32_OFF32_CFLAGS”: null,
      “POSIX_V6_ILP32_OFF32_LDFLAGS”: null,
      “POSIX_V6_ILP32_OFF32_LIBS”: null,
      “POSIX_V6_ILP32_OFF32_LINTFLAGS”: null,
      “_POSIX_V6_WIDTH_RESTRICTED_ENVS”: “POSIX_V6_LP64_OFF64”,
      “POSIX_V6_WIDTH_RESTRICTED_ENVS”: “POSIX_V6_LP64_OFF64”,
      “_POSIX_V6_ILP32_OFFBIG”: null,
      “POSIX_V6_ILP32_OFFBIG_CFLAGS”: null,
      “POSIX_V6_ILP32_OFFBIG_LDFLAGS”: null,
      “POSIX_V6_ILP32_OFFBIG_LIBS”: null,
      “POSIX_V6_ILP32_OFFBIG_LINTFLAGS”: null,
      “_POSIX_V6_LP64_OFF64”: 1,
      “POSIX_V6_LP64_OFF64_CFLAGS”: “-m64”,
      “POSIX_V6_LP64_OFF64_LDFLAGS”: “-m64”,
      “POSIX_V6_LP64_OFF64_LIBS”: null,
      “POSIX_V6_LP64_OFF64_LINTFLAGS”: null,
      “_POSIX_V6_LPBIG_OFFBIG”: null,
      “POSIX_V6_LPBIG_OFFBIG_CFLAGS”: null,
      “POSIX_V6_LPBIG_OFFBIG_LDFLAGS”: null,
      “POSIX_V6_LPBIG_OFFBIG_LIBS”: null,
      “POSIX_V6_LPBIG_OFFBIG_LINTFLAGS”: null,
      “_POSIX_V7_ILP32_OFF32”: null,
      “POSIX_V7_ILP32_OFF32_CFLAGS”: null,
      “POSIX_V7_ILP32_OFF32_LDFLAGS”: null,
      “POSIX_V7_ILP32_OFF32_LIBS”: null,
      “POSIX_V7_ILP32_OFF32_LINTFLAGS”: null,
      “_POSIX_V7_WIDTH_RESTRICTED_ENVS”: “POSIX_V7_LP64_OFF64”,
      “POSIX_V7_WIDTH_RESTRICTED_ENVS”: “POSIX_V7_LP64_OFF64”,
      “_POSIX_V7_ILP32_OFFBIG”: null,
      “POSIX_V7_ILP32_OFFBIG_CFLAGS”: null,
      “POSIX_V7_ILP32_OFFBIG_LDFLAGS”: null,
      “POSIX_V7_ILP32_OFFBIG_LIBS”: null,
      “POSIX_V7_ILP32_OFFBIG_LINTFLAGS”: null,
      “_POSIX_V7_LP64_OFF64”: 1,
      “POSIX_V7_LP64_OFF64_CFLAGS”: “-m64”,
      “POSIX_V7_LP64_OFF64_LDFLAGS”: “-m64”,
      “POSIX_V7_LP64_OFF64_LIBS”: null,
      “POSIX_V7_LP64_OFF64_LINTFLAGS”: null,
      “_POSIX_V7_LPBIG_OFFBIG”: null,
      “POSIX_V7_LPBIG_OFFBIG_CFLAGS”: null,
      “POSIX_V7_LPBIG_OFFBIG_LDFLAGS”: null,
      “POSIX_V7_LPBIG_OFFBIG_LIBS”: null,
      “POSIX_V7_LPBIG_OFFBIG_LINTFLAGS”: null,
      “_POSIX_ADVISORY_INFO”: 200809,
      “_POSIX_BARRIERS”: 200809,
      “_POSIX_BASE”: null,
      “_POSIX_C_LANG_SUPPORT”: null,
      “_POSIX_C_LANG_SUPPORT_R”: null,
      “_POSIX_CLOCK_SELECTION”: 200809,
      “_POSIX_CPUTIME”: 200809,
      “_POSIX_THREAD_CPUTIME”: 200809,
      “_POSIX_DEVICE_SPECIFIC”: null,
      “_POSIX_DEVICE_SPECIFIC_R”: null,
      “_POSIX_FD_MGMT”: null,
      “_POSIX_FIFO”: null,
      “_POSIX_PIPE”: null,
      “_POSIX_FILE_ATTRIBUTES”: null,
      “_POSIX_FILE_LOCKING”: null,
      “_POSIX_FILE_SYSTEM”: null,
      “_POSIX_MONOTONIC_CLOCK”: 200809,
      “_POSIX_MULTI_PROCESS”: null,
      “_POSIX_SINGLE_PROCESS”: null,
      “_POSIX_NETWORKING”: null,
      “_POSIX_READER_WRITER_LOCKS”: 200809,
      “_POSIX_SPIN_LOCKS”: 200809,
      “_POSIX_REGEXP”: 1,
      “_REGEX_VERSION”: null,
      “_POSIX_SHELL”: 1,
      “_POSIX_SIGNALS”: null,
      “_POSIX_SPAWN”: 200809,
      “_POSIX_SPORADIC_SERVER”: null,
      “_POSIX_THREAD_SPORADIC_SERVER”: null,
      “_POSIX_SYSTEM_DATABASE”: null,
      “_POSIX_SYSTEM_DATABASE_R”: null,
      “_POSIX_TIMEOUTS”: 200809,
      “_POSIX_TYPED_MEMORY_OBJECTS”: null,
      “_POSIX_USER_GROUPS”: null,
      “_POSIX_USER_GROUPS_R”: null,
      “POSIX2_PBS”: null,
      “POSIX2_PBS_ACCOUNTING”: null,
      “POSIX2_PBS_LOCATE”: null,
      “POSIX2_PBS_TRACK”: null,
      “POSIX2_PBS_MESSAGE”: null,
      “SYMLOOP_MAX”: null,
      “STREAM_MAX”: 16,
      “AIO_LISTIO_MAX”: null,
      “AIO_MAX”: null,
      “AIO_PRIO_DELTA_MAX”: 20,
      “DELAYTIMER_MAX”: 2147483647,
      “HOST_NAME_MAX”: 64,
      “LOGIN_NAME_MAX”: 256,
      “MQ_OPEN_MAX”: null,
      “MQ_PRIO_MAX”: 32768,
      “_POSIX_DEVICE_IO”: null,
      “_POSIX_TRACE”: null,
      “_POSIX_TRACE_EVENT_FILTER”: null,
      “_POSIX_TRACE_INHERIT”: null,
      “_POSIX_TRACE_LOG”: null,
      “RTSIG_MAX”: 32,
      “SEM_NSEMS_MAX”: null,
      “SEM_VALUE_MAX”: 2147483647,
      “SIGQUEUE_MAX”: 15019,
      “FILESIZEBITS”: 64,
      “POSIX_ALLOC_SIZE_MIN”: 4096,
      “POSIX_REC_INCR_XFER_SIZE”: null,
      “POSIX_REC_MAX_XFER_SIZE”: null,
      “POSIX_REC_MIN_XFER_SIZE”: 4096,
      “POSIX_REC_XFER_ALIGN”: 4096,
      “SYMLINK_MAX”: null,
      “GNU_LIBC_VERSION”: “glibc 2.17”,
      “GNU_LIBPTHREAD_VERSION”: “NPTL 2.17”,
      “POSIX2_SYMLINKS”: 1,
      “LEVEL1_ICACHE_SIZE”: 32768,
      “LEVEL1_ICACHE_ASSOC”: 8,
      “LEVEL1_ICACHE_LINESIZE”: 64,
      “LEVEL1_DCACHE_SIZE”: 32768,
      “LEVEL1_DCACHE_ASSOC”: 8,
      “LEVEL1_DCACHE_LINESIZE”: 64,
      “LEVEL2_CACHE_SIZE”: 2097152,
      “LEVEL2_CACHE_ASSOC”: 8,
      “LEVEL2_CACHE_LINESIZE”: 64,
      “LEVEL3_CACHE_SIZE”: 0,
      “LEVEL3_CACHE_ASSOC”: 0,
      “LEVEL3_CACHE_LINESIZE”: 0,
      “LEVEL4_CACHE_SIZE”: 0,
      “LEVEL4_CACHE_ASSOC”: 0,
      “LEVEL4_CACHE_LINESIZE”: 0,
      “IPV6”: 200809,
      “RAW_SOCKETS”: 200809
      },
      “time”: {
      “timezone”: “UTC”
      }
      }
      It gives information about our node.
    2. Suppose if I want to retrieve the ipaddress of node then we can execute the command:
      ohai ipaddressOutput will be as follows:
      [
      “192.168.1.240”
      ]
      We can use these attributes in our code.
      ohai hostname
      [
      “chef-node”
      ]
      ohai | grep ipaddress
      “ipaddress”: “192.168.1.240”
      ohai cpu
      {
      “0”: {
      “vendor_id”: “GenuineIntel”,
      “family”: “6”,
      “model”: “61”,
      “model_name”: “Intel Core Processor (Broadwell)”,
      “stepping”: “2”,
      “mhz”: “2095.146”,
      “cache_size”: “4096 KB”,
      “physical_id”: “0”,
      “core_id”: “0”,
      “cores”: “1”,
      “flags”: [
      “fpu”,
      “vme”,
      “de”,
      “pse”,
      “tsc”,
      “msr”,
      “pae”,
      “mce”,
      “cx8”,
      “apic”,
      “sep”,
      “mtrr”,
      “pge”,
      “mca”,
      “cmov”,
      “pat”,
      “pse36”,
      “clflush”,
      “mmx”,
      “fxsr”,
      “sse”,
      “sse2”,
      “ss”,
      “syscall”,
      “nx”,
      “pdpe1gb”,
      “rdtscp”,
      “lm”,
      “constant_tsc”,
      “rep_good”,
      “nopl”,
      “eagerfpu”,
      “pni”,
      “pclmulqdq”,
      “vmx”,
      “ssse3”,
      “fma”,
      “cx16”,
      “pcid”,
      “sse4_1”,
      “sse4_2”,
      “x2apic”,
      “movbe”,
      “popcnt”,
      “tsc_deadline_timer”,
      “aes”,
      “xsave”,
      “avx”,
      “f16c”,
      “rdrand”,
      “hypervisor”,
      “lahf_lm”,
      “abm”,
      “3dnowprefetch”,
      “arat”,
      “tpr_shadow”,
      “vnmi”,
      “flexpriority”,
      “ept”,
      “vpid”,
      “fsgsbase”,
      “bmi1”,
      “hle”,
      “avx2”,
      “smep”,
      “bmi2”,
      “erms”,
      “invpcid”,
      “rtm”,
      “rdseed”,
      “adx”,
      “smap”,
      “xsaveopt”
      ]
      },
      “1”: {
      “vendor_id”: “GenuineIntel”,
      “family”: “6”,
      “model”: “61”,
      “model_name”: “Intel Core Processor (Broadwell)”,
      “stepping”: “2”,
      “mhz”: “2095.146”,
      “cache_size”: “4096 KB”,
      “physical_id”: “1”,
      “core_id”: “0”,
      “cores”: “1”,
      “flags”: [
      “fpu”,
      “vme”,
      “de”,
      “pse”,
      “tsc”,
      “msr”,
      “pae”,
      “mce”,
      “cx8”,
      “apic”,
      “sep”,
      “mtrr”,
      “pge”,
      “mca”,
      “cmov”,
      “pat”,
      “pse36”,
      “clflush”,
      “mmx”,
      “fxsr”,
      “sse”,
      “sse2”,
      “ss”,
      “syscall”,
      “nx”,
      “pdpe1gb”,
      “rdtscp”,
      “lm”,
      “constant_tsc”,
      “rep_good”,
      “nopl”,
      “eagerfpu”,
      “pni”,
      “pclmulqdq”,
      “vmx”,
      “ssse3”,
      “fma”,
      “cx16”,
      “pcid”,
      “sse4_1”,
      “sse4_2”,
      “x2apic”,
      “movbe”,
      “popcnt”,
      “tsc_deadline_timer”,
      “aes”,
      “xsave”,
      “avx”,
      “f16c”,
      “rdrand”,
      “hypervisor”,
      “lahf_lm”,
      “abm”,
      “3dnowprefetch”,
      “arat”,
      “tpr_shadow”,
      “vnmi”,
      “flexpriority”,
      “ept”,
      “vpid”,
      “fsgsbase”,
      “bmi1”,
      “hle”,
      “avx2”,
      “smep”,
      “bmi2”,
      “erms”,
      “invpcid”,
      “rtm”,
      “rdseed”,
      “adx”,
      “smap”,
      “xsaveopt”
      ]
      },
      “total”: 2,
      “real”: 2,
      “cores”: 2
      }
      ohai platform
      [
      “centos”
      ]
      ohai platform_family

      [
      “rhel”
      ]

    3. Lets edit the apache cookbook we created in previous post.
      Edit default.rb

      if node['platform_family'] == "rhel"
              package = "httpd"
      elsif node['platform_family'] == "debian"
              package = "apache2"
      end
      
      package 'apache2' do
              package_name package
              action :install
      end
      
      service 'apache2' do
              service_name package
              action [:start, :enable]
      end
      
      
    4. Now create a recipe motd.rb with the following content:
      
      hostname = node['hostname']
      file '/etc/motd' do
              content "Hostname is this #{hostname}"
      end
      
      

      Add the code to git repo. Then upload the cookbook to chef-server. Then add the recipe to the run_list with the command:
      knife node run_list add chef-node ‘recipe[motd]’

    5. Now if you run chef-client then you will get the following error:
      Error Resolving Cookbooks for Run List:
      ================================================================================

      Missing Cookbooks:
      ——————
      The following cookbooks are required by the client but don’t exist on the server
      * motd

      We called motd but motd is not a cookbook it is a recipe inside the apache cookbook.
      Now go ahead and remove the recipe from run_list.
      knife node run_list remove chef-node ‘recipe[motd]’
      Then add the recipe as:
      knife node run_list add chef-node ‘recipe[apache::motd]’

    6. Then run the chef-client the motd recipe will be executed. View the contents of /etc/motd you will see the content updated there.

Search

search1.png

search2.png

search3search4

search5

search6

Execute the following command to find nodes having platform_family as rhel

knife search ‘platform_family:rhel’
Output:

Environment: _default
FQDN:
IP: 192.168.1.240
Run List: recipe[apache::websites], recipe[apache], recipe[apache::motd]
Roles:
Recipes: apache::websites, apache, apache::default, apache::motd
Platform: centos 7.2.1511
Tags:


Execute the following command to find nodes having recipes:apache
knife search ‘recipes:apache’

To find the recipe websites in cookbook apache:
knife search ‘recipes:apache\:\:websites’
knife search ‘recipes:apache\:\:websites*’

If you want to retrieve a list of hostnames of the nodes which have platform of centos:
knife search ‘platfor?:centos’ -a hostname
With -a we are specifying the attribute we want.

If you want to list all nodes:
knife search ‘*:*’

If you want to search the nodes with role web:
knife search role ‘role:web’
You can also execute the following:
knife search ‘*.*’ -a recipes

 

Install and configure chef server on centos 7

  1. Go to this link: https://downloads.chef.io/chef-server
  2. In the on-premise section select your OS and download your package.
  3. Here I will be using centos 7. When the rpm is downloaded you can install it via the command:
    sudo rpm -Uvh
  4. Execute the following command: chef-server-ctl reconfigure
    Because the Chef server is composed of many different services that work together to create a functioning system, this step may take a few minutes to complete.
  5. Run the following command to create an administrator:
    $ chef-server-ctl user-create USER_NAME FIRST_NAME LAST_NAME EMAIL 'PASSWORD' --filename FILE_NAME
    

    An RSA private key is generated automatically. This is the user’s private key and should be saved to a safe location. The --filename option will save the RSA private key to the specified absolute path.

    For example:

    $ chef-server-ctl user-create stevedanno Steve Danno steved@chef.io 'abc123' --filename /path/to/stevedanno.pem

    If you get the following error:

    Specified config file /etc/opscode/pivotal.rb does not exist

    Then check if you have RAM available. Free some memory and rerun the

    chef-server-ctl reconfigure

  6. If you get following error: /users resource does not exist

    Then check the chef logs with following command:

    chef-server-ctl tail

    You might see an error similar to the following:
    ==> /var/log/opscode/nginx/error.log <==
    2017/09/08 11:38:28 [emerg] 29689#0: bind() to 0.0.0.0:80 failed (98: Address already in use)
    2017/09/08 11:38:28 [emerg] 29689#0: bind() to 0.0.0.0:443 failed (98: Address already in use).

    Then execute the following command:
    netstat -ntlp | grep 80
    Check which service is using the port 80 and 443. Majorly it is the httpd service. Stop the httpd service. Then the chef nginx service will start automatically without any issues.

    Then execute the create-user command it will get executed without any error.

  7. Run the following command to create an organization:
    $ chef-server-ctl org-create short_name 'full_organization_name' --association_user user_name --filename ORGANIZATION-validator.pem
    

    The name must begin with a lower-case letter or digit, may only contain lower-case letters, digits, hyphens, and underscores, and must be between 1 and 255 characters. For example: 4thcoffee.

    The full name must begin with a non-white space character and must be between 1 and 1023 characters. For example: 'Fourth Coffee, Inc.'.

    The --association_user option will associate the user_name with the admins security group on the Chef server.

    An RSA private key is generated automatically. This is the chef-validator key and should be saved to a safe location. The --filename option will save the RSA private key to the specified absolute path.

    For example:

    $ chef-server-ctl org-create 4thcoffee 'Fourth Coffee, Inc.' --association_user stevedanno --filename /path/to/4thcoffee-validator.pem
    
  8. Enable additional features of the Chef server! The packages may be downloaded directly as part of the installation process or they may be first downloaded to a local directory, and then installed.Use DownloadsThe install subcommand downloads packages from https://packages.chef.io/ by default. For systems that are not behind a firewall (and have connectivity to https://packages.chef.io/), these packages can be installed as described below.
    Feature Command
    Chef Manage

    Use Chef management console to manage data bags, attributes, run-lists, roles, environments, and cookbooks from a web user interface.

    On the Chef server, run:

    $ chef-server-ctl install chef-manage
    

    then:

    $ chef-server-ctl reconfigure
    

    and then:

    $ chef-manage-ctl reconfigure
    

    Note

    Starting with the Chef management console 2.3.0, the Chef MLSA must be accepted when reconfiguring the product. If the Chef MLSA has not already been accepted, the reconfigure process will prompt for a yes to accept it. Or run chef-manage-ctl reconfigure --accept-license to automatically accept the license.

  9. Open the chef-manage UI in the browser with https:///login
    Login with the credentials of the user you just created in the above step.
    On the nodes panel if you see the following error:  Error An error occurred, please try again
    Then look at the chef logs with the command chef-server-ctl tail
    The error will be majorly with the nginx. The error that I was facing was as follows:
    FAILED SocketConnector@127.0.0.1:8983: java.net.BindException: Address already in use (Bind failed). The issue was that solr service was already running on my server before installing chef. I had to stop the solr service, the issue was resolved. I was able to see the nodes panel without any error.2017-09-11 11_03_01-Mail
  10. Chef Push Jobs

    Use Chef push jobs to run jobs—an action or a command to be executed—against nodes independently of a chef-client run.

    On the Chef server, run:

    $ chef-server-ctl install opscode-push-jobs-server
    

    then:

    $ chef-server-ctl reconfigure
    

    and then:

    $ opscode-push-jobs-server-ctl reconfigure
  11. Reporting

    Use Reporting to keep track of what happens during every chef-client runs across all of the infrastructure being managed by Chef. Run Reporting with Chef management console to view reports from a web user interface.

    On the Chef server, run:

    $ chef-server-ctl install opscode-reporting
    

    then:

    $ chef-server-ctl reconfigure
    

    and then:

    $ opscode-reporting-ctl reconfigure
  12. If you want to login into postgres database of chef and see the data present in there execute the following command:
    chef-server-ctl psql
    You will get an output similar to:
    [ERROR] You must supply a service name. Valid names include: bifrost, bookshelf, oc-id, oc_erchef, oc_id, opscode-erchef, opscode_chef, push-jobs, reporting
    This is the list of databases you can login and see the data from.
    The main database where the chef data is present is opscode-erchef (previously opscode_chef). You can login to the database with the following command:
    chef-server-ctl psql opscode-erchef
    To see the tables in the database execute the following psql command:
    \dt
    This will give you a list as below:
    Schema | Name | Type | Owner
    ——–+——————————————–+——-+—————
    public | checksums | table | opscode-pgsql
    public | clients | table | opscode-pgsql
    public | containers | table | opscode-pgsql
    public | cookbook_artifact_version_checksums | table | opscode-pgsql
    public | cookbook_artifact_versions | table | opscode-pgsql
    public | cookbook_artifacts | table | opscode-pgsql
    public | cookbook_version_checksums | table | opscode-pgsql
    public | cookbook_versions | table | opscode-pgsql
    public | cookbooks | table | opscode-pgsql
    public | data_bag_items | table | opscode-pgsql
    public | data_bags | table | opscode-pgsql
    public | environments | table | opscode-pgsql
    public | groups | table | opscode-pgsql
    public | keys | table | opscode-pgsql
    public | node_policy | table | opscode-pgsql
    public | nodes | table | opscode-pgsql
    public | opc_customers | table | opscode-pgsql
    public | opc_users | table | opscode-pgsql
    public | org_migration_state | table | opscode-pgsql
    public | org_user_associations | table | opscode-pgsql
    public | org_user_invites | table | opscode-pgsql
    public | orgs | table | opscode-pgsql
    public | policies | table | opscode-pgsql
    public | policy_groups | table | opscode-pgsql
    public | policy_revisions | table | opscode-pgsql
    public | policy_revisions_policy_groups_association | table | opscode-pgsql
    public | roles | table | opscode-pgsql
    public | sandboxed_checksums | table | opscode-pgsql
    public | users | table | opscode-pgsqlYou can see the data in every table with the follwoing command:
    select * from <table-name>;
  13. If you want to see all the settings and configurations chef is using you can see the file:
    vi /etc/opscode/chef-server-running.json
  14. Find chef version:
    head -n1 /opt/opscode/version-manifest.txt
  15. Go to the chef dashboard -> Administration-> Organizations-> Starter Kit – > download starter kit.
    unzip chef-starter.zip
    Then unzip the starter kit in workstation. You can also use your chef server for this purpose. A chef-repo directory will be created.
    cd chef-repo/.chef
    cat knife.rb
    Check the configurations in knife.rb file.
  16. Install chefdk
    rpm -ivh https://packages.chef.io/files/stable/chefdk/2.2.1/el/7/chefdk-2.2.1-1.el7.x86_64.rpm
  17. Execute the following command
    knife ssl fetch 
    If you get an permission denied error then execute the command with sudo privileges.
    After execuing the above command you will get an output similar to the above:
    WARNING: Certificates from vrushabh.novalocal will be fetched and placed in your trusted_cert
    directory (/root/chef-repo/.chef/trusted_certs)……
  18. Knife is used to create cookbooks and to upload the cookbooks to chef server, upload roles, runlist etc.
    Knife allows us to communicate with our chef server.
  19. Lets bootstrap our node to chef server. For this you will need another machine which is accessible from the machine you have unzipped the chef-repo directory. Create a user in the node machine with sudo privileges, which can be ‘ssh’ed from our workstation and chef server.
    Execute the command:
    knife bootstrap 192.168.1.240 -N chef-node –ssh-user user1 –sudo
    Where ‘chef-node’ is the node name i am giving to the node. This can be any name. If -N option is not provided the default nodename will be the hostname of the node.
    ‘user1’ is the user I created on node.
    You might get an error: Your private key could not be loaded.
    cd chef-repo then execute the bootstrap command.
    You will see an output similar to the following:
    ……
    192.168.1.240 Converging 0 resources
    192.168.1.240
    192.168.1.240 Running handlers:
    192.168.1.240 Running handlers complete
    192.168.1.240 Chef Client finished, 0/0 resources updated in 16 seconds
  20. Then goto the chef dashboard and on the nodes panel page you can see the newly added node. In the attributes panel you can see the attributes belonging to the node like CPU,RAM etc.
  21. Create a project in github(ex: chef-fluency-badge). Then cd chef-repo and execute the following command:
    git init
    git add ./
    git config –global user.email “”
    git config –global user.name “”
    git commit -am “Adding chef-repo”
    git remote add origin https://github.com//chef-fluency-badge.git
    git push -u origin master
  22. Create a cookbook with the followig command:
    knife cookbook create learn for chef < 12
    chef generate cookbook for chef => 12
    Add this learn cookbook to git repo with the following commands:
    git add ./
    git commit -m “adding learn cookbook”
    git push -u origin master
  23. Lets create apache cookbook:
    cd chef-repo
    chef generate cookbook cookbooks/apache
    cd cookbooks/apache
    Edit the metadata.rb file and enter your details. Save and close.
    cd recipes
    Edit default.rb and add the following lines:
    ##

    package 'apache2' do
            package_name 'httpd'
            action :install
    end
    
    service 'apache2' do
            service_name 'httpd'
            action [:start, :enable]
    end
    
    
  24. Check the ruby syntax by running the command:
    ruby -c default.rb
    foodcritic default.rb 

    foodcritic should not give any error message.
    Now we want to change the default apache webpage.
    In the same recipes directory create websites.rb with following content:
    ##

    file "default www" do
            path '/var/www/html/index.html'
            content 'Hello world'
    end
    &lt;span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			&gt;&amp;#65279;&lt;/span&gt;

    Check it with foodcritic. You can also comeback to cookbooks directory and execute:
    foodcritic apache

  25. Upload the cookbook to the chef server with the following command:
    knife cookbook upload apache
    You can also add this code to git repo.
  26. Then goto the chef-manage UI, in the policies section you will see the apache cookbook. Policy is basically configuration management for a node.
  27. In your workstation machine execute the knife node list command to get a list of nodes.
  28. Then we need to add our cookbook to run_list. Execute the following command for it:
    knife node run_list add chef-node ‘recipe[apache]’

    Then execute the following command to retreive the list of run_list:
    knife node show chef-node
    The above command gives a summary of the node like recipes, OS version etc. To get a detailed list execute the following command:
    knife node show -l chef-node

  29. Now we will dry-run our cookbook on chef-client:
    chef-client –why-run
    OR
    chef-client -W
  30. After the why-run is successful then execute the cookbook with the following command:
    chef-client

    You can check the httpd service status, it should be running. Then go to the browser and hit the <IP> of the client. It will not show our “Hello World” page but the default apache “Testing 123” page.
    This was because our websites recipe did not execute. Edit the default.rb and add the following line:
    include_recipe ‘apache::websites’

  31. Then upload the apache cookbook to chef-server:
    knife cookbook upload apache
  32. Then run chef-client your websites recipe will get executed.
  33. Suppose if we want to run the websites recipe manually everytime.
    Edit the websites.rb file and remove the include_recipe line we just added above. Then again upload the cookbook to the chef-server.
  34. Then we need to add the websites recipe to the run_list otherwise after running chef-client the websites recipe will not get executed.
    You can add the recipe with the following command:
    knife node run_list add chef-node ‘recipe[apache::websites]’ -a recipe[apache]
    or you can also execute knife node run_list add ‘apache’
  35. Now you can run chef-client it will execute the websites recipe.
  36. The client configuration can be found at /etc/chef/client.rb on the client machine.