TGViewer
Сочный DevOps Сочный DevOps @andtree_sec · 420 subscribers
Post #210 237
Иногда так бывает, что в инфре нужно поддерживать дистрибутивы EL8 (RedHat семейство 8 версии). Если захотите запустить на них любой модуль работы с пакетами на Ansible версии выше 2.17, то получите ошибку вида:
SyntaxError: future feature annotations is not defined


В чём суть. EL8 поставляется с Python 3.6. Модули Ansible 2.17 внутри используют синтаксис from __future__ import annotations, который появился только в Python 3.7. Отсюда несовместимость. Причём упадут все модули - package_facts, package, yum, dnf, command, setup и другие. Механизм один и тот же: Ansible упаковывает любой модуль через AnsiballZ-фреймворк и запускает его локальным Python-интерпретатором на хосте.
Единственный модуль который не использует Python на хосте вообще — raw. Он передаёт команду напрямую через SSH. Его и будем использовать для фиксов.

Сначала определяем ОС через raw:
- name: "Detect OS family via raw"
ansible.builtin.raw: |
if [ -f /etc/redhat-release ]; then
major=$(rpm -E '%{rhel}' 2>/dev/null || grep -oP '\d+' /etc/redhat-release | head -1)
echo "RedHat:${major}"
else
echo "other"
fi
register: os_detection
changed_when: false


Выставляем флаг:
- name: "Set EL8 flag"
ansible.builtin.set_fact:
is_el8: "{{ os_detection.stdout | trim is search('^RedHat:8') }}"


ansible.builtin.setup запускаем только для не-EL8:
name: "Populate ansible facts"
ansible.builtin.setup:
when: not is_el8


Для EL8 собираем нужные факты через raw:
- name: "Populate ansible facts via raw (EL8)"
# We already now that's 8 major version via is_el8 var
ansible.builtin.raw: |
python3 -c "
import platform, json, subprocess
print(json.dumps({
'ansible_distribution': open('/etc/system-release').read().split()[0],
'ansible_distribution_major_version': '8',
'ansible_os_family': 'RedHat',
'ansible_architecture': platform.machine(),
'ansible_hostname': platform.node(),
}))
" 2>/dev/null
register: raw_facts
changed_when: false
when: is_el8

- name: "Set ansible facts from raw (EL8)"
ansible.builtin.set_fact:
ansible_distribution: "{{ (raw_facts.stdout | trim | from_json).ansible_distribution }}"
ansible_distribution_major_version: "{{ (raw_facts.stdout | trim | from_json).ansible_distribution_major_version }}"
ansible_os_family: "{{ (raw_facts.stdout | trim | from_json).ansible_os_family }}"
ansible_architecture: "{{ (raw_facts.stdout | trim | from_json).ansible_architecture }}"
ansible_hostname: "{{ (raw_facts.stdout | trim | from_json).ansible_hostname }}"
when: is_el8


Все операции с пакетами для EL8 делаем тоже через raw:
- name: "Install package (EL8)"
ansible.builtin.raw: dnf -y install <package_name>
when: is_el8

- name: "Gather package list (EL8)"
ansible.builtin.raw: rpm -qa --qf '%{NAME}\n'
register: rpm_list
changed_when: false
when: is_el8


Можно конечно установить/скомпилировать свежий Python, но иногда нужно работать с тем что есть.

#ansible
  • 👍 2
  • ❤ 1
More from @andtree_sec
  1. Sep 7, 2026Давненько не было сообщений. Скорее всего в будущем они уйдут в telegraf, который я еще не…
  2. Jul 6, 2026Последнее время на работе часто приходится работать с apache flink и даже что-то писать на…
  3. Jun 4, 2026Немножко про молекула тесты... У нас принято использовать в переменных lookup плагин для д…
  4. May 20, 2026Очередной небольшой проект. Веб-приложение, которое агрегирует через стандартный механиз g…
  5. May 15, 2026Включаем профилирование в ansible Профилирование, это вывод даты, времени запуска и итогов…
  6. Apr 17, 2026Так выглядит общий dashbord работы с инцидентами.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →