I'm very new to Chef and am trying to figure out templating (which seems really cool). In my old deploy structure, I had a directory which I simply wanted to copy over. It had a number of configuration parameters scattered about throughout the files in the directory. I have gone ahead and tried to abstract those parameters away into an attribute file (much cleaner), but am having trouble installing it with Chef. I have modified the extensions of all the files with ERB in them to end with .erb (I come from a Rails background, so this seems natural to me). For instance, I had a file named run.conf, and it is now named run.conf.erb.
Ideally I'd like to have one template block in the recipe which just copies over all the files in the directory and updates those .erb files (removing the .erb extension) with the variables I provide. Here is an example of where I'm at so far:
template "#{node["dcm4chee"]["home"]}" do
source "server/"
variables(
"java_mem_opts" => node["dcm4chee"]["java_mem_opts"],
"db_username" => node["dcm4chee"]["admin"]["username"],
"db_password" => node["dcm4chee"]["admin"]["password"],
"db_hostname" => node["mysql"]["hostname"],
"db_port" => node["mysql"]["port"]
)
end
I have put a folder called server under templates/default and that folder contains the files I want templated. The #{node["dcm4chee"]["home"]} variable is the location of where I want to put the files on the target machine. Ideally I'd like to do this without naming specific files within the recipe because that way I don't have to touch the recipe if I modify the contents of the server directory for deployment.
Is this possible? If so what am I doing wrong? If not, what are my alternatives.
Thanks
EDIT
After thinking about this a bit, I tried to use some custom ruby code to do this. Here is my current attempt which is failing with a NoMethodError referring to tempate_dir from the initial call within the ruby_block.
def template_dir(file)
Dir.foreach("server") do |file|
if File.file?(file)
template "#{node["dcm4chee"]["home"]}/#{file}" do
source "server/#{file}"
variables(
"java_mem_opts" => node["dcm4chee"]["java_mem_opts"],
"db_username" => node["dcm4chee"]["admin"]["username"],
"db_password" => node["dcm4chee"]["admin"]["password"],
"db_hostname" => node["mysql"]["hostname"],
"db_port" => node["mysql"]["port"]
)
end
else
directory "#{node["dcm4chee"]["home"]}/#{file}" do
action :create
end
template_dir(file)
end
end
end
ruby_block "template the whole server directory" do
block do
template_dir("server")
end
end
You could define template_dir
inside of your ruby_block
instead of at the top level- that will work just fine.
find
is a part of the Ruby standard library, and will recursively walk through a directory. Using it would result in something slightly cleaner:
ruby_block "recursive templating" do
block do
require 'find'
root = 'server'
Find.find(root) do |file|
if File.file?(file)
template "#{node["dcm4chee"]["home"]}/#{file}" do
source file
variables(
"java_mem_opts" => node["dcm4chee"]["java_mem_opts"],
"db_username" => node["dcm4chee"]["admin"]["username"],
"db_password" => node["dcm4chee"]["admin"]["password"],
"db_hostname" => node["mysql"]["hostname"],
"db_port" => node["mysql"]["port"]
)
end
end
end
end
end
In general, if you're writing any sort of mildly complicated logic, you should consider writing an LWRP instead of putting it into your recipe. The two-phase compilation/execution thing causes a lot of unintuitive behavior (like the fact that the block can't look up template_dir
), and because writing an LWRP lets you validate input, write tests, and do a better job of ensuring idempotency.
Also, I'm a little confused about the 'server' string you have- I'm not sure in what environment that will resolve to your templates
directory. In any case, if you want to get access to a list of all the templates in your cookbook, there is an array available here: run_context.cookbook_collection[cookbook_name].template_filenames
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With