我正在寻找您的想法,以便在发生from_json
过滤器故障时优雅地处理它。
我有一个角色很普通的任务,用来在sonatype nexus存储库管理器中调用不同的groovy脚本
- name: Calling Groovy script {{ script_name }}
uri:
url: "{{ nexus_api_scheme }}://{{ nexus_api_hostname }}:{{ nexus_api_port }}\
{{ nexus_api_context_path }}{{ nexus_rest_api_endpoint }}/{{ script_name }}/run"
user: 'admin'
password: "{{ current_nexus_admin_password }}"
headers:
Content-Type: "text/plain"
method: POST
force_basic_auth: yes
validate_certs: "{{ nexus_api_validate_certs }}"
body: "{{ args | to_json }}"
register: script_run
我所有的脚本都返回一个json映射
{
"name": "name of the script"
"result": "whatever was used as a groovy return statement"
}
注意:无法从groovy向此地图添加任何其他内容,我只能在result
中将数据推回ansible
现在,我想使用result
进一步详细说明我的脚本调用是否导致错误,更改或正常状态。一些常规脚本完全“可感知”,并且会在result
中返回一个转义的json字符串,我可以使用该字符串检查错误/更改。但是(暂时)其他一些脚本不是“可感知的”(或者我自己无法更改),它们会在result
中返回一个简单的字符串(在大多数情况下,没有任何可用的信息)。>
现在是我真正的问题:如果我得到json结果,我想用它来检查失败或更改。如果不是json结果,我将仅依靠http 200获得成功(直到脚本可以修复)。
我几乎可以在任务中使用以下选项:
failed_when: >-
script_run.status != 200
or
(script_run.json.result | from_json | default({})).error | default(false) | bool
changed_when: >-
(script_run.json.result | from_json | default({})).changed | default(false) | bool
不幸的是,当result
是一个简单的字符串时,from_json
将在应用默认值并将我的剧本结束之前触发错误(Expecting value: line 1 column 1 (char 0)
)。
我当前的解决方法是添加另一个条件,以在尝试读取json之前检查result
是否以{
开头,但是对此我并不满意(因为json字符串可能仍然损坏了仍然会导致错误)
如果您有任何经验/想法如何合理地使用默认值处理此json解码错误或很好地检查字符串是否可以在ansible中解码为json,我将接受所有建议。
答案 0 :(得分:1)
(这是从上面的评论中复制/粘贴的)
我发现用failed_when
/ changed_when
编写复杂的东西很容易失控。您是否尝试过创建过滤器,然后执行类似failed_when: script_run | my_role_failed
的操作?
https://gist.github.com/tuxfight3r/37048ba536575277f5f4d26813d69489
过滤器位于filter_plugins/
下您的角色中,因此分发不成问题。您甚至可以创建空的ansible角色,这些角色仅定义过滤器,然后将它们包含在其他角色中(通过meta/main.yml
)以在其中使用。
答案 1 :(得分:1)
我不确定它是否满足“优雅”的阈值,但我使用了自定义测试插件和jinja2 {{ <something> if <test> else <somethingelse> }}
表达式来解决此问题:
# test_plugins/is_json.py
import json
def is_json(input_string):
''' Tests if input_string is valid JSON
Returns a bool
'''
try:
json.loads(input_string)
return True
except:
return False
class TestModule(object):
def tests(self):
return {
'json': is_json,
}
# test_json_test.yaml
---
- name: 'Test json test'
hosts: localhost
tasks:
- name: 'Give us an empty dict on invalid json'
with_items:
- ' {"somekey": "somevalue"} ' # valid JSON
# ^-extra space here to ensure Ansible treats this as a string
- '{"somekey": "somevalue"}' # valid JSON
- ' { }' # valid
- ' [ ]' # valid
- '[]' # valid
- "I'm not valid JSON" # invalid JSON
debug:
msg: '{{ item if item is json else "{}" }}'
# ^^^^-our test
输出:
PLAY [Test json test] *************
TASK [Gathering Facts] ************
ok: [localhost]
TASK [Give us an empty dict on invalid json] ************
ok: [localhost] => (item= {"somekey": "somevalue"} ) => {
"msg": " {\"somekey\": \"somevalue\"} "
}
ok: [localhost] => (item={'somekey': 'somevalue'}) => {
"msg": {
"somekey": "somevalue"
}
}
ok: [localhost] => (item= { }) => {
"msg": " { }"
}
ok: [localhost] => (item= [ ]) => {
"msg": " [ ]"
}
ok: [localhost] => (item=[]) => {
"msg": []
}
ok: [localhost] => (item=I'm not valid JSON) => {
"msg": {}
}
PLAY RECAP ****************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0