如何在Ansible uri模块的JSON字符串中使用变量?
我在Ubuntu 16.10系统上使用Ansible 2.5.3版本,想在Ansible uri模块的body参数对应的JSON字符串里嵌入变量,结果遇到了变量无法正确展开的问题,还报了错。
我的角色任务写法:
- name: REST POST Example uri: url: "{{ webapp_url }}/api/orgs" method: POST return_content: yes body: "{ \"name\": \"{{ project_name }}\" }" validate_certs: no user: "{{ user }}" password: "{{ password }}" force_basic_auth: yes headers: Content-Type: "application/json"
剧本中定义的变量:
--- - hosts: all gather_facts: no vars: project_name: "SAMPLE_PROJECT"
运行时的报错信息:
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: unhashable type
fatal: [localhost]: FAILED! => {"changed": false, "content": "", "msg": "Status code was -1 and not [200]: An unknown error occurred: unhashable type", "redirected": false, "status": -1, "url": "https://webapp/api/orgs"}
如果把body参数硬编码成body: "{\"name\": \"SAMPLE_PROJECT\"}"就能正常运行,但我需要用变量,请问该怎么修正写法?
解决方法:
你遇到的问题是因为手动写JSON字符串时,Jinja2变量解析和JSON转义规则冲突导致的,这里有两种更可靠的写法:
方法1:用Jinja2的to_json过滤器生成JSON
不需要手动拼接JSON字符串,直接构造字典再通过过滤器转成JSON,变量会被正确解析:
- name: REST POST Example uri: url: "{{ webapp_url }}/api/orgs" method: POST return_content: yes body: "{{ {'name': project_name} | to_json }}" validate_certs: no user: "{{ user }}" password: "{{ password }}" force_basic_auth: yes headers: Content-Type: "application/json"
方法2:启用body_format: json参数(推荐)
Ansible的uri模块自带body_format参数,设置为json后,你可以直接传入Python字典结构,模块会自动帮你转换成标准JSON格式,完全不用处理转义问题,代码可读性也更高:
- name: REST POST Example uri: url: "{{ webapp_url }}/api/orgs" method: POST return_content: yes body: name: "{{ project_name }}" body_format: json validate_certs: no user: "{{ user }}" password: "{{ password }}" force_basic_auth: yes
这两种方法都能解决变量无法展开的问题,优先推荐方法2,它更贴合Ansible的最佳实践,也不容易出错。
内容的提问来源于stack exchange,提问作者u123

