Chef:强制在模板中使用修改后的属性
Chef: Force use of modified attributes in template
我有菜鸟厨师的问题。我需要更新模板中的目录路径并将其复制到两个不同的地方。尽管模板文件相同,但每个实例的目录路径不同。
我有以下属性文件 (default.rb):
node['conf_dir'] = '/opt/app/etc'
我有以下模板文件 (myconfig.conf.erb):
ConfigDir = <%= node['conf_dir'] %>
我的食谱文件中有以下内容:
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
我希望在 /opt/app/etc/myconfig.conf 中看到 ConfigDir 的值为“/opt/app/etc”并且我希望在 /opt/newapp/etc/myconfig.conf 中看到 ConfigDir具有“/opt/newapp/etc”的值。当我尝试 运行 配方时,两个应用程序的 configDir 都指向 newapp 目录。为什么我对属性的更新没有生效?厨师可以做这样的事情吗?如果是这样,非常感谢任何指针。谢谢
[不是稳健的解决方案]
在配方 中以相同优先级 定义的属性比属性文件 中 定义的属性具有更高的优先级(Ohai 的自动属性永远不会更改).您可以查看 attributes precedence in details。在你的情况下,我会使用模板和变量方法,所以你的食谱看起来像:
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
您的属性文件也需要明确指定优先级,因此它将是 node.default['conf_dir'] = '/opt/app/etc'
并且模板文件将使用变量 ConfigDir = <%= @conf_dir %>
。在上面的代码片段中,我还留下了 pp node.debug_value('conf_dir')
行,这 非常 对调试很有用。
如果您使用 include_recipe
,您可以在 运行 时覆盖属性,但我发现它对您的情况没有用。
这个答案有两个部分,一个是解决原始问题,另一个是针对这个用例提供更好的方法。
1)
因为我非常反对在另一个答案中提到的方式,所以我会利用 lazy evaluation:
写一个
模板:
ConfigDir = <%= @conf_dir %>
食谱:
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
这样模板的变量实际上是由配方配置的,无论环境、角色或其他配方做什么,因为节点对象的更改是在模板渲染之前完成的,惰性求值与分辨率不同什么值是 node['config']
直到需要它(在收敛阶段)
2)
旁注:您做事的方式很容易出错,并且会成为维护的噩梦,我建议您回顾一下您做事的方式,例如:
属性文件:
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'
用于定义散列的属性的替代语法:
node['apps']['app'] = { conf_dir: '/opt/app/etc',
owner: 'root',
group: 'root'
}
模板:
ConfigDir = <%= @conf_dir %>
食谱:
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
这样您就不会再在 runtime/compile 时弄乱节点对象,并且您可以轻松添加另一个应用程序而无需再次复制粘贴模板定义。
对于那些想知道双引号和单引号混合的人,变量的插值 #{var}
只发生在双引号内,并且它的用法是在固定字符串上保留单引号以区分它们。
不建议您尝试这样做。如果两个不同的文件需要两个不同的值,那么您真的应该使用两个不同的节点属性。
attributes/default.rb
default['app']['conf_dir'] = '/opt/app/etc'
default['new_app']['conf_dir'] = '/opt/new_app/etc'
模板
ConfigDir = <%= @conf_dir %>
食谱
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
我有菜鸟厨师的问题。我需要更新模板中的目录路径并将其复制到两个不同的地方。尽管模板文件相同,但每个实例的目录路径不同。
我有以下属性文件 (default.rb):
node['conf_dir'] = '/opt/app/etc'
我有以下模板文件 (myconfig.conf.erb):
ConfigDir = <%= node['conf_dir'] %>
我的食谱文件中有以下内容:
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
我希望在 /opt/app/etc/myconfig.conf 中看到 ConfigDir 的值为“/opt/app/etc”并且我希望在 /opt/newapp/etc/myconfig.conf 中看到 ConfigDir具有“/opt/newapp/etc”的值。当我尝试 运行 配方时,两个应用程序的 configDir 都指向 newapp 目录。为什么我对属性的更新没有生效?厨师可以做这样的事情吗?如果是这样,非常感谢任何指针。谢谢
[不是稳健的解决方案] 在配方 中以相同优先级 定义的属性比属性文件 中 定义的属性具有更高的优先级(Ohai 的自动属性永远不会更改).您可以查看 attributes precedence in details。在你的情况下,我会使用模板和变量方法,所以你的食谱看起来像:
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
您的属性文件也需要明确指定优先级,因此它将是 node.default['conf_dir'] = '/opt/app/etc'
并且模板文件将使用变量 ConfigDir = <%= @conf_dir %>
。在上面的代码片段中,我还留下了 pp node.debug_value('conf_dir')
行,这 非常 对调试很有用。
如果您使用 include_recipe
,您可以在 运行 时覆盖属性,但我发现它对您的情况没有用。
这个答案有两个部分,一个是解决原始问题,另一个是针对这个用例提供更好的方法。
1)
因为我非常反对在另一个答案中提到的方式,所以我会利用 lazy evaluation:
写一个模板:
ConfigDir = <%= @conf_dir %>
食谱:
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
这样模板的变量实际上是由配方配置的,无论环境、角色或其他配方做什么,因为节点对象的更改是在模板渲染之前完成的,惰性求值与分辨率不同什么值是 node['config']
直到需要它(在收敛阶段)
2)
旁注:您做事的方式很容易出错,并且会成为维护的噩梦,我建议您回顾一下您做事的方式,例如:
属性文件:
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'
用于定义散列的属性的替代语法:
node['apps']['app'] = { conf_dir: '/opt/app/etc',
owner: 'root',
group: 'root'
}
模板:
ConfigDir = <%= @conf_dir %>
食谱:
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
这样您就不会再在 runtime/compile 时弄乱节点对象,并且您可以轻松添加另一个应用程序而无需再次复制粘贴模板定义。
对于那些想知道双引号和单引号混合的人,变量的插值 #{var}
只发生在双引号内,并且它的用法是在固定字符串上保留单引号以区分它们。
不建议您尝试这样做。如果两个不同的文件需要两个不同的值,那么您真的应该使用两个不同的节点属性。
attributes/default.rb
default['app']['conf_dir'] = '/opt/app/etc'
default['new_app']['conf_dir'] = '/opt/new_app/etc'
模板
ConfigDir = <%= @conf_dir %>
食谱
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