zap_directory now supports recursive
[https://github.com/nvwls/zap] is a library cookbook for garbage collecting chef controlled resource sets. For those unfamilar with zap, please check out my ChefConf 2014 presentation [http://www.youtube.com/watch?v=4-So4AJlBI4&list=PL11cZfNdwNyMmx0msapJfuGsLV43C7XsA&feature=share&index=53] and the slide deck [https://speakerdeck.com/nvwls/building-authoritative-resource-sets]
A month ago, [https://github.com/withnale] raised the issue that zap_directory
would fail if it encountered subdirectory within the directory you were
zapping. In v0.8.0, I fixed that bug. It will skip directories it encounters.
At the same, I also added the recursive
attribute to zap_directory
. When set
to true, all files under the specified directory will be zapped.
I’ve given you a very sharp stick, don’t hurt yourself with it.
zap_directory "#{eval_to_nil}/etc" do
recursive true
end
This would zap most of /etc. For this reason, when I use zap_directory
I always use an explict directory name instead of an evaluated one.
An Example
Let’s build a recipe for a hypothectical application called crossbar. It has a configuration structure of:
/etc/crossbar/*.conf
/etc/crossbar/inputs/*.conf
/etc/crossbar/outputs/*.conf
Since different nodes will have different inputs and outputs, node attributes will be used to control which conf files are installed. Optionally there is a list of users and groups that have access to crossbar.
In the past you might have done something like this:
template '/etc/crossbar/groups.conf' do
if node['crossbar']['groups'].empty?
action :delete
else
action :create
source 'groups.conf'
variables 'groups' => node['crossbar']['groups']
end
end
%w[foo bar baz].each do |src|
template "/etc/crossbar/inputs/#{n}.conf" do
if node['crossbar']['inputs'].include?(src)
action :create
source "inputs/#{src}.conf"
else
action :delete
end
end
end
Every time you add an input or output type, you’d need to update the lists.
Using zap, you don’t have to worry about this anymore; just create the resource if you need it.
The final recipe may look something like:
package 'crossbar' do
version node['crossbar']['version']
end
# installed by crossbar RPM
file '/etc/crossbar/defaults.conf' do
action :nothing
end
template '/etc/crossbar/groups.conf' do
source 'groups.conf'
variables 'groups' => node['crossbar']['groups']
end unless { node['crossbar']['groups'].empty? }
template '/etc/crossbar/users.conf' do
source 'users.conf'
variables 'groups' => node['crossbar']['users']
end unless { node['crossbar']['users'].empty? }
node['crossbar']['inputs'].each do |src|
template "/etc/crossbar/inputs/#{src}.conf"
source "inputs/#{src}.erb"
end
end
node['crossbar']['outputs'].each do |dst|
template "/etc/crossbar/outputs/"{dst}.conf"
source "outputs/#{dst}.erb"
end
end
zap_directory '/etc/crossbar' do
filter '*.conf'
recursive true
end
The declarative model is easier to understand and maintain. If previous versions of the package laid additional conf files, you would need to maintain the list of files to delete going forward. You don’t know if the node was previously running v1.0, v1.1, or v2.0 you need to cover all the bases.
Hopefully this example helps illustrate the power of the zap paradigm.