Я использую Ansible и столкнулся с проблемой, которую не понимаю или не знаю, как решить. Надеюсь, кто-нибудь может мне помочь.
Проблема возникает с условием failed_when:
fatal: [localhost]: FAILED! => {
"msg": "The conditional check ''must not contain special characters or whitespace' not in result.results[0].json['localizedMessage']' failed. The error was: error while evaluating conditional ('must not contain special characters or whitespace' not in result.results[0].json['localizedMessage']): 'dict object' has no attribute 'results'"
}
Моя задача:
- name: Create instance - must not contain special characters or whitespace
uri:
url: "https://{{PROXY_ADDRESS}}/api/sol005/etsi/nslcm/v2/ns_instances"
status_code: 400
validate_certs: no
body_format: json
method: POST
headers:
Content-type: application/json
Authorization: "{{'Bearer'+' '+access_token}}"
Version: "2.0.0"
Accept: "*/*"
body: >
{ "nsdId": "instance::int::1.0",
"nsName": "{{ item }}",
"nsDescription": "Test instance with name containing invalid characters."
}
register: result
# - set_fact:
# localizedMessage: "{{ result.results[0].json['localizedMessage'] }}"
with_items:
- "caesar:test"
failed_when: "'must not contain special characters or whitespace' not in result.results[0].json['localizedMessage']"
При попытке отладки я написал следующее:
- debug:
msg:
- "============ Printing result output =========== = "
- "Showing result type: {{ result | type_debug }}"
- "Showing result contents: {{ result}}"
- "Showing result.keys(): {{ item }}"
with_items: "{{ result.keys() }}"
- debug:
msg:
- "============ Printing result.results output =========== = "
- "Showing result.results type: {{ result.results | type_debug }}"
- "Showing result.results contents: {{ result.results }}"
- debug:
msg:
- "============ Printing result.results[0] output =========== = "
- "Showing result.results[0].type: {{ result.results[0] | type_debug }}"
- "Showing result.results[0].contents: {{ result.results[0] }}"
- "Showing result.results[0].keys(): {{ item }}"
with_items: "{{ result.results[0].keys() }}"
- debug:
msg:
- "============ Printing result.results[0].json output =========== = "
- "Showing result.results[0].json type: {{ result.results[0].json | type_debug }}"
- "Showing result.results[0].json contents: {{ result.results[0].json }}"
- "Showing result.results[0].json.keys(): {{ item }}"
with_items: "{{ result.results[0].json.keys() }}"
- debug:
msg:
- "============ Printing result.results[0].json.localizedMessage output =========== = "
- "Showing result.results[0].json.localizedMessage type: {{ result.results[0].json.localizedMessage | type_debug }}"
- "Showing result.results[0].json.localizedMessage contents: {{ result.results[0].json.localizedMessage }}"
Где, я думаю, важная информация здесь:
"============ Printing result output =========== = ",
"Showing result type: dict",
"Showing result.keys(): dict_keys(['results', 'msg', 'changed'])"
"============ Printing result.results output =========== = ",
"Showing result.results type: list",
"============ Printing result.results[0] output =========== = ",
"Showing result.results[0].type: dict",
"Showing result.results[0].keys(): dict_keys(['redirected', 'url', 'status', 'x_content_type_options', 'x_xss_protection', 'cache_control', 'pragma', 'expires', 'strict_transport_security', 'x_frame_options', 'vary', 'content_type', 'transfer_encoding', 'date', 'connection', 'server', 'msg', 'elapsed', 'changed', 'json', 'invocation', 'failed', 'item', 'ansible_loop_var'])"
"============ Printing result.results[0].json output =========== = ",
"Showing result.results[0].json type: dict",
"Showing result.results[0].json.keys(): dict_keys(['url', 'localizedMessage', 'details'])"
"============ Printing result.results[0].json.localizedMessage output =========== = ",
"Showing result.results[0].json.localizedMessage type: AnsibleUnsafeText",
"Showing result.results[0].json.localizedMessage contents: A INVALID_REQUEST error has occurred: name must not contain special characters or whitespace (excluding: '-', '_')"
Я новичок в Ansible, возможно, поэтому я его не вижу, но формулировка 'dict object' has no attribute 'results' предполагает, что result, который является диктовкой, не имеет атрибута results, который, согласно моей отладке, он имеет. Мне удалось перейти к result.results[0].json и result.results[0].json.localizedMessage, поэтому мне кажется, что все в порядке.
Кто-нибудь может посоветовать? Я хотел бы понять, где я ошибаюсь, в качестве альтернативы я приму предложения по выполнению проверки failed_when с использованием другого подхода.
^ --- вы говорите нам, что у failed_when есть проблема, но вы не воспроизводите здесь указанное условие.
@β.εηοιτ.βε: Справедливое замечание - я забыл добавить в условие! Я сделаю это и добавлю то, что смогу (опустив что-то деликатное). mdaniel, спасибо за подсказку: задавать вопросы.
Я также протестировал запись через точку: result.results[0].json.localizedMessage с тем же результатом. И я счастлив, что получаю ответ, и это 400 Bad Request.
Ваша проблема связана с тем, что Ansible создает results очень своеобразным образом:
results
создается в словаре, а затем заполняется из всех результатов.Это очень кратко описано в этом предложении и примере:
Во время итерации результат текущего элемента будет помещен в переменную: - name: Place the result of the current item in the variable shell: echo "{{ item }}" loop: - one - two register: echo changed_when: echo.stdout != "one"
Source: https://docs.ansible.com/ansible/2.9/user_guide/playbooks_loops.html#registering-variables-with-a-loop
Итак, если вам нужна самозарегистрированная задача, которая проверяет статус своих собственных элементов, вам просто нужно сделать что-то вроде:
failed_when: "'must not contain special characters or whitespace' not in result.json.localizedMessage"
Вот два примера игр:
- hosts: localhost
gather_facts: no
tasks:
- uri:
url: "{{ item }}"
loop:
- https://httpbin.org/get
- https://httpbin.org/anything
register: result
failed_when: "result.json.url == 'https://httpbin.org/get'"
Это дает резюме:
PLAY [localhost] ***************************************************************************************************
TASK [uri] *********************************************************************************************************
failed: [localhost] (item=https://httpbin.org/get) => {"access_control_allow_credentials": "true", "access_control_allow_origin": "*", "ansible_loop_var": "item", "changed": false, "connection": "close", "content_length": "274", "content_type": "application/json", "cookies": {}, "cookies_string": "", "date": "Fri, 18 Dec 2020 18:17:12 GMT", "elapsed": 0, "failed_when_result": true, "item": "https://httpbin.org/get", "json": {"args": {}, "headers": {"Accept-Encoding": "identity", "Host": "httpbin.org", "User-Agent": "ansible-httpget", "X-Amzn-Trace-Id": "Root=1-5fdcf228-559950431b1315ce1ea53e71"}, "url": "https://httpbin.org/get"}, "msg": "OK (274 bytes)", "redirected": false, "server": "gunicorn/19.9.0", "status": 200, "url": "https://httpbin.org/get"}
ok: [localhost] => (item=https://httpbin.org/anything)
PLAY RECAP *********************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
- hosts: localhost
gather_facts: no
tasks:
- uri:
url: "{{ item }}"
loop:
- https://httpbin.org/get
- https://httpbin.org/anything
register: result
failed_when: "result.json.url == 'https://httpbin.org/anything'"
Это дает резюме:
PLAY [localhost] ***************************************************************************************************
TASK [uri] *********************************************************************************************************
ok: [localhost] => (item=https://httpbin.org/get)
failed: [localhost] (item=https://httpbin.org/anything) => {"access_control_allow_credentials": "true", "access_control_allow_origin": "*", "ansible_loop_var": "item", "changed": false, "connection": "close", "content_length": "362", "content_type": "application/json", "cookies": {}, "cookies_string": "", "date": "Fri, 18 Dec 2020 18:18:40 GMT", "elapsed": 0, "failed_when_result": true, "item": "https://httpbin.org/anything", "json": {"args": {}, "data": "", "files": {}, "form": {}, "headers": {"Accept-Encoding": "identity", "Host": "httpbin.org", "User-Agent": "ansible-httpget", "X-Amzn-Trace-Id": "Root=1-5fdcf280-71b7cca020b6fda0055b4603"}, "json": null, "method": "GET", "origin": "127.0.0.1", "url": "https://httpbin.org/anything"}, "msg": "OK (362 bytes)", "redirected": false, "server": "gunicorn/19.9.0", "status": 200, "url": "https://httpbin.org/anything"}
PLAY RECAP *********************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Отлично @β.εηοιτ.βε - это решило проблему. Я также понял, что в своем коде я использую цикл, то, что я знал, что делаю, но не думал, что это повлияет на то, что вы описали, когда дело доходит до доступа к результатам и использования условного выражения failed_when.
Вы включили много отладочного текста, и это здорово, но не настоящую книгу игр (в идеале как MCVE), так как это, скорее всего, будет простой ошибкой, чем мир вверх ногами.