5

I'm trying to figure out how can I construct the path to templates (or files, since it works the same way) folder, then I could read it and use template resource in the loop, so each template file could trigger notification on change.

I can't use remote_directory because I want to notify services only if template changes.

I also would like to avoid manual template specification, since there could be many files inside those dirs. Plus it would allow us to change just configs in the templates folder without touching recipe.

The main problem is those subdirectories like default, host, host-version and the logic chef goes through to determine correct templates folder. I was thinking maybe there is a method in one of the Chef classes I could call from my custom cookbook to get to the starting point for my logic (loop).

It should be something like this I think:

entry_point = CHEF::...getEntryPointDir entry_point.glob.. .each do template fname do ... end end 

I would appreciate any help!

4 Answers 4

9

WARNING: This solution uses a private interface which may change or be removed without warning. Chef does not currently (13.x) provide a supported way of solving this problem - consider an alternative approach to solving your requirement.

Now that you've been warned, here's how you would do it in a recipe:

# Get the Chef::CookbookVersion for the current cookbook cb = run_context.cookbook_collection[cookbook_name] # Loop over the array of files. # 'templates' will also work. cb.manifest['files'].each do |cookbookfile| Chef::Log("found: " + cookbookfile['name']) end 

I've shared an example recipe to show this in context.

In practice, this needs to be more complicated - for example, you may only want a subset of the files/templates in the cookbook, or need to transform paths in some way. Consider writing a library function that makes a list of the files you are interested in, and calling that from your recipe.

2
  • Thanks for your answer, I'll give it a try. The main problem I faced was that chef would transfer only files or templates that are defined in the recipe. Commented Aug 6, 2013 at 18:28
  • Tested your solution and it worked! Thanks for that! Commented Jan 24, 2014 at 1:19
4

Thanks "zts". I created one to create template directory with all .erb files inside it.

cb = run_context.cookbook_collection[cookbook_name] # you may get 'files' OR 'templates' from manifest cb.manifest['templates'].each do |tmpl_manifest| filepath = tmpl_manifest['path'] next if not filepath =~ /#{cmk_colo}\/server\/checks\/.*erb/ filename = tmpl_manifest['name'].split(".erb")[0] fileshortpath=filepath.split("/",3)[2] template "/opt/omd/sites/prod/etc/check_mk/conf.d/checks/#{filename}" do source fileshortpath mode '0644' owner 'prod' group 'prod' end end 

this one gets full/long path to all .erb files in templates dir. If path matches to name of directory you want to loop though, it creates it via standard template recipe.

4

Thanks to @zts & @Zaur. I thought I'd post my complete answer which ended up combining both. The biggest thing to note is that your cookbook name must be in quotes. That wasn't obvious to me and was a bit of a blocker in my case.

2nd, instead of using @Zaur's RegEx search for filtering file paths, I'm using a more "ruby-way" of doing string comparison to see if the path contains a specific directory:

# Get the Chef::CookbookVersion for this cookbook cb = run_context.cookbook_collection['cookbook_name'] # Loop over the array of files cb.manifest['files'].each do |cbf| # cbf['path'] is relative to the cookbook root, eg # 'files/default/foo.txt' # cbf['name'] strips the first two directories, eg # 'foo.txt' filepath = cbf['path'] filename = cbf['name'] next if not filepath.include? "directory-to-filter-for/" cookbook_file "/etc/service/conf.d/#{filename}" do source "directory-to-filter-for/#{filename}" mode 0600 owner "root" group "root" end end 

I'm using this for files, but you can use templates as well. Just substitute the 'template' block instead of the 'file' block at line 14. Then change line 5 to use templates instead of files:

cb.manifest['templates'].each do |cbf| 
0
1

In Chef > 12.19 there is a breaking change (RFC 67) to the manifest which combines all files in a cookbook under :all_files

See https://chef.github.io/chef-rfc/rfc067-cookbook-segment-deprecation.html

To return a list of all templates, you now use:

run_context.cookbook_collection[:examplecookbook].files_for('templates')

1

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.