Ansible通过jinja2模块对后缀为.j2的文件进行jinja模板渲染,某一次在引用一个类似python dict的配置文件变量时报出了如上错误。
这里直接参考一个ansible github issue中的示例进行解释:
ansible配置文件中有如下一个变量:
[nginx:vars] nginx_upstream_check_upstreams={ "yAuthAPI": { "enable": true, "http_send": "GET / HTTP/1.0\r\n\r\n", "expect_alive": "http_2xx" }, "yAuthServer": { "enable": true, "http_send": "GET / HTTP/1.0\r\n\r\n", "expect_alive": "http_2xx" }}
上述配置中,变量名为nginx_upstream_check_upstreams,变量的值是json格式的。
作者引用上述变量的jinja模板为:
{% for backend in nginx_backends %} upstream {{ backend }} { ip_hash; {% for host in nginx_backends[backend] %} server {{ host }}; {% endfor %} {% if nginx_upstream_check_enable %} {% if nginx_upstream_check_upstreams[backend].enable %} check interval=5000 rise=1 fall=3 timeout=4000 type=http; check_http_send "{{ nginx_upstream_check_upstreams[backend].http_send }}"; check_http_expect_alive {{ nginx_upstream_check_upstreams[backend].expect_alive }}; {% endif %} {% endif %} }
报错为:
fatal: [10.2.79.1]: FAILED! => {"changed": false, "failed": true, "msg": "AnsibleUndefinedVariable: 'unicode object' has no attribute u'yAuthAPI'"}
模板中的其他地方忽略,只要注意其中的nginx_upstream_check_upstreams[backend],这里就是出错的地方。
报错提示的比较明显,就是出现了一个ansible未定义的变量,其类型为unicode object,且其没有yAuthAPI的属性。
这说明ansible把nginx_upstream_check_upstreams这个变量当成了一个unicode解析,这显然不符合预期,我们希望ansible将其当做一个dict进行解析。
仔细看下nginx_upstream_check_upstreams的值发现: "enable": true,这里显然有问题,python中的bool类型True才是合法值,这里的true未首字母大写,所以ansible解析时只能将其当做一个字符类型。
解决办法就是将上述true改为True,这才是合法的python bool值,才可以被jinja2模块解析。
我自己遇到的问题:
与上述问题类似,也是在引用一个json格式的变量时出错,只不过我是其中有一段类似 "enable": null。在python中none才是合法的值。
之所以生成的是null是因为配置文件是使用基于java的freemarker模板进行渲染的。
总结:
在ansible的j2文件中渲染jinja模板时,如果使用了json格式的变量,且想要将其当做一个python dict引用,那么就需要验证好json的格式,确保其可以正确的使用python语言解析,类似true,null这种字符需要使用True,None代替,或者使用其他方法变通。
一种简单的验证方式为,使用python/ipython命令行将对应的json值直接赋给一个python变量,如果正常说明符合python的dict格式,否则不合法。