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格式,否則不合法。
