chef生成xml模板必须用erb,需手动转义特殊字符、显式指定cookbook和source,并用数组遍历替代硬编码节点以确保xml合法性。

模板语法必须用 ERB,不能用 Mustache 或 Liquid
Chef 默认只支持 ERB 模板引擎生成动态内容,XML 文件本质是纯文本,但 XML 的格式敏感性比 HTML 更高——比如未闭合标签、非法字符、编码不一致都会导致解析失败。所以不能指望 template 资源自动“理解” XML 结构,它只是把 ERB 渲染后的字符串原样写入文件。
常见错误是误以为 Chef 有 XML 专用模板机制,或试图在 .xml.erb 中混用 和原始 XML 实体(如 &),结果渲染出无效 XML。
- 所有变量插值必须包裹在
中,且确保输出内容已做 XML 转义(见下一条) - 避免直接拼接 XML 标签字符串,优先用嵌套结构 + 条件判断控制节点存在性
- 若需输出特殊字符(如
&,, <code>>),必须用CGI.escapeHTML或手动替换,否则生成的 XML 会非法
用 CGI.escapeHTML 转义动态字段值
XML 不允许在文本内容中直接出现 &、、<code>>,而 Chef 的 默认不做转义。例如:@app_name = "Order & Payment" 直接插入会变成 <name>Order & Payment</name>,XML 解析器会报错 Invalid character in entity name。
正确做法是在模板中显式调用转义函数:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<app_name><%= CGI.escapeHTML(@app_name) %></app_name>
<timeout><%= @timeout || 30 %></timeout>
<% if @features.include?('ssl') %>
<ssl_enabled>true</ssl_enabled>
<% end %>
</config>
注意:不要用 h()(Rails 辅助方法),Chef 的 ERB 环境里不可用;也不要依赖外部库,CGI 是 Ruby 标准库,无需额外安装。
template 资源必须指定 cookbook 和 source
很多人写完 myapp.xml.erb 放进 templates/default/,却在资源里漏掉 cookbook 参数,导致 Chef 找不到模板文件,报错 Cannot find a template in cookbook xxx for node yyy。
系统简介逍遥内容管理系统(CarefreeCMS)是一款功能强大、易于使用的内容管理平台,采用前后端分离架构,支持静态页面生成,适用于个人博客、企业网站、新闻媒体等各类内容发布场景。核心特性1、模板套装系统 - 支持多套模板自由切换,快速定制网站风格2、静态页面生成 - 一键生成纯静态HTML页面,访问速度快,SEO友好3、文章管理 - 支持富文本编辑、草稿保存、文章属性标记、自动提取SEO4、全
完整写法必须包含:
-
source:模板文件名(含.erb后缀) -
cookbook:模板所在 cookbook 名(即使当前 cookbook 也要显式写) -
variables:传入哈希,键名即模板中@xxx变量名
示例资源定义:
template '/etc/myapp/config.xml' do
source 'myapp.xml.erb'
cookbook 'myapp-cookbook'
variables(
app_name: node['myapp']['name'],
timeout: node['myapp']['timeout'],
features: node['myapp']['features'] || []
)
mode '0644'
owner 'root'
group 'root'
end
嵌套结构多时,优先用数组遍历而非硬编码节点
当 XML 需要动态生成多个同类子节点(如 <server></server> 列表),别写一堆 ...,用数组 + each 更可靠、易维护。
假设 node['myapp']['servers'] = [{ host: 'a.example.com', port: 8080 }, { host: 'b.example.com', port: 8081 }],模板应这样写:
<servers>
<% @servers.each do |s| %>
<server>
<host><%= CGI.escapeHTML(s[:host]) %></host>
<port><%= s[:port] %></port>
</server>
<% end %>
</servers>
容易被忽略的是:数组元素若为 nil 或空哈希,each 会跳过,不会生成空节点;但如果数组本身是 nil,调用 each 会报错 undefined method `each' for nil:NilClass。所以建议在资源中预处理:servers: node['myapp']['servers'] || []。









