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 executeohai > nodeinfo.json
- Navigate to attributes section of the node as shown in the chefserver UI
- These attributes can be used in recipe dsl as node object.
What happens during chef-convergance
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
- 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
- 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
- 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
- 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