Как стать автором
Обновить

Комментарии 12

Мне очень не нравится идея ориентироваться на размер кода в гите при решении "что нужно тестировать". Бывают архиважные проекты из сотни-другой строчек, а бывают вполне себе ленивые помоечки на тысячи строк (про которые известно, что это помоечки), которые едва-едва тестируемы и это ок.

В моём представлении линтеры не являются тестами. Они хороши для того, чтобы затащить в проект наличие CI/CD (когда не знаешь с чего начинать - начинай с линтеров), но первый, основной тест, который нужно написать - это smoke test всего.

Есть плейбука, которая "конфигурирует"? Сделай её на тестовый сервер с другой инвентори. (та же молекула, или даже прямо поверх второго сервера). Как бы уродливо оно не было, 90% проблем в плейбуках будут пойманы на этом этапе.

Если к ней приделать чуть-чуть инфра-тестов (testinfra) - получится уже вполне себе решение на котором можно долго жить. Тесты ролей имеют смысл только если роли большие и подразумевают переиспользование, по моим наблюдениям в большинстве случаев роли "per project" и спокойно тестируются в составе всего остального, без дополнительной бюрократии вида "отдельная репа для роли со своим CI".

И только если проект разрастается до больших размеров (больших == один человек всего уже не помнит), в этот момент можно думать про тесты для подсистем, просто для упрощения и ускорения процесса работы.

Т.е. приоритеты выглядят так (в порядке появления в проекте): staging/empty run, testinfra-тесты, e2e сценарии, тесты модулей (по мере появления модульности).

Мне очень не нравится идея ориентироваться на размер кода в гите при решении "что нужно тестировать". Бывают архиважные проекты из сотни-другой строчек, а бывают вполне себе ленивые помоечки на тысячи строк (про которые известно, что это помоечки), которые едва-едва тестируемы и это ок.

в целом валидно. поэтом и не возвожу это правило в абсолют, это на уровне рекомендаций. ведь ту же помоечку лучше пролинтовать и хотя бы прикрутить молекулу. пусть и с проблемами идемпотентности.

В моём представлении линтеры не являются тестами. Они хороши для того, чтобы затащить в проект наличие CI/CD (когда не знаешь с чего начинать - начинай с линтеров), но первый, основной тест, который нужно написать - это smoke test всего.

линтеры не тесты, но без них не получить быстрой обратной связи прям из в IDE своей не отходя от кассы.

Есть плейбука, которая "конфигурирует"? Сделай её на тестовый сервер с другой инвентори. (та же молекула, или даже прямо поверх второго сервера). Как бы уродливо оно не было, 90% проблем в плейбуках будут пойманы на этом этапе.

обычно молекулу прикручиваем: получаем smoke test, плюс можно не зависеть от тестовых серверов. единственное что в контейнерах есть порой дискомфорт, особенно если настраиваешь контейнеры, трогаешь ядро. приходится какие-то корявые заглушки ставить. вот были бы dependecy injection... зажили бы тогда

Если к ней приделать чуть-чуть инфра-тестов (testinfra) - получится уже вполне себе решение на котором можно долго жить. Тесты ролей имеют смысл только если роли большие и подразумевают переиспользование, по моим наблюдениям в большинстве случаев роли "per project" и спокойно тестируются в составе всего остального, без дополнительной бюрократии вида "отдельная репа для роли со своим CI".

И только если проект разрастается до больших размеров (больших == один человек всего уже не помнит), в этот момент можно думать про тесты для подсистем, просто для упрощения и ускорения процесса работы.

у меня так исторически сложилось, что на большинстве проектов монорепозитории и большинство ролей в одной репе. на каждую роль накидываем молекулу с ansible verifier И рефакторинг/расширение функционала/внесение изменений происходят плавно.

Работает ли молекула как smoke test зависит от того, что тестируется. Если плейбука, то да. Если роль - то нет, увы. Слишком много двигающихся деталей (начиная с опечаток в самой плейбуке).

Насчёт контейнеров... У нас молекула использует delegated (поскольку все драйвера в молекуле - странноватые), и у нас написаны плейбуки для openstack под молекулу. Свои, с учётом нашего openstack'а. Это позволяет тестировать настолько близко к продакшену, насколько можно. У нас часто даже group_vars линкуются из продакшена, и только хосты в инвентори - свои. (Разумеется, это работает, если нет внешних stateful зависимостей). Основная причина, почему мы полностью ушли от контейнеров для тестов - ребут не проверить, /etc/hosts не проверить, настройку сети не проверить, systemd козлит, ntp козлит, machine id козлит... Да что из инфры не козлит в контейнерах?

... У нас тоже монорепы. Репа на роль - это утопия, IMHO. Единственный вид модулярности, который мы себе сделали - это facility (доморощенный термин) - завендоренные (git vendor) репозитории, предоставляющие большой функционал (авторизация, мониторинг и т.д.), где модули, роли и плейбуки. galaxy грозился добавить в коллекции плейбуки, тогда можно на них перейти. До этого момента модульность получается на уровне import_playbook из завендоренного.

А вот тесты отдельных ролей я всё-таки считаю слегка избыточными. Писать приятно, но пользы мало. Если есть тест проекта, то роли в рамках своего применения всё равно тестируются.

с group_vars тоже финт ушами пробовали, но как-то не прижился. через delegated подход позволяет стать ближе к проду, но тогда это очень жестко приколачивает к существющим решениям. мы пока так не готовы и сидим на контейнерах.

вывод у меня напрашивается один с этого - в инфраструктуре не хватате(и не факт что будет) dependency injection, что обрекает тесты быть условными и/или черечур сложными и/или долгими

На самом деле сами молекульщики говорят - пишите на delegated. Реальный размер плейбук - пара сотен строк (с учётом всех нюансов и идемпотентности), а потом их можно переиспользовать снова и снова. А использование виртуалок для тестов офигенно в первую очередь потому, что оно делает процесс тестирования предельно близким к продакшену без спецусилий. Сами виртуалки - что используете, для того и пишите. Мы используем openstack, хотя какой-нибудь gcp или aws туда встраивается тривиально. Для hyper-v, вроде бы, модули тоже есть.

А вот тезис про DI, вы бы не могли развернуть пошире? Например, на псевдокоде/псевдоямле.

А вот тезис про DI, вы бы не могли развернуть пошире? Например, на псевдокоде/псевдоямле.

например есть задача расширить диск, поправить LVM и создать swap. я бы хотел вместо диска подсунуть образ пустышку и заменить модуль создания lvm

---
- name: create swap
  hosts: test
  inject:
    disk:
      name: /dev/sda
      src: some_image
    module:
      name: lvol
      cmd: return true
  tasks:
    - name: Read device information
      parted:
        device: /dev/sda
        unit: MiB
      register: sda_info
    - name: Extend last partition at /dev/sda
      parted:
        device: "{{ sda_info.partitions | length }}"
        label: gpt
        number: 2
        part_end: "100%"
        resize: true
        state: present
    - name: Create swap logical volume
      lvol:
        vg: VGsystem
        lv: LVswap
        size: 8g
    - name: format swap partition
      command: mkswap /dev/mapper/VGsystem-LVswap
    - name: Run swapon on the swap partition
      command: swapon /dev/mapper/VGsystem-LVswap

Ну, подмена модулей - это харкдор, потому что модули не совсем "ансибл", и их описать силами ансибла очень сложно (потому что мы хотим не просто "запустить мок", но и получить от него разумный ответ для других модулей, а ,может, и правильный сайд-эффект в setup).

Конкретно эту проблему можно попробовать решить двумя способами:

  • check_mode - если он поддерживается модулем.

  • Дать ему /dev/sd-что-то.

Последний раз, когда мне нужно было иметь настоящее scsi (sas) устройство в виртуалке, я монтировал файл через iscsi. Экспортировал диск, потом на localhost обратно цеплял. Настоящее sas-устройство, никаких намёков на loop.

... Хотя это хороший пример, почему контейнеры плохо для тестов. Интеграция такого уровня (сделал lv - получил диск, на диске можно partitions) моками почти не возможна. А вот с помощью "карманного" диска - вполне. Но карманный диск требует рутового доступа к ядру, а докер всё это ломает.

Ок, не модули подменяем, а роли. Но здесь тогда привет: правис некий «глобал стейт» и нет возвращаемого значения.

У меня был в практике один проект где был оркестратор инфрой на ruby. Там под капотом дергался shell, и к этому был прикручен самописный тест фржймворк: мы в нем подменяли класс который дергал шел и вставляли моки.

Погодите, если вы подменяете роли, то это уже ...м.. что-то странное и я не совсем понимаю, что вы тестируете.

Но если вы очень хотите это сделать, то есть role_path в ansible.cfg. Молекула позволяет задавать куски ansible.cfg.

Вообще, в ansible глобальное состояние обязательно, и оно не ограничивается переменными. У вас каждый модуль меняет глобальное состояние.

В целом, мок для роли/плейбуки, если и нужен, должен возвращать похожие сайд-эффекты. iscsi в качестве диска - вполне себе мок.

А вот если вы хотите тестировать ансибл без сайд-эффектов, то это практически не возможно по дизайну, потому что ансибл - это система управления сайд-эффектами. Если вы в плейбуку или роль вместо управления сайд-эффектами кодируете принятие решений, то это ошибка. (Поговорка "ансибл - не язык программирования").

Хорошо написанные роли и плейбуки в ансибле имеют минимум (или полное отсутствие решений) и линейное/декларативное исполнение сайд-эффектов. Соответственно, все тесты для такого должны проверять сайд-эффекты, а не джинджу и when'ы.

Роли это пример подняться по уровням абстракциям выше. Готового кейса не придумаю. В голову мне с натягом приходит вариант есть роль создания вм подключаемая через include_role куда скармливаются переменные, но это странно

Можно раскрыть мысль про «полное отсутсвие решений»?

Ну, собственно, тезис простой: в ансибле нет адекватных средств программирования. У переменных модель наследования, shadowing'а, приоритетов и т.д. ориентируется на нужды инвентори и контроллера (`-e`), а не ролей. Jinja не очень выразительна. Конвертация данных из jinja в ансибл имеет кучу глюков и не всегда приводит к ожидаемому (https://github.com/amarao/ansible-bingo). Отсутствуют нормальные инструменты для реализации базовых паттернов (даже block не умеет loop).

Другими словами, в Ансибле нет ничего, с помощью чего было бы легко программировать. Наоборот, все наличествующие инструменты целятся в удобство выполнения сайд-эффектов, часто в ущерб программируемости.

Вывод - не надо программировать. Сделали when? Уже подозрительно. Если when по динамической перменной (register/set_fact), то это, практически, code smell. Использовали loop по чему-то, кроме явно переданного из инвентори/групповых переменных/локальному списку - code smell. Совместили loop с when? ой-ой-ой.

Сделали include_role в цикле по результату uri в предыдущей таске с when и развесистой клюквой из jmeth_path/jinja в переменных? Закапывайте и никому не показывайте.

Ансибл - исполнитель сайд-эффектов. Там есть чуть-чуть фэнсервиса, но в целом, вся логика должна быть вне yaml'а. Пишите генераторы инвентори, динамические инвентори, lookup-plugin'ы, модули, динамические факты, пожалуйста. Но не пишите тяжёлого и сложного в jinja, особенно в перемешку с тасками.

Инфраструктура не статична, он как живой организм изменяется во времени. Но, как правило, она стремится к хаосу.

После прочтения этих предложений задёргался глаз... Совпадение?

Зарегистрируйтесь на Хабре , чтобы оставить комментарий