Chef template resource to execute if the source template changes? - ruby

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.

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.

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 - 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.

Test file initialization based off template using ChefSpec

I've got the following template file creation in my cookbook:
template "my_file" do
path "my_path"
source "my_file.erb"
owner "root"
group "root"
mode "0644"
variables(#template_variables)
notifies :restart, resources(service: "my_service")
end
and the following assertions in my ChefSpec tests:
chef_run.should create_file "my_file"
chef_run.file("my_file").should be_owned_by('root', 'root')
Which results in the following failure:
No file resource named 'my_file' with action :create found.
This is due to the fact that I am not using afile resource but a template resource. Question: How can I test for file creation off a template resource using ChefSpec?
There are two ways to solve your problem.
First, you can use the create_template matcher. This will match only "template" resources in the run context:
expect(chef_run).to create_template('my_file')
This matcher is also chainable, so you can assert attributes:
expect(chef_run).to create_template('my_file')
.with_path('my_path')
.with_owner('root')
However, this matcher won't actually render the template. So you can't check if you've setup file-specificity correctly.
There's also a top-level matcher for any kind of "file" (file, cookbook_file, and template) that actually renders the contents in memory:
expect(chef_run).to render_file('my_file').with_content(/^match me$/)
You can find more information about render_file in the README.
According to the docs (https://github.com/acrmp/chefspec) you should be able to use:
expect(chef_run).to create_file 'my_file'
I think something changed very recently (possibly the version of chefspec on rubygems), however, because tests I had passing earlier today (using the same syntax you are using) are now suddenly failing.

Resources