Reputation: 372
I have noob chef question. I need to update a directory path in a template and copy it to two different places. The directory path is different for each instance although the template file is the same.
I have the following attributes file (default.rb):
node['conf_dir'] = '/opt/app/etc'
I have the following template file (myconfig.conf.erb):
ConfigDir = <%= node['conf_dir'] %>
I have the following in my recipe file:
template '/opt/app/etc/myconfig.conf' do
source 'myconfig.conf.erb'
owner 'root'
group 'root'
mode '0644'
end
# update conf dir for new app
node['conf_dir'] = '/opt/newapp/etc'
template '/opt/newapp/etc/myconfig.conf' do
source 'myconfig.conf.erb'
owner 'root'
group 'root'
mode '0644'
end
I'd like to see the ConfigDir in /opt/app/etc/myconfig.conf to have a value of '/opt/app/etc' and I'd like to see the ConfigDir in /opt/newapp/etc/myconfig.conf to have a value of '/opt/newapp/etc'. When I try to run the recipe, configDir for both app points to the newapp directory. Why is my update to the attribute not taking affect? Is something like this possible with chef? If so, any pointers are much appreciated. Thanks.
Upvotes: 2
Views: 2139
Reputation: 5190
[NOT ROBUST SOLUTION] Attribute defined at the same precedence level in the recipe has higher priority over the one which is defined in attributes file (automatic one by Ohai is never changed). You can check attributes precedence in details. In your case, I would go with template and variable approach, so your recipe will look smth like:
require 'pp'
node.override['conf_dir'] = '/tmp'
pp node.debug_value('conf_dir')
template '/opt/app/etc/myconfig.conf' do
source 'myconfig.conf.erb'
mode '0644'
variables({
:conf_dir => node.default['conf_dir']
})
end
template '/opt/app/etc/myconfig.conf' do
source 'myconfig.conf.erb'
mode '0644'
variables({
:conf_dir => node.override['conf_dir']
})
end
Also your attribute file you need to explicitly specify precedence level, so it will be node.default['conf_dir'] = '/opt/app/etc'
and template file will be using variable ConfigDir = <%= @conf_dir %>
. In the code snippet above I also left pp node.debug_value('conf_dir')
line which is extremely useful for debugging.
You can override attributes at run time if you're using include_recipe
, but I cannot find it useful in your case.
Upvotes: -1
Reputation: 15784
This answer has two part, one fixing the original question, the second giving a better approach for this use case.
1)
As I highly discourage the way mentioned in the other answer I'll write one taking advantage of lazy evaluation:
Template:
ConfigDir = <%= @conf_dir %>
Recipe:
template '/opt/app/etc/myconfig.conf' do
source 'myconfig.conf.erb'
owner 'root'
group 'root'
mode '0644'
variables( conf_dir: node['conf_dir'] )
end
# update conf dir for new app
ruby_block "update conf dir" do
block
node['conf_dir'] = '/opt/newapp/etc'
end
end
template '/opt/newapp/etc/myconfig.conf' do
source 'myconfig.conf.erb'
owner 'root'
group 'root'
mode '0644'
variables(lazy { conf_dir: node['conf_dir'] } )
end
This way the variable for the template is really configured by the recipe, whatever the environment, role or other recipes does as the change in the node object is done just before the template rendering, the lazy evaluation differ the resolution of what value is node['config']
until it is needed (at convergence phase)
2)
Side note: The way you're doing things is highly error prone and will become a nightmare to maintain, I suggest you review your way of doing things in something like:
Attribute file:
node['apps']['app']['conf_dir'] = '/opt/app/etc'
node['apps']['app']['owner'] = 'root'
node['apps']['app']['group'] = 'root'
node['apps']['newapp']['conf_dir'] = '/opt/newapp/etc'
node['apps']['newapp']['owner'] = 'root'
node['apps']['newapp']['group'] = 'root'
Alternative syntax for attributes defining a hash instead:
node['apps']['app'] = { conf_dir: '/opt/app/etc',
owner: 'root',
group: 'root'
}
Template:
ConfigDir = <%= @conf_dir %>
Recipe:
node['apps'].each do |app,properties|
template "/opt/#{app}/etc/myconfig.conf" do
source 'myconfig.conf.erb'
owner properties['owner']
group properties['group']
mode '0644'
variables( conf_dir: properties['conf_dir'] )
end
end
This way you're not messing anymore with node object at runtime/compile time and you have an easy path to add another app without copy pasting the template definition again.
For those wondering the mix between double quotes and single quote, the interpolation of variables #{var}
takes place only inside double quotes, and it's usage to keep single quotes on fixed string to differentiate them.
Upvotes: 2
Reputation: 4223
What you're trying to do is not advised. If you need two different values for two different files, then you really should use two different node attributes.
attributes/default.rb
default['app']['conf_dir'] = '/opt/app/etc'
default['new_app']['conf_dir'] = '/opt/new_app/etc'
template
ConfigDir = <%= @conf_dir %>
recipe
template '/opt/app/etc/myconfig.conf' do
source 'myconfig.conf.erb'
mode '0644'
variables({
:conf_dir => node['app']['conf_dir']
})
end
template '/opt/app/etc/myconfig.conf' do
source 'myconfig.conf.erb'
mode '0644'
variables({
:conf_dir => node['new_app']['conf_dir']
})
end
Upvotes: 1