Chef Conditional Prgramming Tutorials
There are certain attributes that can be used to evaluate the state of a node during the
execution process of a chef-client run. Based on the result of the evaluation, the attribute
is used to tell chef-client whether it should continue the execution of that specific
resource or not.
These attributes are referred to as guard attributes or conditionals.
A guard attribute either accepts
- A string or - If a string is supplied as a value, the string is considered as a command,if the execution of the concerned command yields 0 as the return value the guard is applied or else not.
- A block of Ruby code as a value. - If a Ruby block is supplied as a value, the block is executed as Ruby code. The block
must return either true or false.
Guard attributes are typically used to ensure that the Chef resource is idempotent. It checks whether the desired state is present or not. If the state is already present, the chef-client run does nothing for the concerned resource.
The following attributes can be used to define a guard:
Attribute | Description |
---|---|
not_if | This prevents a resource from being executed if the condition is true |
only_if | This ensures that a resource is executed only if the condition is true |
Example Programs
Condistions Based on if-else statement with Chef Attributes attribute? A useful method that is related to attributes is the attribute? method. This method will check for the existence of an attribute, so that processing can be done in an attributes file or recipe, but only if a specific attribute exists. Using attribute?() in an attributes file: if attribute?('ec2') # ... set stuff related to EC2 end Using attribute?() in a recipe: if node.attribute?('ec2') # ... do stuff on EC2 nodes end Condistions Based on if statement if node[:platform_family].include?("rhel") ... end Condistions Based on if statement
if node['platform'] == 'debian' || node['platform'] == 'ubuntu'
execute "apt-get update" do
command "apt-get update"
end
end
Condistions Based on include_recipe
include_recipe 'python::repository' if node['python']['installrepo']
Condistions Based on if-else and include_recipe
if node['platform_family'] == 'windows'
include_recipe 'python::install-windows'
else
include_recipe 'python::install-linux'
end
Condistions Based on Attributes
if node['platform'] == 'debian' || node['platform'] == 'ubuntu'
execute "apt-get update" do
command "apt-get update"
end
end
if node['platform'] == 'redhat'
execute "yum git" do
command "yum install git -y"
end
end
not_if
apt_package "apache2" do
action :install
not_if { node['platform'] == 'redhat' }
end
file '/tmp/somefile.txt' do
mode '0755'
not_if { File.exist?('/etc/passwd' )}
end
execute 'bundle install' do
cwd '/myapp'
not_if 'bundle check' # This is run from /myapp
end
template '/tmp/somefile' do
mode '0755'
source 'somefile.erb'
not_if { node[:some_value] }
end
template '/tmp/somefile' do
mode '0755'
source 'somefile.erb'
not_if do
File.exist?('/etc/passwd')
end
end
template '/tmp/somefile' do
mode '0755'
source 'somefile.erb'
not_if { File.exist?('/etc/passwd' )}
end
template '/tmp/somefile' do
mode '0755'
source 'somefile.erb'
not_if 'test -f /etc/passwd'
end
Example
:user
Specify the user that a command will run as. For example:
not_if 'grep adam /etc/passwd', :user => 'adam'
:group
Specify the group that a command will run as. For example:
not_if 'grep adam /etc/passwd', :group => 'adam'
:environment
Specify a Hash of environment variables to be set. For example:
not_if 'grep adam /etc/passwd', :environment => {
'HOME' => '/home/adam'
}
:cwd
Set the current working directory before running a command. For example:
not_if 'grep adam passwd', :cwd => '/etc'
:timeout
Set a timeout for a command. For example:
not_if 'sleep 10000', :timeout => 10
apt_package "php5" do
action :install
not_if { node['platform'] == 'centos' }
end
# want to ensure that we have the right JAVA_HOME path set before we go about
triggering the command to start the app or check the status.
bash "some_app" do
environment { "JAVA_HOME" => "/usr/java/default" }
code "java /apps/some_app/app start"
not_if "java /apps/some_app/app status"
end
# However, this isn't the right way to go about handling our situation because the
environment variable JAVA_HOME isn't available to the java some_app status
command. One way to do it correctly is this:
bash "some_app" do
environment { "JAVA_HOME" => "/usr/java/default" }
code "java /apps/some_app/app start"
not_if "java /apps/some_app/app status", :environment => {
'JAVA_HOME' => '/usr/java/default' }
end
bash "some_app" do
guard_interpreter :bash
environment { "JAVA_HOME" => "/usr/java/default" }
code "java /apps/some_app/app start"
not_if "java /apps/some_app/app status"
end
# we are installing a package called package_name and
we want to install it only on systems running RHEL 6.x.
package "package_name" do
action :install
not_if { platform_family?('rhel') && node['platform_version'].to_f < 6.0 }
end
only_if
only_if
Allow a resource to execute only if the condition returns true.
file '/tmp/infy.txt' do
only_if { File.exist?('/etc/passwd2' ) }
end
package "httpd" do
action :install
only_if { platform_family?('rhel') && node['platform_version'].to_f >= 6.0 }
end
template '/tmp/somefile' do
mode '0755'
source 'somefile.erb'
only_if { node[:some_value] }
end
template '/tmp/somefile' do
mode '0755'
source 'somefile.erb'
only_if do ! File.exist?('/etc/passwd') end
end
template '/tmp/somefile' do
mode '0755'
source 'somefile.erb'
only_if 'test -f /etc/passwd'
end
file '/var/www/html/login.php' do
only_if { ::File.exist?('/var/www/html/login.php') }
action :touch
end
file '/path/foo' do
action :delete
only_if { File.exist? '/path/foo' }
end
apt_package "php-pear" do
action :install
only_if "which php"
end
# we are installing a package called package_name and
we want to install it only on systems running RHEL 6.x.
package "package_name" do
action :install
only_if { platform_family?('rhel') && node['platform_version'].to_f >= 6.0 }
end
include_recipe "postfix::server" do
only_if node["defaults"]["postfix_server"] = true
end