Chef execute block - ruby

I am very new to Chef. I have a recipe that installs sendmail and it does my configurations. I have noticed that Chef restarts the service on every run. That is because I'm running an execute that calls the session restart.
It looks like this:
execute "hashAccess" do
command "makemap hash /etc/mail/access < /etc/mail/access"
notifies :restart, "service[sendmail]"
end
I need to call this only when the access file if updated.
template "/etc/mail/access" do
source "access.erb"
mode "0644"
notifies :run, "execute[hashAccess]"
end
When the file is updated, the execute is called twice.
Both of the resources are in the same recipe and when I try to define hashAccess I get an error
ERROR: Cannot find a resource for define on amazon version 2013.09
How do I make the execute resource to run only when called?

You should add action :nothing to your execute resource.
execute "hashAccess" do
command "makemap hash /etc/mail/access < /etc/mail/access"
action :nothing
notifies :restart, "service[sendmail]"
end
This way it will not be executed, unless notified by other resource.

Related

How to use a Chef Windows reboot resource to reboot only once

I'm currently attempting to use the reboot resource in a chef resource:
reboot 'ADS Install Complete' do
action :nothing
reason 'Cannot continue Chef run without a reboot.'
only_if {reboot_pending?}
end
...
execute 'Initialize ADS Configuration INI' do
command "\"#{node["ads-tfs-ini"]["tfsconfig_path"]}\" unattend \/create \/type:#{node["ads-tfs-ini"]["Scenario"]} \/unattendfile:\"#{node["ads-tfs-ini"]["unattend_file_path"]}\""
only_if { ! "#{ENV['JAVA_HOME']}".to_s.empty? }
notifies :request_reboot, 'reboot[ADS Install Complete]', :delayed
end
I am getting an endless loop of reboots (client reboots-->chef client runs-->chef client reruns the run_list--client reboots-->...). How can I just reboot once?
You could add some validation to check whether the computer has been rebooted once.
ruby_block "reboot" do
unless File.exist?("C:\reboot") do
block do
Chef::Util::FileEdit.new('C:\reboot').write_file
Chef::ShellOut.new("shutdown /r").run_command
end
end
end
This solution isn't really elegant, but it should work. The reboot is inside the ruby block which will only run if C:\reboot DOESN'T exist. If the file doesn't exist, the block will create the file and then call the reboot. On the second chef run, the file will exist so the reboot will not be triggered.
Here is the documention regarding ruby_block
from reboot chef resource:
Use the reboot resource to reboot a node, a necessary step with some installations on certain platforms. This resource is supported for use on the Microsoft Windows, macOS, and Linux platforms.
reboot 'name' do
action :reboot_now
end
Your only_if guard in the execute resource makes execute resource run, if ENV['JAVA_HOME'] is not empty. Very likely, that this environment variable is set and that's why your execute resource is run every time Chef runs, and triggers the reboot.
My guess, is you just actually need an opposite, run the resource, only if the variable is empty. For that you can just remove the ! from the line.
only_if { ENV['JAVA_HOME'].to_s.empty? }
If my previous guess is wrong, then you need to change your only_if guard to something more robust. From the command line, I understand you create some configuration files, so you don't need to run execute resource, when you config files already exist:
not_if { ::File.exist?('/path/to/file/created/by/command') }

Subscribes/Notifies in Chef

I have recently started working on CHEF Recipes and was trying to learn about subscribes/notifies in CHEF
Scenario: Wrote a recipe to install sendmail package, have a local copy of sendmail.mc on CHEF that i am deploying on the Node[Client].
I read about notifies/subscribes and what i am trying to do is when there is a change in the sendmail.mc file at /etc/mail/sendmail.mc sendmail service should be cycled.
for which i am using subscribes .
But when i manually change the sendmail.mc on the client to trigger Chef to overwrite the file and wait for the service to be restarted for sendmail i see the below error
service[sendmail] action nothing (skipped due to action :nothing)
package "sendmail"
service "sendmail" do
action [:enable, :start]
end
cookbook_file '/etc/mail/sendmail.mc' do
action [:create]
source 'sendmail.mc'
owner 'root'
group 'root'
end
service 'sendmail' do
subscribes :restart, 'file[/etc/mail/sendmail.mc]', :immediately
end
I think the duplicate service definition with the same name ("sendmail") could be a reason. But also your subscribes targets the wrong resource file instead of cookbook_file!
Given that most users and public cookbooks use "notifies" instead of "subscribes", I would rewrite it to:
package 'sendmail'
cookbook_file '/etc/mail/sendmail.mc' do
source 'sendmail.mc'
owner 'root'
group 'root'
action :create
notifies :restart, 'service[sendmail]', :immediately # not sure about the *:immediately* here, usually at the end of converge is sufficient.
end
service 'sendmail' do
action [:enable, :start]
end

Chef template resource to execute if the source template changes?

I'm deploying a package that requires a template be created in a specified directory every time a directory is unzipped.
A remote_file notifies my unzip action, that unzip action notifies the template resource, which in turn notifies other resources. This chain of notifications works as expected.
Below is my template resource:
template 'C:\\Program Files\\MyProgram\\program.yml' do
source "my_program-#{node['program']['version']}.yml.erb"
action :nothing
notifies :run, 'powershell_script[install-program]', :immediately
end
My question: Is there a way to have the template resource execute if I make a change to the source template? Right now it only executes the template resource if notified by my unzip action (due to my action :nothing).
However, it would be great to have a way for it to tell if the template itself has changed. Perhaps some kind of not_if or only_if statement?
sounds to me that you avoid all the notification chaining if you will have your resources defined in the same recipe.
back to your questions, it sounds that setting action :create, which is the default action, will do the trick. from the template resource documentation
action :create
Create a file. If a file already exists (but does not match), update that file to match.

Chef - Block not being executed even tho its notified?

i've looked over this code a few times and i'm not sure why the extract_presta block isnt being triggered. I've confirmed the file i'm looking for isnt in the /var/www/html directory :c)
What i'm trying to achieve is to:
download a file, unzip it, but only if a specific file doesn't exist
Stop apache after downloading, unzip the file
start apache
Could i ask for some advice please? thanks.
-nat
service "apache" do
action :nothing
end
execute 'extract_presta' do
command 'unzip /tmp/prestashop_1.7.4.2.zip'
cwd '/var/www/html'
not_if { File.exists?("/var/www/html/autoload.php") }
action :nothing
notifies :start, "service[apache]"
end
# Fetch the file. Maybe the file won't be fetched because of not_if or checksum.
# In that case apache won't be stopped or started, it will just keep running.
remote_file "/tmp/prestashop_1.7.4.2.zip" do
source "https://download.prestashop.com/download/releases/prestashop_1.7.4.2.zip"
notifies :stop, "service[apache]", :immediately
notifies :run, 'execute[extract_presta]', :immediately
end
Does the download already exist? If so, then the remote_file resource would be marked up-to-date and wouldn't fire notifications.

Why chef does not execute recipe line by line?

Problem is that chef tries to install template first, and only then installs packages. If i comment template block, chef will install sphinxsearch package fine.
But if template block is not commented, sphinxsearch package is not installed, and chef fails with error
resource template[/etc/sphinxsearch/sphinx.conf] is configured to notify resource service[sphinxsearch] with action reload, but service[sphinxsearch] cannot be found in the resource collection`
Why this happens?
##
# Install system packages
##
node['website']['packages'].each do |pkg|
log 'Installing ' + pkg
package pkg
end
##
# Configure sphinx
##
template "/etc/sphinxsearch/sphinx.conf" do
source 'sphinx.erb'
owner 'root'
group 'root'
mode 00644
notifies :reload, 'service[sphinxsearch]', :delayed
end
notifies and subscribes in chef are both trying to reach out to resources that have been defined in your chef run. They will then call teh indicated action on those resources. In your case:
notifies :reload, 'service[sphinxsearch]', :delayed
is looking for a resource of type service named sphinxsearch and call the reload action on it. If, at the end of the resource gathering (compile) phase, chef cannot find a service[sphinxsearch] resource, then it throws the error. You don't see the package installed because chef never enters the execution phase. (See this answer for more on the two phase nature of chef)
As indicated by #IsabelHM, you could solve the problem by adding
service 'sphinxsearch' do
action [:enable, :start]
end
I suggest you use [:enable, :start] rather than :nothing as this will ensure that the service is always running, even if your template doesn't change. Also, please note that the service resource does not add a service config for you. So if the sphinxsearch package does not add a service config, you'll also need a cookbook_file, template, or remote_file resource to create the service config with.
Add this in your recipe.
service 'sphinxsearch' do
action :nothing
end

Resources