Привет, Хабр! Меня зовут Анатолий, я руковожу группой автоматизации и управления тестового оборудования в YADRO.

Представьте, что у вас в компании есть несколько редких плат, на которых вы разрабатываете и тестируете ПО. Вам приходится делиться платами с коллегами: договариваться об очередности по почте, в мессенджерах или лично. Постепенно число плат растет пропорционально количеству использующих их разработчиков. И однажды кто-то новенький без спроса берет плату с вашим сетапом и зашивает свою прошивку, из-за чего вам приходится пару суток разбираться, почему упали ваши тесты.

Хаотичная работа с тестовыми стендами — это проблема, и я пришел в компанию, чтобы ее решить. Так в YADRO появилась автоматизированная система бронирования тестовых стендов, она же Automated Testing Facility (ATF). В статье расскажу, что она умеет, на каких технологиях основана и почему под наши задачи не подошел Jenkins.

Требования к системе

Итак, наша система должна была позволять нам бронировать тестовые стенды и управлять ими. Стенд — это все, что поддерживает агента — программу на Python для запуска тестов и команд по указанию. 

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

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

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

Получается, нам нужна автоматизированная система управления тестовым оборудованием из лабораторий в разных городах, которая может вместить более 200 стендов (это на тот момент) и работать без падений и лагов. При этом у инженеров должна быть возможность бронировать стенд самостоятельно на любое время и указывать, какие тесты запускать в каких сценариях, поддерживать автоматику. То есть нам нужно дать возможность полностью управлять процессом без вовлечения DevOps-инженеров.

Сперва мы решили рассмотреть готовые решения.

Готовые платформы и почему они нам не подошли

Jenkins

Популярная платформа для CI/CD позволяет описывать процессы через pipeline as code: все пайплайны хранятся в системе контроля версий и разворачиваются как код. Jenkins хорошо расширяется: есть множество плагинов, можно интегрироваться с разными системами контроля версий. Но платформа плохо поддерживает большое количество машин. Если добавить много агентов и плагинов, она начинает тормозить, а для восстановления стабильной работы нужен перезапуск.

Неудобно совмещать мануальное и автоматизированное использование. Тесты приходится добавлять и убирать вручную. Нужно было бы привлекать DevOps-команду для каждой правки.

Отказоустойчивость оставляет желать лучшего: если теряется связь с основным сервером Jenkins, пайплайны завершаются с ошибкой. Сами пайплайны пишутся на Groovy, а это дополнительная нагрузка на DevOps-инженеров в виде языка, который нужен только для описания инфраструктуры.

Slurm

Ресурс-менеджер из мира HPC хорошо масштабируется и работает с большими кластерами. На Slurm можно настроить изолированный доступ: если задача заняла ноду, никто другой туда не попадет.

Но эта платформа нам тоже не подошла. Она не проектировалась для раздельного бронирования нескольких устройств внутри одного узла. Яркий пример: несколько ускорителей или несколько подключенных FPGA не могли управляться отдельно на одном узле. «Из коробки» не было удобного планировщика под наши сценарии, поэтому его пришлось бы дописывать. 

Slurm — преимущественно консольный инструмент, из-за этого не самый удобный и наглядный. Большинство наших пользователей предпочитало GUI, а не большой текстовый вывод, в котором сложно ориентироваться. 

LabGrid

Также мы рассмотрели LabGrid — фреймворк для тестирования embedded-систем. Работать в нем удобно: уже есть много готовых драйверов для работы с железом, и он неплохо масштабируется. Но LabGrid — это именно тестовый инструмент, а не полноценная система управления стендами.

Планировщика не было вовсе — его пришлось бы писать с нуля. Плюс, несмотря на наличие драйверов, под наши платы все равно нужно было бы дописывать свою поддержку.

Изучив существующие решения, мы сделали вывод: если хотим гибкое решение, которое полностью покроет наши потребности, придется написать его самостоятельно с нуля.

Дано

Система, в которой будет:

  • бронирование стендов (в том числе многоплатных) и создание виртуальных очередей;

  • интеграция с другими системами;

  • возможность запускать авто- и ручные тесты;

  • анализатор результатов;

  • расширяемость под новые фичи;

  • возможность реализовать любой запрос пользователей.

Также система должна быть лишена сложностей готовых решений. Она должна быть легко масштабируема, отказоустойчива, иметь наглядный интерфейс, быть понятной для новых пользователей и так далее.

Решение

Мы начали разработку ATF четыре года назад. За три месяца я самостоятельно подготовил MVP — и да, сейчас это можно сделать за месяц. Если у вас в планах сделать аналогичный проект, то берите статью на вооружение!

Сейчас в ATF более 450 тестовых стендов: железные FPGA-платы, одноплатники, x86 и даже стенды без поддержки агента. Как система помогает нам эффективно с ними работать? Расскажу по порядку о ее функциональности.

Бронирование

В ATF можно резервировать стенды и группы стендов — лейблы. В рамках платформы можно выбрать из лейбла один стенд или все стенды в группе, исходя из типа лейбла, «руками» или автоматически. Кто-то занимает стенд на час, кто-то бронирует на год-два вперед. Автоматика встает в живую очередь и ждет свободного слота, а инженеры с помощью календаря находят свободные слоты и планируют работу. Автоматические нагрузки у нас в основном запускаются по ночам в порядке живой очереди и используют лейблы. Это помогает продуктивно утилизировать оборудование. 

Периодические бронирования тоже поддерживаются. Это когда стенд автоматически резервируется по расписанию — например, каждую ночь или на определенные часы днем. Так командам удобнее планировать работу: в нужное время стенд всегда будет под рукой. 

Агент

В ATF реализована агентная архитектура. Агент — это легковесное Python-приложение, которое работает по поллинг-модели. Он запрашивает задачи у сервера, который их приоритизирует по актуальности и временным слотам. 

Агент запускает тесты, выдает доступ к машине и управляет сервисами на стенде. Инженер может, например, перезапустить нужный сервис, связанный с ssh, включить NAT или перезапустить стенд без физического доступа к нему. Агент отправляет логи на сервер в реальном времени — это позволяет инженеру наблюдать за исполнением тестов в веб-интерфейсе или настраивать какие-нибудь алерты в CI.

К тому же агент не зависит от сервера: если пропала связь, тесты не прерываются. Логи хранятся локально на машине. Они будут отправлены на сервер, когда связь восстановится.

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

Управление и интеграция

Помимо бронирования, у нас есть полноценное управление стендами — по сути, полный контроль над оборудованием без прямого доступа к нему. Для интеграции стендов с внешними инструментами, включая Jenkins и другие CI/CD-системы, предусмотрена поддержка публичных API — об этом ниже.

На платформе можно управлять внешними устройствами — например, Power Control. За их счет можно включать и выключать питание, полностью обесточивать платы, перезагружать железо. Через систему есть возможность управлять USB- или Bluetooth-устройствами, а это тоже важно для тестов.

Массовая установка прошивок

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

В ATF мы реализовали механизм «живой очереди». Система создает сервисную задачу на обновление прошивки и ставит ее в очередь. Как только пользовательская задача заканчивается и стенд освобождается, автоматически запускается сервисная задача: прошивка обновляется с помощью Ansible. Если все проходит успешно, стенд становится доступен для работы. Если что-то идет не так, стенд блокируется, и система сигнализирует о проблеме инженеру, обслуживающему плату.

Веб-консоль

Это инструмент, который позволяет напрямую отправлять команды на стенд. Он работает через интеграцию с агентом. Что он умеет? Например, однажды к нам обратилась команда инженеров из инфраструктуры: им нужно было срочно удаленно настроить стенды в другом городе. У них были только ssh-ключи для доступа к стендам, но по какой-то причине они не подошли.

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

Интеграция с лабораториями (физический учет)

У нас есть интеграция с системой CMDB (Configuration Management Database) — единой базой данных, где хранится информация обо всей инфраструктуре компании и о наших стендах в том числе: какое оборудование есть, где оно находится, в каком состоянии, как оно связано между собой. 

В будущем мы планируем работать и в обратную сторону: забирать данные из CMDB. Так, когда оборудование будет приходить со склада и регистрироваться в единой БД, оно автоматически подтянется в нашу систему для дальнейшей настройки еще до физического прибытия. В этом случае стенд будет «красным», то есть не готовым к работе, но уже видимым в системе.

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

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

Как забронировать стенд и запустить на нем тесты

Интерфейс представлен в двух вариантах — GUI и CLI. Покажу на примере графического интерфейса, что есть в ATF:

На скриншоте мы видим стенд #30 и всю информацию о нем: наверху есть название, состояние (онлайн/офлайн), номер, город расположения стенда, его тип. Агент на стенде активен и каждые 10 секунд шлет нам извещение о себе (Last Ping Time). Здесь же IP-адрес и способ аутентификации (LDAP, password, ATF temp password). Чуть ниже все про систему: тип стенда, место расположения лаборатории, модель.

Есть информация о «здоровье» стенда. В рамках диагностических тестов по всем подсистемам машины может выясниться, что какой-то компонент работает неправильно. Эта информация сохраняется в системе и видна всем пользователям. И уже сам бронирующий решает, не критичны ли такие неполадки для него и не следует ли выбрать другой стенд.

На примере выше видно, что стенд свободен («No active task for node») и его можно забронировать, нажав на кнопку «забронировать». Здесь же указано описание стенда. В деталях указаны подключенные внешние устройства и перечень лейблов, куда входит стенд. Когда стенд забронирован, в интерфейсе видно название брони, время ее начала и окончания и статус: в процессе или нет. В описании переменных окружения (Environment Variables) отражена информация для отгрузки во внешние сервисы. Эти данные могут пригодиться для запусков тестов.

Здесь же можно открыть Admin Panel для управления стендом: она доступна только администраторам и владельцу стенда. В этой панели можно поставить лимит на время бронирования в рабочее время, обновить агента, проверить Power Controls и доступ к веб-консоли.

Теперь рассмотрим фичи, доступные в системе. Доступ к ним реализован и через CLI, и через GUI — прикрепляю скриншоты из последнего для наглядности.

Конфигуратор

В ATF можно собрать конфигурацию стенда: добавить дополнительное оборудование, соединить его кабелями — при этом указав, какими именно. Дальше это описание можно передать прототипистам, а они соберут нужный битстрим.

В обратную сторону это тоже работает: если нужен конкретный тестовый стенд, можно найти в системе подходящий и забронировать его.

Поддержка временных паролей

Некоторые стенды не поддерживают авторизацию через LDAP из-за сетевых особенностей или из-за мощностей плат. Для таких стендов мы сделали выписывание временных паролей для ssh. Это позволило нам добавить в систему больший пласт оборудования — слабые одноплатники или стенды, находящиеся за корпоративным периметром, где нет доступа к корпоративной сети.

Разграничения ресурсов

В ATF есть различные ресурсы — стенды, лейблы, тесты и матрицы тестов. Инженеры хотели управлять видимостью своих ресурсов. Мы реализовали два варианта для разных целей:

  1. В группах доступа инженеры могут видеть свои ресурсы, а другие — нет. Есть поддержка как LDAP-групп, так и точечное добавление пользователей.

  2. Проекты — виртуальные пространства, в которых можно изолировать не только стенды, но и тесты, логи, отчеты. Внутри такого проекта команда получает полный контроль над своими ресурсами и действиями.

Автоматизация и запуск тестов

Пользователям доступен запуск всевозможных тестов на стендах через нашу систему. Когда проводятся большие наборы запусков тестов, где одна и та же функциональность проверяется в разных условиях, мы используем тестовые матрицы. 

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

Инженеры сами решают, что запускать, где и когда. При необходимости можно настроить автоматические запуски: указать окружение и расписание — тесты будут выполняться регулярно без ручного участия. Это сильно снижает зависимость от DevOps-процессов, так как команды сами управляют своими проверками.

После выполнения результаты доступны в виде матриц: видно, какие тесты прошли, какие упали и в каком окружении это произошло. 

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

Однажды коллеги проверяли фичу, и в одной ячейке оказались десятки тысяч тестов. Всего количество тестов доходило до сотен тысяч. В сумме тестировщики попытались сохранить около миллиона результатов. Для хранения мы используем MongoDB, где максимальный размер одного документа — 16 МБ, поэтому система не справилась. Все упало.

После этого мы переработали механику хранения результатов: теперь можно запускать практически любое количество тестов — система выдерживает. В одной ячейке может быть до нескольких десятков тысяч тестов.

Анализатор

Еще один важный компонент — инструменты для первичного разбора результатов. Сравниваются они по шаблонам с анализом логов. Эта функциональность позволяет сократить время на ручной анализ с часа до пяти минут и своевременно выявить критические сбои. 

Идея простая: если тест падает по известной причине, нет смысла каждый раз разбирать это вручную. Система находит паттерны. Например, если определенный сетап из раза в раз не может поднять Linux и в логах появляется характерная ошибка (условный Epic Fail), система понимает, что это уже известная проблема. В таком случае тест помечается. Например, желтым. Тогда это значит, что «тикет создан, и инженер бежит спасать нерабочий стенд».

Результат теста не красный, а желтый, так как есть проблема в загрузке Linux на стенде
Результат теста не красный, а желтый, так как есть проблема в загрузке Linux на стенде

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

Если ничего не делать, то стенд будет брать задачу, падать, брать следующую — и так по кругу, окрашивая столбец матрицы в красный. Чтобы этого избежать, анализатор ловит такую ситуацию по логам, определяет причину и автоматически «лочит» стенд, выводит его из эксплуатации. Система предупреждает о неисправности стенда, и на результатах такая блокировка не отражается.

Внутренний мир ATF

Коротко расскажу про архитектуру платформы. Мы выбрали микросервисы вместо монолита, хотя начинали с него. В начале пути система активно разрабатывалась, мы часто выпускали обновления, требующие больших пересборок всего проекта. Это было долго и муторно, поэтому мы перешли на микросервисную архитектуру.

Контекстная диаграмма системы
Контекстная диаграмма системы

Пользователи взаимодействуют с ATF как с черным ящиком с помощью API, WebUI и CLI. А ядро ATF взаимодействует с внешними частями системы — агентом/клиентом, Power Controls на машинах, сервисами оповещения и с Jira, куда отправляются результаты проблематичных тестов. Оформляются они в виде тикетов.

ATF изнутри
ATF изнутри

В системе реализован веб-интерфейс на Vue.js, CLI на Go, который написали сами пользователи, и интеграция с CMDB, о которой я уже рассказал выше. Все они взаимодействуют с бэкендом, тоже написанном на Go. Сервис логирования написан на Python. 

Архитектура бэкенда ATF
Архитектура бэкенда ATF

Все запросы из GUI, CLI и CMDB идут на API Gateway, в котором мы реализовали интеграцию с внешними API и выдачу доступов: авторизацию и аутентификацию. Через хедеры данные пользователя идут в бэкенд, где реализован доступ в базу данных сущностей, то есть наших стендов.

Кастомизированный CI/CD 

В этом проекте используется Git Flow, адаптированный под микросервисную архитектуру ATF, где каждый сервис хранится в отдельном репозитории. В каждом из них есть стабильная ветка master для готовых к релизу версий и ветка dev, куда автоматически попадает код после слияния пул-реквеста с тестами. Для разработки новых функций или исправлений ошибок создаются временные ветки, которые после прохождения CI-тестов объединяются с dev. Параллельно ведется центральный ATF-репозиторий, где в ветках master и stage фиксируются версии микросервисов для боевого и промежуточного окружений. При появлении нового коммита в мастер-ветке сервиса система автоматически инкрементирует его версию и переносит данные в ATF-хранилище.

Процесс публикации релиза начинается с создания пул-реквеста из ветки update в stage, где запускаются интеграционные и E2E-тесты. После успешной проверки и ручного утверждения владельцем проекта код автоматически разворачивается на промежуточной среде. Если на staging нет критических ошибок, создается релиз в ветку production, что запускает финальный деплой на боевой сервер. В случае обнаружения багов на prod все исправления проходят через ветку prodfix, которая синхронизируется с мастером и повторно тестируется перед обновлением окружений. Для срочных хотфиксов создается изолированная ветка hotfix/*, после слияния которой версия сервиса получает специальный суффикс и обновляется в центральном конфиге.

Планы на будущее

В перспективе мы хотим реализовать:

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

  • Продвинутую систему нотификаций, чтобы можно было подписаться на любую активность в системе с определенными условиями и фильтрами.

  • Поддержку сложных стендов, которые состоят из нескольких машин. Нам бы хотелось, чтобы такие машины можно было брать как по отдельности, так и вместе. Для этого же ввести поддержку списков сложных стендов.

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

Появились ли у вас вопросы про работу системы? Есть ли у вас подобные практики? Расскажите о них в комментариях.

Комментарии (0)