ADG Оставить заявку
Блог Автоматизация 4 мин чтения

Ansible 2.8 и Python 3: обновление вскрыло зависимости, которые мы считали несуществующими

Ansible 2.8 с официальной поддержкой Python 3 и улучшенными network-модулями - хорошо, что тесты в molecule прогнали до продакшна, а не после.

Контекст момента

Ansible 2.8 вышел в мае 2019 с официальной поддержкой Python 3, улучшенными network-модулями и новым плагином автоопределения интерпретатора

Ansible 2.8 вышел в мае, но руки дошли до нормального обновления только сейчас - в июле-августе мы планово прогоняли его на всём наборе ролей, которые используем в проектах managed-инфраструктуры. Результат предсказуемо смешанный: большинство ролей поднялось без вопросов, несколько вскрыли зависимости от Python 2, о которых мы, строго говоря, знали - но не думали, что это будет проблемой именно здесь.

Что нового в 2.8

Главное в этом релизе - Python 3 переведён из категории «работает, но не гарантируем» в официально поддерживаемый. Плюс новый плагин auto для определения интерпретатора: Ansible теперь сам пытается найти подходящий python на целевом хосте, вместо того чтобы тупо использовать /usr/bin/python.

На первый взгляд - качество жизни, мелочь. На практике оказалось, что это меняет поведение там, где раньше всё шло «молчком».

Network-модули тоже подтянули. В 2.6 мы писали про работу с Cisco и Juniper - там были шероховатости с обработкой diff-вывода и некоторые модули периодически падали с невразумительными ошибками разбора. В 2.8 это заметно улучшилось, по крайней мере на той версии IOS, с которой работаем чаще всего. Не скажем, что всё идеально, но явных регрессий не видим.

Тесты выловили то, что мы не ждали

У нас есть практика прогона ролей через molecule перед обновлением версии Ansible в продакшне - об этом писали в январе. Сначала ставим новую версию в виртуальной среде, запускаем сценарии, смотрим что сломалось. Потом несём в продакшн.

Именно этот прогон и поймал проблемы. Три роли упали с похожими ошибками:

  • Роль для настройки logrotate - использовала модуль template с фильтром, который внутри вызывал unicode(). В Python 3 unicode как встроенный тип не существует, есть только str. Jinja2-фильтр был написан как inline Python-код в vars-файле, что само по себе не лучшая практика, но работало годами на Python 2.
  • Роль для сборки конфигов nginx - в lookup-плагине был has_key(), который убрали из Python 3 dict. Не критично, там буквально одна строка, но без molecule мы бы узнали об этом в продакшне в неудобный момент.
  • Сетевая роль для Cisco - здесь интереснее: роль сама по себе рабочая, но она дёргала кастомный connection plugin, в котором кто-то давно написал print "debug: ..." без скобок. Python 3 считает это синтаксической ошибкой. Плагин просто не загружался - со стеком, который с первого взгляда не очевиден.

Все три починились за час с небольшим - ничего системного, просто технический долг, накопленный с тех времён, когда Python 3 в контексте Ansible был скорее теоретическим.

Про плагин автоопределения интерпретатора

Это отдельный момент, заслуживающий внимания. Новый плагин auto по умолчанию включён в 2.8, и он меняет поведение: если на хосте есть python3, Ansible может выбрать его, даже если раньше всегда брал python2.

На наших хостах под CentOS 7 это поначалу вызвало путаницу: python3 поставлен отдельно через SCL, /usr/bin/python3 есть, и Ansible его нашёл. Часть ролей написана в расчёте на то, что python на хосте - это python2, и ведёт себя соответственно. Конкретно: pip-модули ставились в python2-окружение, а выполнялись потом из python3 или наоборот.

Решение простое - явно указать ansible_python_interpreter в инвентаре там, где нужна конкретная версия. Но надо знать, что плагин auto теперь активен и не ожидать старого поведения.

Сетевые улучшения на практике

Для ролей, которые работают с сетевым оборудованием, 2.8 принёс заметное улучшение в разделе connection: network_cli. В частности, более надёжная работа с timeout-ами при длинных операциях - раньше при загрузке большого конфига на свитч соединение иногда рвалось без внятного сообщения об ошибке, и приходилось разбираться, применился конфиг или нет.

Сейчас прогнали на нескольких Cisco-устройствах - всё отработало чище. Без приключений - что в данном случае и является результатом.

Что в итоге

Обновление прошло без инцидентов в продакшне именно потому, что мы его прогнали через molecule заранее. Три роли с Python 2-зависимостями были бы неприятным сюрпризом в рабочее время. Вместо этого - спокойное исправление в тестовой среде и плановое обновление.

Отдельный вывод: inline Python-код в ролях - это технический долг, который рано или поздно откликнется. Сейчас откликнулся в связи со сменой версии интерпретатора. Перед нами список из ещё нескольких ролей с похожими конструкциями - будем разбирать по мере возможности, не все сразу.

Python 3 в Ansible больше не эксперимент. Это меняет ожидания по совместимости, и лучше узнать об этом в тестах, чем в продакшне.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.