Преобразование строки в целое число в Ansible Playbook

Вопрос или проблема

Я получаю значение с помощью команды 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

Решение

  1. Проверка структуры переменной: Обратите внимание, что переменная message_count может быть более сложной структурой (например, словарем), а не просто строкой. Поэтому для извлечения значения счетчика вам необходимо правильно обработать его.

  2. Избегайте ненужных set_fact: Вы можете выполнить преобразование и в условии when.

  3. Правильное преобразование: В условии 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 обрабатывает переменные не так, как вы ожидаете, и всегда следует проверять тип данных перед их использованием. В случае с числами следует избегать лишних преобразований, где это возможно. Так же стоит проверять выдаваемый результат команд на правильность и соответствие ожидаемым значениям.

Оцените материал
Добавить комментарий

Капча загружается...