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.

About learningthoughtsadmin