Skip to main content

Chef-Cookbooks Walls of chef-house..



                  

Introduction

As we work with cookbook in our previous blog, we are now aware about how chef really works and manage machines using cookbooks. Its crucial to understand the potential of thoughts and theories behind any concept. According to Albert Einstein,

A Theory Can Be Proved By Experiment;
But No Paths Leads from Experiments To The Birth Of Theory

Prerequisites

To follow this article you need a prior information about Git and Vagrant. This blog uses centos7   as platform. It needs basic understanding of chef and it's cookbooks. To know about chef cookbooks follow our previous blogs of this series Chef Start here with ease.. .

Get started

Clone our github repository and spin up a bare centos7 vagrant machine.


Go to Chef/centos/chefCookbooksBackings directory.

$ cd  Chef/centos/chefCookbooksBackings

  • This directory have a Vagrantfile. Which can initiate a centos7 vagrant box.
$ cat Vagrantfile


This file update and install some basic tools in your vagrant machine using vagrant shell provisioning.
  • Download Chefdk using below available command

$ cd Chef/centos/chefResources

$ wget https://opscode-omnibus-packages.s3.amazonaws.com/el/7/x86_64/chefdk-0.11.2-1.el7.x86_64.rpm

  • This directory also includes a knife.rb file which sets the cookbook folder path and default editor for the virtual machine.

  • Launch new vagrant machine and login into it via ssh.
$ vagrant up

$ vagrant ssh

Cookbooks

As per chef’s official document “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.”  
Chef cookbooks are the first configurational unit of chef. These are the like a box which contains all the basic tools for the comfortable management of any machine. It consist of
 
  • Recipes
  • Attribute
  • File
  • Templates
  • libraries, definitions, and custom resources

Directory Structure

The directory structure of any cookbook  is very straight and simple. We took an example cookbook which we are going to create in our next section, so have a look on what it looks like on completion.

$ tree cookbooks/nginxVhostExtended/

  • Attributes
This directory contains all files which holds the values of the variables used in the cookbook.
  • Definitions
This directory contains definition of new created resources.
  • Files
This folder holds static file used in cookbook.
  • Libraries
Allows users to use extended ruby libraries for new class declarations.
  • Providers
This will contains actions which will be taken on using a custom resource declared in resources directory.
  • Recipes
This directory holds all the the recipes of any cookbook. These are the main execution part of the cookbook.
  • Resources
Here custom resources are defined.
  • Templates
This directory provide templates for the dynamic solutions of a cookbook.
  • Metadata.rb
This file ensures that every cookbook is deployed correctly. Also holds the general information for any cookbook as like author copyright and version.

Try with a complex one

This time we introduce some extended concepts of chef cookbooks in our example cookbook. As in our previous blogs problem statement remain same to install nginx and setup nginx vhost with our cookbook. But this time we tried to be more efficient so that we can create multiple vhost in a single chef-client run.


First create a dedicated directory for our cookbooks. As in knife.rb file it will be created by following command.

$ mkdir /vagrant/cookbooks

Chef manage its cookbooks using a version control system so next we initialize and also make our first commit for /vagrant/cookbooks directory. Provide your name and email for git configuration.
$ mkdir /vagrant/cookbooks
$ cd /vagrant/cookbooks
$ git init
$ git add .
$ git config --global user.email "you@example.com"
$ git config --global user.name "Your Name"
$ git commit -m "Initial Commit"

Now you are ready to start with the creation of your next cookbook.

$ knife cookbook create nginxVhostExtended -C "Saurabh Vajpayee" -m "myemail@email.com" -I nginxv1 -r md

Create default recipe

Create a default recipe with following content to install  nginx.

$ vim /vagrant/cookbooks/nginxVhostExtended/recipes/default.rb

include_recipe 'yum-epel'

package node['nginx']['packages'] do
action :install
end

service 'iptables' do
action :stop
end

service 'nginx' do
action [:start, :enable]
end

This time we also  included another recipe “yum-epel” in our default recipe.

Generate another recipe to configure vhost with following content.

$ chef generate recipe /vagrant/cookbooks/nginxVhostExtended/ vhost

$ vim /vagrant/cookbooks/nginxVhostExtended/recipes/vhost.rb

include_recipe 'nginxVhostExtended'

node['nginx']['vhost'].each do |name, attrs|
 nginxVhostExtended_vhost 'name' do
   port attrs['port']
   webroot attrs['webroot']
   servername attrs['servername']
   conffile attrs['conffile']
 end
end

service 'nginx' do
action :restart
end

This recipe contains a custom resource  “nginxVhostExtended_vhost” which has its definition and attribute declaration under provider and resource directory.

Generate attribute file

Generate default attribute file with following defined variables.

$ chef generate attribute /vagrant/cookbooks/nginxVhostExtended/ default

$ vim /vagrant/cookbooks/nginxVhostExtended/attributes/default.rb

default['nginx']['packages'] = "nginx"
default['nginx']['port'] = 80
default['nginx']['webroot'] = "/usr/share/nginx/blog"
default['nginx']['servername'] = "blog.opstree.com"
default['nginx']['conffile'] = "blog.opstree.com.conf"
default['nginx']['vhost'] = {}

This attribute file holds default values for variable used in templates

Generate template files

Generate two templates for conf and index.html files. Use following content to paste.

$ chef generate template /vagrant/cookbooks/nginxVhostExtended/ chefmanagedconf.conf

$ chef generate template /vagrant/cookbooks/nginxVhostExtended/ index.html

$ vim /vagrant/cookbooks/nginxVhostExtended/templates/default/chefmanagedconf.conf.erb

server {
   listen       <%= @port  %>;
   server_name  <%= @servername  %>;

   location / {
       root   <%= @webroot  %>;
       index  index.html index.htm;
   }

   error_page  404              /404.html;
   location = /404.html {
       root   <%= @webroot  %>;
   }

   # redirect server error pages to the static page /50x.html
   error_page   500 502 503 504  /50x.html;
   location = /50x.html {
       root   <%= @webroot  %>;
        }
  }

$ vim /vagrant/cookbooks/nginxVhostExtended/templates/default/index.html.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
       <title>Test Page for the Opstree Server </title>
   </head>

   <body>
       <h1>Welcome to <strong> <%= @servername %> </strong></h1>
   </body>
</html>

Generate a lwrp

Generate a lwrp (light weight resource provider ) using knife command and use following content.

$ chef generate lwrp /vagrant/cookbooks/nginxVhostExtended/ vhost

$ vim  /vagrant/cookbooks/nginxVhostExtended/resources/vhost.rb

actions :configure
default_action :configure

attribute :name,
 kind_of: String,
 required: true,
 name_attribute: true
attribute :port,
 kind_of: Fixnum
attribute :webroot,
 kind_of: String
attribute :servername,
 kind_of: String
attribute :conffile,
 kind_of: String

$ vim /vagrant/cookbooks/nginxVhostExtended/providers/vhost.rb

action :configure do

[:webroot, :conffile, :servername, :port].each do |attr|
      unless new_resource.instance_variable_get("@#{attr}")
        new_resource.instance_variable_set("@#{attr}", node['nginx'][attr])
      end
    end

[:webroot].each do |attr|
      directory new_resource.instance_variable_get("@#{attr}") do
        mode '0755'
        recursive true
      end
      template "#{new_resource.webroot}/index.html" do
        source 'index.html.erb'
        variables(
         servername: new_resource.servername
       )
      end
    end

template "/etc/nginx/conf.d/#{new_resource.conffile}" do
  source 'chefmanagedconf.conf.erb'
  variables(
         port: new_resource.port,
         servername: new_resource.servername,
         webroot: new_resource.webroot
       )
end

line = "127.0.0.1 #{new_resource.servername}"
file = Chef::Util::FileEdit.new('/etc/hosts')
file.insert_line_if_no_match(/#{line}/, line)
file.write_file

end

Now our cookbook is ready but as we define in yum-epel dependency in our default  cookbook so in next steps we install this cookbook from chef repository.

$ git status
$ git add .
$ git commit -m "nginxVhostExtended cookbook added"

$ knife cookbook site install yum-epel

Go for it

Lets run our cookbook to just install nginx using default recipe. Create   installrunlist.json with following content.   

$ vim installrunlist.json

{
"run_list": [
"recipe[yum-epel]",
"recipe[nginxVhostExtended]"
]
}

$ chef-client  --local-mode -j /vagrant/runlist.json
This will install your nginx server only.

Now we create a runlist file for configuring vhost.

$ vim vhostrunlist.json

{
  "nginx": {
     "vhost": {
       "vhost1": {
         "webroot": "/usr/share/nginx/chef",
             "servername": "chef.opstree.com",
             "conffile": "chef.opstree.com.conf"
             },
        "vhost2": {
          "webroot": "/usr/share/nginx/blog",
             "servername": "blog.opstree.com",
             "conffile": "blog.opstree.com.conf"
             }
           }
 },
  "run_list": [
"recipe[yum-epel]",
"recipe[nginxVhostExtended]",
       "recipe[nginxVhostExtended::vhost]"
              ]
}

$ chef-client  --local-mode -j /vagrant/vhostrunlist.json

This will run and configure two vhost blog.opstree.com and chef.opstree.com on your machine. Now with our new cookbook we are able to create and configure multiple vhost in single run.


We took some extended concepts of chef cookbooks. Chef and it's cookbooks are beyond away from all limits. This is just a drop from the ocean but every drop in the ocean counts…

You need an entire life just to know about tomatoes. Ferran Adria

Don't be panic by messing up with a lot of things and start playing with your own written cookbooks.  

Comments

Popular posts from this blog

EC2 Ssh Connection Refused

When ssh: connect to host ip_address port 22 Connection refused



Unable to access server???
Exactly when you see the error - “ssh: connect to host ip_address port 22: Connection refused” while connecting your AWS EC2 Instance. In order to find solution of the problem, you will go to AWS forum and other channels where you need to answers several questions first. But it's very difficult to find the actual problem. In order to get clues what the problem is, we should provide as many details as possible about what we have tried and the results we are getting. Because there are hundreds of reason why a server or service might not be accessible, also connectivity is one of the toughest issue to diagnose, especially when you are hosting something critical on your box. I've seen several topics on this problem, but none offers a solution to it.  I was not aware for what should I look at first. So I walk through from the very basics and investigated the following thing Use of verbose while ss…

jgit-flow maven plugin to Release Java Application

Introduction As a DevOps I need a smooth way to release the java application, so I compared two maven plugin that are used to release the java application and in the end I found that Jgit-flow plugin is far better than maven-release plugin on the basis of following points: Maven-release plugin creates .backup and release.properties files to your working directory which can be committed mistakenly, when they should not be. jgit-flow maven plugin doesn't create these files or any other file in your working directory.Maven-release plugin create two tags.Maven-release plugin does a build in the prepare goal and a build in the perform goal causing tests to run 2 times but jgit-flow maven plugin builds project once so tests run only once.If something goes wrong during the maven plugin execution, It become very tough to roll it back, on the other hand jgit-flow maven plugin makes all changes into the branch and if you want to roll back just delete that branch.jgit-flow maven plugin doesn…

VPC per envrionvment versus Single VPC for all environments

This blog talks about the two possible ways of hosting your infrastructure in Cloud, though it will be more close to hosting on AWS as it is a real life example but this problem can be applied to any cloud infrastructure set-up. I'm just sharing my thoughts and pros & cons of both approaches but I would love to hear from the people reading this blog about their take as well what do they think.


Before jumping right away into the real talk I would like to give a bit of background on how I come up with this blog, I was working with a client in managing his cloud infrastructure where we had 4 environments dev, QA, Pre Production and Production and each environment had close to 20 instances, apart from applications instances there were some admin instances as well such as Icinga for monitoring, logstash for consolidating logs, Graphite Server to view the logs, VPN server to manage access of people.




At this point we got into a discussion that whether the current infrastructure set-u…