AnsibleUndefinedVariable: 'unicode object' has no attribute u'xxx'

Ansible通过jinja2模块对后缀为.j2的文件进行jinja模板渲染,某一次在引用一个类似python dict的配置文件变量时报出了如上错误。

这里直接参考一个ansible github issue中的示例进行解释:

"AnsibleUndefinedVariable: 'unicode object' has no attribute when dict in json format · Issue #19356 · ansible/ansible (github.com)

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格式,否则不合法。
posted @ 2021-02-23 16:16  realcp1018  阅读(2274)  评论(0编辑  收藏  举报