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!

gansbrest
  • 785
  • 1
  • 8
  • 17

4 Answers4

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.

zts
  • 945
  • 5
  • 8
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.

Zaur
  • 141
  • 3
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|
BoomShadow
  • 405
  • 1
  • 4
  • 9
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')

oldchili
  • 11
  • 1
  • updated link https://github.com/chef-boneyard/chef-rfc/blob/master/rfc067-cookbook-segment-deprecation.md – Dave Jun 30 '21 at 10:45