Subscribes/Notifies in Chef - ruby

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

Related

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.

How to configure software using chef and vagrant after install recipe runs

Thanks for taking a look at this question. Any help is appreciated.
I am provisioning a virtual machine with a GUI using vagrant and chef.
Goal: to download IntelliJ IDE and then install it so that it is available to my user when I log in.
The cookbook cookbook 'idea', '~> 0.4.0'achieves the download but a user must manually complete the install on the guest.
I am having trouble with my custom recipe to complete the configuration with chef. As it is written, the recipe completes if I add it to the run list after the machine is provisioned but fails in the initial run because files are not yet installed.
I tried using the only_if method within the relevant blocks and on the entire recipe, but couldn't get it to work. I also messed with the subscribe method but couldn't get that to work either.
I'm sure this has an easy solution, but Googling and trial and error are not getting me any closer. I would appreciate any help to achieve the goal. Thanks!
Current recipe
# Configure IntelliJ Idea.
file '/opt/idea/idea.desktop' do
content '[Desktop Entry]
Name=IntelliJ IDEA
Type=Application
Exec=idea
Terminal=false
Icon=idea
Comment=Integrated Development Environment
NoDisplay=false
Categories=Development;IDE;
Name[en]=IntelliJ IDEA'
mode '644'
owner 'root'
group 'root'
end
bash 'install idea desktop' do
code <<-EOH
cd /opt/idea
sudo desktop-file-install idea.desktop
EOH
end
file '/usr/share/pixmaps/idea.png' do
owner 'root'
group 'root'
mode '0644'
content ::File.open('/opt/idea/bin/idea.png').read
action :create
end
link '/usr/local/bin/idea' do
to '/opt/idea/bin/idea.sh'
link_type :symbolic
end
Failed efforts:
Wrapping the entire script
# Configure IntelliJ Idea.
execute 'configure idea' do
only_if { ::File.exist?("/opt/idea") }
continues...
end
Using only_if in the blocks
file '/usr/share/pixmaps/idea.png' do
action :create
only_if { ::File.exist?('/opt/idea/bin/idea.png') }
owner 'root'
group 'root'
mode '0644'
content ::File.open('/opt/idea/bin/idea.png').read
end
link '/usr/local/bin/idea' do
to '/opt/idea/bin/idea.sh'
only_if { ::File.exist?('/opt/idea/bin/idea.sh') }
link_type :symbolic
end
What you probably want is a lazy evaluated property:
content lazy { ::File.open('/opt/idea/bin/idea.png').read }
That will delay the file read until converge time instead of compile time.

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

Chef 12.0.3: Why I can't find my own provider on Resource Collection?

I wrote my own provider which runs ok, for example:
my_custom_provider "#{node['ipaddress']}" do
my_attribute_1 node['ipaddress']
action :create
end
template '/opt/app/something.conf' do
mode '0664'
owner 'someuser'
group 'someuser'
notyfies :restart, "my_custom_provider[#{node['ipaddress']}]", :delayed
end
I receiving error (under chef-solo in Vagrant):
ERROR: resource template[/opt/app/something.conf] is configured to notify
resource my_custom_provider[10.0.2.15] with action restart, but
my_custom_provider[10.0.2.15] cannot be found in the resource collection.
template[/opt/app/something.conf] is defined in
/tmp/vagrant-chef/2a59b2477390af49acec413909d80cf5/cookbooks/project/recipes/default.rb:76:in `from_file'
But when I reverse direction of notification it works fine:
my_custom_provider "#{node['ipaddress']}" do
my_attribute_1 node['ipaddress']
action :create
subscribes :restart, 'template[/opt/app/something.conf]', :delayed
end
template '/opt/app/something.conf' do
mode '0664'
owner 'someuser'
group 'someuser'
end
I think this is a bug in chef-solo run under vagrant or maybe I can't add my custom providers as notification target ?
To get notifications working on your custom LWRPs, you might want to look at the example here in chef docs https://docs.chef.io/lwrp_custom_provider.html#updated-by-last-action

Chef execute block

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.

Resources