DevOps Classroom Series – 19/Apr/2020

Setup

  • Kitchen Setup: We already have it
  • Chef Infra Server and Chef-client node:
    • Ensure you have one centos and one ubuntu bootstrapped

Ohai

  • Login into the chef-client-nodes and execute ohai and now execute ohai > nodeinfo.json
  • Navigate to attributes section of the node as shown in the chefserver UI Preview
  • These attributes can be used in recipe dsl as node object.

What happens during chef-convergance

Preview

Attributes

  • Attribute is some information about the node or application or anything which can be represented
  • Attributes are of two types
    • automatic attributes collected by ohai during chef-client cannot be changed by user
    • custom attributes can be changed at various places

Practical Explanation

  • Im trying to acheive lamp stack (without mysql) in centos 7 and ubuntu 18 ubuntu and centos

  • Lets generate a cookbook for apache

cd <chef-repo>\cookbooks\
chef generate cookbook -b apache
  • Manual Steps:
Ubuntu:
sudo apt-get update
sudo apt-get install apache2 -y
sudo systemctl enable apache2
sudo systemctl start apache2
sudo apt install php libapache2-mod-php php-mysql php-cli
sudo systemctl restart apache2
sudo vi /var/www/html/info.php
<?php phpinfo(); ?>

Centos:
sudo yum install httpd -y
sudo systemctl enable httpd
sudo systemctl start httpd
sudo yum install php php-mysql php-fpm
sudo systemctl restart httpd
sudo vi /var/www/html/info.php
<?php phpinfo(); ?>
sudo systemctl restart httpd

  • Generate a recipe for apache
chef generate recipe . install
  • Now inside install.rb file lets write resource for apt-get update and it has to run only on ubuntu machines for that we write
# write an if condition
#
# Cookbook:: .
# Recipe:: install
#
# Copyright:: 2020, The Authors, All Rights Reserved.

# i want to run this cookbook only if the node is debian

# write an if condition
if node['platform'] == 'ubuntu'
    apt_update 'updateubuntu' do
        ignore_failure true
        action :update
    end
end
  • chef gives us one better alternative for writing if conditions using guards Refer Here
#
# Cookbook:: .
# Recipe:: install
#
# Copyright:: 2020, The Authors, All Rights Reserved.

# i want to run this cookbook only if the node is debian

apt_update 'updateubuntu' do
    ignore_failure true
    action :update
    only_if node['platform'] == 'ubuntu'
end
  • Now to write the installation we can use apt_package resource but this works only on ubuntu, chef has a generic package resource refer here Preview
  • Now create a variable and assign the value of the variable depending on platform family
#
# Cookbook:: .
# Recipe:: install
#
# Copyright:: 2020, The Authors, All Rights Reserved.

# i want to run this cookbook only if the node is debian

apt_update 'updateubuntu' do
    ignore_failure true
    action :update
    only_if node['platform'] == 'ubuntu'
end

if node['platform_family'] == 'debian'
    package_name = 'apache2'
    
elsif node['platform_family'] == 'rhel'
    package_name = 'httpd'
end

package package_name do
    action :install
end

  • It is a best practice in chef to use attribute to store variables which might change, so lets go and define custom attribute Preview Preview
  • Lets generate an custom attribute file called as default
chef generate attribute . default
# A new folder attributes will be generated inside the cookbook
  • Attributes in the attributes file should be defined like how the node object appears, becoz attributes become part of your node object.
<type>['cookbookname']['purpose'] = '<value>'
  • As of now only type which i want you to use is default
default['apache']['packagename'] = 'apache2'
default['tomcat']['conf_file'] = '/var/lib/tomcat7/tomcat.conf'
  • The default.rb file in attributes will appear as
if node['platform_family'] == 'debian'
    default['apache']['package_name'] = 'apache2'
    
elsif node['platform_family'] == 'rhel'
    default['apache']['package_name']
end
  • Now recipe install.rb looks as shown below
#
# Cookbook:: .
# Recipe:: install
#
# Copyright:: 2020, The Authors, All Rights Reserved.

# i want to run this cookbook only if the node is debian

apt_update 'updateubuntu' do
    ignore_failure true
    action :update
    only_if { node['platform'] == 'ubuntu' }
end

# using the attribute defined in the attributes/default.rb file
package node['apache']['package_name'] do
    action :install
end

# enable the apache service
service node['apache']['package_name'] do
    action :enable
end
  • Lets upload the recipe and do the chef convergance
berks install
berks upload
# change run_list
  • Change the run_list for centos and ubuntu node and look what happens during converge
  • In chef cookbook you cannot have two resources of same type with same name use service resource twice in install.rb as shown below
#
# Cookbook:: .
# Recipe:: install
#
# Copyright:: 2020, The Authors, All Rights Reserved.

# using the attribute defined in the attributes/default.rb file
package node['apache']['package_name'] do
    action :install
end

# enable the apache service
service node['apache']['package_name'] do
    action :enable
end

# two resources of same type cannot have same name so workaround
service 'starting apache ' do
    service_name node['apache']['package_name']
    action :start
end

  • Now upload the cookbook after changing the version in metadata.rb file and apply convergance. (Run-list as of now picks the latest version)
berks upload

Preview Preview

  • If you look at the whole manual steps, there are systemctl commands appearing thrice and giving three different names doesn’t sound like a good idea.
  • Chef has a concept of Notifications Refer Here
    • we will be using notifications to define the service once and using it multiple times
    • Notifications are of two types notifies/subscribes Preview
  • Now lets apply notifies to service resource install
  • Now we want to install multiple pacakges for that we would use loop and for that we use each in ruby
  • Navigate to attributes/default.rb and change as shown below
if node['platform_family'] == 'debian'
    default['apache']['package_name'] = 'apache2'
    default['apache']['php_packages'] = ['php', 'libapache2-mod-php', 'php-mysql', 'php-cli']
    
elsif node['platform_family'] == 'rhel'
    default['apache']['package_name'] = 'httpd'
    default['apache']['php_packages'] = ['php','php-mysql', 'php-fpm']
end
  • Also look into string interpolation over here
  • To accomodate these in install.rb in recipes
#
# Cookbook:: .
# Recipe:: install
#
# Copyright:: 2020, The Authors, All Rights Reserved.

# using the attribute defined in the attributes/default.rb file

package_name = node['apache']['package_name']


package node['apache']['package_name'] do
    action :install
    notifies :enable, 'service[apache]'
end

service 'apache' do
    service_name node['apache']['package_name']
    action :nothing
end

packages = node['apache']['php_packages']

packages.each do |package_now|
    package package_now do
        action :install
        notifies :restart, 'service[apache]'
    end
end

  • Now upload this cookbook and test it out
berks upload
# do convergance

Exercise:

  • First execute what i have done in the class on chef nodes
  • Try doing the same thing on kitchen

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Please turn AdBlock off
Floating Social Media Icons by Acurax Wordpress Designers

Discover more from Direct DevOps from Quality Thought

Subscribe now to keep reading and get access to the full archive.

Continue reading

Visit Us On FacebookVisit Us On LinkedinVisit Us On Youtube