У меня есть код, включающий json_query в цикле, который я пытаюсь сделать условным. Но я думаю, что есть что-то, чего я не понимаю в предложениях when и циклах.
Следующий код работает нормально, когда выполняется условие (IaC.status == 400), проблема в том, что когда условие не выполняется, 2-я задача все еще выполняется, цикл пытается обработать IaC2, которого не существует, и задача не выполняется с: "Invalid data passed to 'loop', it requires a list, got this instead:
Я думаю, что на самом деле это ожидаемое поведение для условных операторов и циклов: (https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html#using-conditionals-in-loops), но описанное решение чтобы пропустить всю задачу, нужно использовать пустой итератор, но я понятия не имею, как объединить его с оператором json_query().
Кто-нибудь знает, как я могу действительно сделать вторую задачу ниже условной?
# The preceding code has made a RESTful API call to create a gitlab group, if the group
# exists the return status is 400, so I need to look it up instead. In which case the
# following code works fine. The problem is when IaC.status = 201 for some reason the loop
# in the 2nd task below tries to run, despite the when clause, and fails
# because the variable IaC2 doesn't exist
- name: or if IaC already exists
when: IaC.status == 400
uri:
url: https://{{new_hostname}}/api/v4/groups
method: GET
headers:
Authorization: "Bearer {{token.json.access_token}}"
body_format: json
body:
name: "IaC"
top_level_only: true
status_code: 200
validate_certs: yes
register: IaC2
- name: json_query to find the IaC group id when status = "{{IaC.status}}"
when: IaC.status == 400
debug:
var: item
loop: "{{ IaC2 | community.general.json_query(jmesquery) }}"
vars:
jmesquery: "json[?name=='IaC'].id"
register: group_id
Вы должны обусловить свою вторую задачу первой задачей:
- name: json_query to find the IaC group id when status = "{{IaC.status}}"
when: IaC2 is defined
debug:
var: item
loop: "{{ IaC2 | community.general.json_query(jmesquery) }}"
vars:
jmesquery: "json[?name=='IaC'].id"
register: group_id
Я не могу воспроизвести ваш случай на ansible 2.9.10, где задача пропускается, как и ожидалось. Но вы также можете помочь со значением по умолчанию. Я думаю, это сработает:
- name: json_query to find the IaC group id when status = "{{IaC.status}}"
when: IaC2 is defined
debug:
var: item
loop: "{{ IaC2 | community.general.json_query(jmesquery) | default([]) }}"
vars:
jmesquery: "json[?name=='IaC'].id"
register: group_id
Привет, боюсь, ни один из них не сработал. Одна проблема заключается в том, что регистровая переменная всегда создается, даже если задача, которая ее создает, пропускается. Я использую ansible 2.10.4, если это имеет значение.
Это не сработает, потому что, как указано в комментарии OP, IaC2
всегда будет определено: существует регистр, независимо от того, выполнена ли задача успешно, неудачно или пропущена. Он просто не содержит той же информации => when: IaC2 is succeeded
. docs.ansible.com/ansible/latest/user_guide/…
цель состояла в том, чтобы избежать ошибки «var не определен». Это все та же ошибка? Можете ли вы опубликовать вывод ansible-playbook с -vv?
У меня есть своеобразный ответ. Во-первых, я не совсем понял две вещи;
register
(IaC2) всегда создается, даже если задача uri
пропущена. И IaC2 имеет совершенно другую структуру в зависимости от того, выполняется эта задача или пропускается.Настоящая проблема заключалась в том, что jmesquery искал переменную IaC2 с определенной структурой json, которой нет в случае, когда задача uri
пропускается.
Таким образом, решение, которое кажется работающим, заключается в проверке того, была ли пропущена задача uri
(when: IaC2.skipped is defined
), и если она была пропущена, повторное определение IaC2
в форме пустого списка, что не прерывает цикл.
Примеры кода показаны ниже.
Итак, это работает, но я не могу отделаться от мысли, что должен быть более простой способ сделать это?
- name: If IaC already exists (IaC.status == 400) then get the list of existing groups.
when: IaC.status == 400
uri:
url: https://{{new_hostname}}/api/v4/groups
method: GET
headers:
Authorization: "Bearer {{token.json.access_token}}"
body_format: json
body:
name: "IaC"
top_level_only: true
status_code: 200
validate_certs: no
register: IaC2
# To avoid breaking the following loop that searches the groups in the case that
# the group was created, re-define IaC2 into a form that won't break it.
- name: Not created group "IaC", so redefine IaC2 var so as not to break the following loop
when: IaC2.skipped is defined
set_fact:
IaC2: '{{ {"json": []} }}'
- name: json_query to find the IaC group id when status = "{{IaC.status}}"
#when: IaC.status == 400 << Leave in or comment out, makes no difference
debug:
var: item
loop: "{{ (IaC2 | community.general.json_query(jmesquery)) }}"
vars:
jmesquery: "json[?name=='IaC'].id"
register: group_id
- name: record the IaC group's id (400)
when: IaC.status == 400
set_fact:
IaC_group_id: "{{group_id.results[0].item}}"
Ваше предложение цикла всегда будет интерпретироваться независимо от условия when. Более того, условие будет проверяться на каждой итерации, даже если оно всегда ложно. Я сомневаюсь, что IaC2 не существует, поскольку это регистр. Однако он может быть пустым (отладка была бы очень полезна). Вероятно, вы можете исправить это, назначив значение пустого списка по умолчанию (
[]
) для IaC2, когда оно равно нулю или пусто, чтобы ваше выражение цикла возвращало пустой список. См. фильтрdefault
и его второй необязательный аргумент (true
)