Вопрос или проблема
Я получаю значение с помощью команды PowerShell и сохраняю его в переменной. Мне нужно использовать это значение в условии ‘when’. Я преобразовал его в целое число перед использованием в условии ‘when’. Тем не менее, задача ( уведомление по электронной почте) пропускается, несмотря на то что значение здесь равно 0. Может кто-то подскажет, что я делаю не так? Ниже приведен код, который я выполняю.
- name: Получить message_count
shell: echo "{{ (output.stdout | from_json).MessageCount }}"
register: message_count #message_count здесь равно нулю
delegate_to: localhost
- set_fact:
countt: "{{ message_count | int }}"
#попробовал преобразовать в целое число перед передачей в условие с помощью set_fact
- debug: var=countt
- name: отправить уведомление по электронной почте
mail:
host: abc.zzzz.net
port: 25
from: <[email protected]>
to:
- [email protected]
subject: Тестовое письмо, отправленное с основного сервера
body: Тестовое письмо, отправленное с основного сервера
delegate_to: localhost
when: countt==0
Вот что я сделал, чтобы это заработало:
---
- name: ответить на serverfault
hosts: all
become: yes
tasks:
- name: Получить message_count
shell: ls /tmp/empty | wc -l
register: tmp_count
delegate_to: localhost
- debug: var=tmp_count.stdout
- name: выполнить другое действие, когда tmp_count.stdout == 0
shell: echo "Я это делаю"
delegate_to: localhost
when: tmp_count.stdout | int == 0
Вот результат выполнения плейбука:
ripper@mini-ripper:~/Devel/ansible$ ansip ./test_playbook.yml -i localhost,
PLAY [ответить на serverfault] **************************************************************************************************************************************************************************************
TASK [Сбор данных] ********************************************************************************************************************************************************************************************
[WARNING]: Платформа linux на хосте localhost использует обнаруженный интерпретатор Python по адресу /usr/bin/python, но при будущей установке другого интерпретатора Python это может измениться. См.
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html для получения дополнительной информации.
ok: [localhost]
TASK [Получить message_count] ******************************************************************************************************************************************************************************************
changed: [localhost -> localhost]
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"tmp_count.stdout": "0"
}
TASK [выполнить другое действие, когда tmp_count.stdout == 0] ***************************************************************************************************************************************************************
changed: [localhost -> localhost]
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Так что, подытожим:
- вы должны проверить, не является ли зарегистрированная переменная более сложной структурой – обычно это так
- вам не нужна еще одна пользовательская факция
- вам нужно преобразовать вашу переменную без использования
{{ }}
в условииwhen
Вы, конечно, можете помнить, что то, что вы хотели, чтобы было целым числом, на самом деле преобразуется в строку с помощью Jinja2 в set_fact
. Таким образом, вы можете выполнять преобразование в целое число каждый раз, когда хотите его использовать, как иллюстрируют другие ответы – как здесь, так и в других ответах на Stack Overflow.
Но если вы уверены, что хотите подлинное целое число, конструкция цикла Ansible использует более строгую проверку типов. Поэтому вы можете использовать такой обходной путь:
---
- name: Получить HugePages_Total из /proc/meminfo
shell: grep '^HugePages_Total' /proc/meminfo | awk '{print $2}'
register: hugepages_total_line
changed_when: False
- name: Убедиться в преобразовании в целое число с помощью цикла
set_fact:
hugepages_total: "{{ item }}"
loop: "{{ [hugepages_total_line.stdout_lines[0] | int] }}"
- name: Проверить тип и значение hugepages_total
debug:
msg:
- "HUGEPAGES: {{ hugepages_total }} {{ hugepages_total | type_debug }}"
- "stdout: {{ hugepages_total_line.stdout[0] }}"
- "stdout type: {{ hugepages_total_line.stdout[0] | type_debug }}"
...
Здесь мы сохраняем hugepages_total_line.stdout_lines[0]
как целое число в списке из одного элемента и передаем это в цикл. Внутри цикла "{{ item }}"
к счастью не преобразуется в строку. hugepages_total
будет целым числом.
Очевидно, что hugepages_total
будет установлено на последний элемент в списке, поэтому вам нужно правильно сформировать свой список: убедитесь, что он содержит один элемент. Использование stdout_lines[0]
гарантирует это в данном случае.
Проблема: Вы, вероятно, заметили, что Jinja2 преобразует все или почти все данные переменных в строки, когда они ссылаются таким образом:
set_fact:
i_wish_it_was_an_int: "{{ var_containing_int | int }}"
i_wish_it_was_an_int
никогда не будет целым числом для Ansible в этой ситуации. Для внутренних нужд Jinja2 var_containing_int
преобразуется в целое число, но оно преобразуется обратно в строку перед присвоением i_wish_it_was_an_int
. Таким образом, | int
в данном случае является никчемным.
Проверено с использованием Ansible 2.9.27.
Ответ или решение
Конverting string to integer в Ansible Playbook
В Ansible часто возникает необходимость преобразования строк в целые числа, особенно если вы работаете с результатами команд и хотите использовать эти значения в условиях. Например, как в вашем случае, вы получаете счетчик из команды PowerShell и хотите использовать его в условии для отправки уведомления по электронной почте. Рассмотрим ваш код и предложенные решения.
Проблема
Из вашего кода видно, что вы используете переменную message_count
, но вместо того, чтобы преобразовать значение правильно, вы не получаете ожидаемого результата в части when
для отправки уведомления по электронной почте:
- name: Get message_count
shell: echo "{{ (output.stdout | from_json).MessageCount }}"
register: message_count
delegate_to: localhost
- set_fact:
countt: "{{ message_count | int}}"
- name: send mail notification
mail:
host: abc.zzzz.net
port: 25
from: <[email protected]>
to:
- <[email protected]>
subject: Test mail sent from core server
body: Test mail sent from core server
delegate_to: localhost
when: countt == 0
Решение
-
Проверка структуры переменной: Обратите внимание, что переменная
message_count
может быть более сложной структурой (например, словарем), а не просто строкой. Поэтому для извлечения значения счетчика вам необходимо правильно обработать его. -
Избегайте ненужных
set_fact
: Вы можете выполнить преобразование и в условииwhen
. -
Правильное преобразование: В условии
when
не используйте двойные фигурные скобки{{ }}
при обращении к переменной. Например,when: message_count.stdout | int == 0
.
Теперь давайте посмотрим на исправленный код плейбука:
---
- name: Пример отправки уведомления по электронной почте
hosts: all
become: yes
tasks:
- name: Получить количество сообщений
shell: echo "{{ (output.stdout | from_json).MessageCount }}"
register: message_count
delegate_to: localhost
- debug:
var: message_count.stdout
- name: Отправить уведомление по электронной почте
mail:
host: abc.zzzz.net
port: 25
from: <[email protected]>
to:
- <[email protected]>
subject: Уведомление
body: Уведомление об отсутствии сообщений
delegate_to: localhost
when: message_count.stdout | int == 0
Объяснение кода
-
Получение сообщения: Мы вызываем команду и регистрируем результат в
message_count
. Убедитесь, что вы корректно обрабатываете вывод, который может быть не строкой. -
Отладка: Используйте
debug
, чтобы проверить, что именно содержитmessage_count.stdout
. Это поможет вам понять, что вы получаете из команды. -
Условие
when
: Вместо использования переменнойcountt
, мы используемmessage_count.stdout | int == 0
напрямую в условиях.
Заключение
На протяжении всего процесса важно помнить, что Ansible обрабатывает переменные не так, как вы ожидаете, и всегда следует проверять тип данных перед их использованием. В случае с числами следует избегать лишних преобразований, где это возможно. Так же стоит проверять выдаваемый результат команд на правильность и соответствие ожидаемым значениям.