Why chef does not execute recipe line by line? - ruby

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

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') }

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.

chef - making yum localinstall of cookbook_file

I have some certain rpm's that need to be moved to a box, and yum localinstall'ed there.
Now I know how to make notifies for upon file creation yum would install something from repo, but I don't know how to specify source in this case.
So for now, I have the following:
cookbook_file "mksh-39-5.el6.x86_64.rpm" do
path "/tmp/mksh-39-5.el6.x86_64.rpm"
action :create
end
package "mksh-39-5.el6.x86_64.rpm" do
source "/tmp/mksh-39-5.el6.x86_64.rpm"
action :install
end
The question is - how do I bind them, so that installation would be called upon file creation?
The brief answer is "use notifications" but as you talk about many files I would loop over a list like this:
['mksh-39-5.el6.x86_64.rpm','package2.rpm'].each do |p| # start from an array of packages, could be an attributes like node['my_namespace']['packages']
package p do # no need to do interpolation here, we just need the name
source "/tmp/#{p}" # Here we have to concatenate path and name
action :nothing # do nothing, just define the resource
end
cookbook_file "/tmp/#{p}" do # I prefer setting the destination in the name
source p # and tell the source name, so in case of different platfom I can take advantage of the resolution of files withint the cookbook tree
action :create
notifies :install, "package[/tmp/#{p}]", :immediately
end
end
The :immediately is to fire the package install as soon as the file has been placed, if there's dependencies, you'll have to manage the order of the packages in the array

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.

Chef - template inside a provider not finding source

I have a little resource and provider for nginx sites which writes out a config file for a site.
action :start do
template "/etc/nginx/sites-enabled/my_site" do
source "nginx_site.conf.erb"
notifies :reload, "service[nginx]"
end
end
When I use it from another cookbook the template nginx_site.conf.erb is not found as chef is looking for a template where this resource is called from.
Is there a way to tell chef to look for a template inside the nginx resource & provider cookbook?
You can set cookbook value for template.
action :start do
template "/etc/nginx/sites-enabled/my_site" do
source "nginx_site.conf.erb"
notifies :reload, "service[nginx]"
cookbook 'nginx'
end
end

Resources