Автоматизация разработки FPGA с Jenkins, Vivado и GitHub на Linux VPS
* В данной статье содержится рекламная ссылка на VPS UpCloud
Непрерывная доставка и непрерывная интеграция — это гибкие методологии разработки ПО, сокращающие время цикла между изменением кода и развертыванием. Используя автоматизацию для верификации изменений кода и сборки релизных файлов, команды могут стать более продуктивными и эффективными.
Программные компании давно практикуют непрерывную разработку, но вы так же можете использовать эти методы для ваших FPGA-проектов. Это руководство научит вас настраивать сервер автоматизации на виртуальном частном сервере (VPS) с использованием Jenkins, Xilinx Vivado и системы управления версиями Git / GitHub.
Что такое Jenkins?
Сервер автоматизации Jenkins — это бесплатная open-source программа, написанная на Java. Она работает на Windows или Linux. Мы будем использовать Linux в этом посте, потому что это самая распространенная платформа для headless-серверов.
Jenkins работает как демон-процесс в Linux или как служба в Windows. Встроенный веб-сервер, который Jenkins запускает при старте, предоставляет пользовательский интерфейс. Большинство пользователей взаимодействуют с Jenkins через веб-интерфейс. Вы можете добавлять новые проекты автоматизации и управлять существующими через веб-GUI.
На изображении выше показана главная страница сервера Jenkins, который мы настроим сегодня. По умолчанию доступ к Jenkins имеют только залогиненные пользователи, но для этой статьи я включил публичный доступ к частям моего *демо-сервера.
* Обновление: Я убрал демо-сервер 13 мая 2020 года
То, что вы видите на главной странице — это список джоб. Эти джобы могут содержать любые задачи, и их можно запускать вручную из веб-GUI. Или они могут запускаться автоматически через скрипты, вебхуки или в результате завершения других джоб. Отсюда термин сервер автоматизации.
В нашем примере каждая джоба соответствует VHDL-модулю, хранящемуся в отдельном GitHub-репозитории. Мы заставим Jenkins запускать симуляцию и собирать проект всякий раз, когда разработчик пушит код в один из отслеживаемых Git-репо. Если тестбенч упадет или сборка сломается, Jenkins пометит джобу как упавшую в веб-интерфейсе и автоматически отправит email человеку, закоммитившему ошибочный код.
Пример проекта
Серверы автоматизации наиболее полезны для команд, работающих над крупными проектами. Поэтому я сконструировал пример FPGA-проекта, состоящего из восьми Git-репозиториев. Проект — это счетчик 7-сегментного дисплея из курса Fast-Track, портированный на Xilinx ZedBoard.
Ссылки на восемь репозиториев на GitHub:
- packages (VHDL-пакеты)
- bcd_encoder (Модуль)
- counter (Модуль)
- digit_selector (Модуль)
- output_mux (Модуль)
- reset (Модуль)
- seg7_encoder (Модуль)
- seg7 (Верхний модуль)
Каждый репозиторий содержит VHDL-модуль и его тестбенч. Исключение — репозиторий packages, который содержит только три VHDL-пакета, определяющие константы и типы. Дополнительно, верхний модуль seg7 содержит файл констрейнтов, определяющий тактовую частоту и назначение пинов физической реализации.
Большинство крупных VHDL-проектов используют модули из более чем одного репозитория. Компании обычно имеют библиотеку пакетов и модулей, которые они переиспользуют во многих дизайнах. Это то, что я эмулирую, разделяя этот довольно простой дизайн на столько модулей.
В нашем примере все модули зависят от репозитория packages, а верхний модуль зависит от всех подмодулей. Я решил это, импортируя их по мере необходимости, используя стандартные Git Submodules. Граф выше показывает содержимое и зависимости всех репозиториев в этом проекте.
Git-репозитории также содержат несколько не-дизайнерских файлов, таких как конфигурация Jenkins и скрипты сборки. Мы поговорим о них в следующих разделах статьи.
Виртуальный частный сервер (VPS)
Хотя Jenkins может работать на любом компьютере Windows или Linux, для всех практических целей вы захотите запускать его на выделенном сервере. Сервер автоматизации должен быть всегда запущен и доступен всем членам вашей команды. Если у вас есть физический сервер с достаточной мощностью — это отлично. Но для большинства из нас более быстрым и дешевым решением является использование виртуального частного сервера (VPS).
VPS — это виртуальный компьютер, который вы арендуете у хостинговой компании через интернет. Он выглядит как настоящий компьютер Windows или Linux, с которым вы можете взаимодействовать и устанавливать любое ПО. Мы будем использовать компьютер Linux, потому что это имеет больше смысла для нашего случая использования.
Сайт VHDLwhiz работает на VPS уже последние два года. Я уже прошел через поиск самого быстрого и лучшего VPS-провайдера, которым является UpCloud. Естественно, мы будем использовать UpCloud для настройки VPS для нашего сервера автоматизации.
Получите $25 бонус UpCloud
Если вы хотите попробовать UpCloud, у меня есть реферальный код, который даст вам $25 кредита при регистрации.
>> Нажмите здесь, чтобы получить $25 бонус UpCloud <<
Или используйте мой промокод при оформлении заказа: NV78V6
Используя код, вы получите бонус и поддержите VHDLwhiz одновременно. Я могу получить некоторые средства на свой аккаунт UpCloud за каждого клиента, использующего его.
Хорошо, достаточно продаж. Давайте перейдем к настройке сервера.
Развертывание VPS UpCloud
После входа в ваш новый аккаунт UpCloud, вы можете начать процесс создания нового VPS-инстанса, перейдя в Servers → Deploy server.
UpCloud имеет много дата-центров по всему миру. Выберите ближайшее к вам местоположение для хостинга вашего нового сервера. Затем выберите план ресурсов для вашей виртуальной машины. Jenkins не использует много ресурсов, но Xilinx Vivado — настоящий пожиратель RAM. Поэтому вы должны выбрать как минимум план с 4 ГБ RAM, как показано на изображении ниже.
Я рекомендую посмотреть страницу рекомендаций по памяти Xilinx, потому что использование памяти тесно связано со сложностью целевого FPGA. Страница указывает пиковое использование памяти для Zynq-7000 XC7Z045 FPGA, который я использую, как 1,9 ГБ. Я обнаружил, что план с 2 ГБ был слишком мал для роутинга дизайна. Vivado упал, и в логе dmesg появилось следующее сообщение:
[807816.678940] Out of memory: Killed process 22605 (vivado) total-vm:2046684kB, anon-rss:782916kB, file-rss:308kB, shmem-rss:0kB
Обратите внимание, что вы всегда можете легко обновить RAM и CPU ресурсы вашего сервера из вашего аккаунта UpCloud. Вы не автоматически получите дополнительное дисковое пространство, идущее с более дорогими пакетами, без переразбиения файловой системы VPS, но оно будет работать. Для справки, я начал с плана с 50 ГБ хранилища, и я использовал 61% от этого после завершения всего сервера автоматизации. Сам Vivado занимает 24 ГБ места.
Я рекомендую выбрать последнее дистрибутив CentOS Linux в качестве операционной системы, как показано на изображении ниже. Xilinx Vivado официально поддерживает только Red Hat Linux, который не бесплатен. Но CentOS — это бесплатный, сообществом поддерживаемый дистрибутив Linux, который близко следует за Red Hat.
Затем есть некоторые опции о сети, которые можно оставить по умолчанию. Есть также раздел на веб-странице, где вы можете загрузить ваши SSH-ключи для безпарольного входа. Вы всегда можете настроить эти вещи позже, используя стандартный Linux-метод загрузки SSH-ключей.
Наконец, вам нужно указать хостнейм и имя сервера, как показано на изображении ниже. Хостнейм — это публичный домен, который пользователи введут в браузер для доступа к серверу Jenkins. Если у вас нет домена или поддомена, готовых, вы всегда можете получить доступ к серверу, используя его IP-адрес. Когда вы довольны настройками, нажмите кнопку Deploy для создания сервера.
После создания сервера, автогенерированный пароль покажется как уведомление. Вы можете изменить это позже, используя Linux-команду passwd. Если вы предоставили свой SSH-ключ до развертывания сервера, вам не понадобится пароль вообще. Если вы когда-либо потеряете доступ к серверу, вы всегда можете зайти из вашего аккаунта UpCloud, нажав Open the console connection, как показано на изображении ниже.
Настройки DNS-зоны
Новый сервер получает постоянные IPv4 и IPv6 адреса, найденные в вашем аккаунте UpCloud в Servers->Network. Вы можете получить доступ к серверу, SSH-ся в root-аккаунт публичного IPv4 адреса.
Используя пример IP-адреса с изображения ниже, соответствующая команда для ввода в вашем домашнем компьютере Linux будет:
ssh root@your_ip_address
Хорошо использовать только IP-адрес, если вы делаете это просто как эксперимент. Но более практичное решение — назначить постоянное доменное имя серверу. Для этого вам нужно купить домен у одного из множества регистраторов, доступных онлайн.
Поскольку я уже владею доменом vhdlwhiz.com, я решил создать поддомен для сервера Jenkins с именем jenkins.vhdlwhiz.com. Мы правильно настроили доменное имя на сервере UpCloud при развертывании. Следующее, что нам нужно сделать — направить поддомен на публичный IPv4 адрес.
На изображении ниже показаны настройки, которые я ввожу в DNS-зоны файл моего регистратора доменных имен. Если бы я хотел сервер на основном домене (vhdlwhiz.com), я бы оставил поле хостнейма пустым. Но я хочу, чтобы он был на поддомене "jenkins" к vhdlwhiz.com. Поэтому я ввожу имя поддомена.
Потребуется некоторое время после изменения DNS-настроек, прежде чем вы сможете использовать доменное имя для доступа к вашему сайту. Обычно это занимает не более 20 минут, но в крайних случаях может занять до 48 часов для распространения изменений во все углы интернета.
Когда изменения вступили в силу, вы можете использовать доменное имя вместо IP-адреса при входе на сервер через SSH:
ssh root@yoursub.yourdomain.com
Установка Jenkins
Первое, что вы должны сделать после входа в root-аккаунт на вашем новом Linux-сервере — обновить все установленные пакеты. В CentOS Linux yum — менеджер пакетов по умолчанию. Мы будем использовать команду yum для установки большинства ПО.
Выполните следующую команду для обновления всех установленных пакетов до последних версий:
yum -y update
Теперь, когда мы знаем, что наша система обновлена, мы можем продолжить установку. Но перед выдачей команды yum для установки Jenkins, мы собираемся установить Java версии 11 явно. Это сэкономит нам некоторые проблемы позже, когда мы установим Xilinx Vivado.
В настоящее время на нашем сервере нет интерпретатора Java, и если мы скажем yum установить Jenkins, он установит Java версии 8. Это хорошо работает для Jenkins, но создаст проблемы для нас позже, потому что Vivado зависит от Java версии 11.
Установите Java 11, используя эту команду перед установкой Jenkins:
yum -y install java-11-openjdk-devel
Jenkins недоступен в стандартном репозитории ПО, идущем с CentOS. К счастью, мы можем импортировать репозиторий Jenkins из Red Hat, используя следующие команды:
wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
Наконец, мы можем пойти вперед и установить Jenkins:
yum -y install jenkins
Сервер Jenkins автоматически запустится после следующей перезагрузки, но вы можете запустить сервер без перезагрузки так:
systemctl start jenkins
Вы всегда можете проверить статус сервера Jenkins, используя команду systemctl:
systemctl status jenkins
Он выведет статус сервера вместе с любыми сообщениями об ошибках.
Jenkins через небезопасный HTTP
В этот момент Jenkins работает на порту 8080 на VPS, но у вас нет способа подключиться к нему через веб-браузер. Это потому, что файрвол CentOS блокирует порт 8080 и порт 80 (HTTP) по умолчанию. Что мы можем сделать, чтобы это исправить — открыть порт 80 в файрволе и перенаправить его на порт 8080 с помощью iptables.
Но прежде чем вы это сделаете, вы должны решить, хотите ли вы защитить свой сайт с HTTPS. Проблема с использованием только HTTP и порта 80 в том, что ваш сайт будет небезопасным. Если вы получаете к нему доступ через публичный Wi-Fi, злонамеренный человек в той же Wi-Fi с ноутбуком и доступным хакерским ПО может перехватить ваше соединение и украсть ваши логин-креденшлы к Jenkins.
Если вы хотите избежать риска безопасности нешифрованного HTTP, перейдите к следующему разделу о настройке HTTPS для Jenkins. В противном случае, продолжайте читать.
Включение небезопасного HTTP-доступа к Jenkins так же просто, как выполнение следующих команд:
firewall-cmd --permanent --zone=public --add-port=80/tcp firewall-cmd --reload iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
Тогда вы можете ввести ваше доменное имя в любимом браузере, и должна появиться страница Jenkins Getting Started. По крайней мере в Google Chrome, предупреждение "Not secure" будет отображаться в адресной строке, как показано на изображении ниже.
Перейдите вперед к разделу Настройка Jenkins, если вы довольны этим.
Jenkins через безопасный HTTPS
Наличие небезопасного сайта, доступного публично — огромный риск безопасности. Jenkins может получить доступ к вашему исходному коду, и так может любой хакер, успешно взломавший сервер. К счастью, защита сайта — это всего лишь несколько скопированно-вставленных команд.
Jenkins не может обрабатывать HTTPS самостоятельно. Поэтому мы должны установить общий веб-сервер для перенаправления запросов, приходящих через защищенный канал, на небезопасный сервер Jenkins. Я буду использовать Nginx, который является одним из самых популярных бесплатных open-source веб-серверов сегодня.
Выполните следующую команду для установки и запуска Nginx:
yum -y install nginx systemctl start nginx
Затем нам нужно открыть и HTTP, и HTTPS порты в файрволе. Мы будем обслуживать только HTTPS-запросы, но нам нужно держать HTTP порт открытым тоже, потому что мы настроим Nginx перенаправлять все небезопасные запросы на защищенный порт.
Эти команды откроют файрвол для веб-трафика:
firewall-cmd --permanent --zone=public --add-port=80/tcp firewall-cmd --permanent --zone=public --add-port=443/tcp firewall-cmd --reload
Следующий шаг — установить сертификат, который веб-браузеры могут использовать для сертификации того, что это ваш сайт, с которым они взаимодействуют, а не самозванец. Мы будем использовать бесплатный центр сертификации Let's Encrypt для защиты нашего сайта. Индивидуальные шаги сложны, но к счастью, certbot предоставляет скрипт, который может сделать это для нас автоматически.
Скачайте и подготовьте скрипт со следующими командами:
apt update apt install snapd snap install core; snap refresh core snap install --classic certbot
Затем запустите скрипт, который установит сертификат и сделает необходимые изменения в конфигурационном файле Nginx:
certbot --nginx
По мере выполнения скрипта, он будет запрашивать информацию. Отвечайте утвердительно (Yes, Accept) на все вопросы, пока вас не спросят, выбираете ли вы перенаправление HTTP-трафика на HTTPS. Ниже показаны вопросы и мой рекомендованный ответ (2). Разрешение Nginx перенаправлять небезопасные запросы гарантирует, что никто не может явно ввести https://yoursite.com и попасть на небезопасную версию Jenkins. Nginx перенаправит их на безопасную версию.
... Deploying Certificate to VirtualHost /etc/nginx/nginx.conf Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Наконец, вы должны включить cron-задачу для периодического обновления сертификата. Иначе он истечет, и браузеры откажутся открывать ваш сайт совсем.
Выполните следующую однострочную команду для добавления ежедневной cron-задачи:
echo "0 0 * * * /snap/bin/certbot renew --quiet" | crontab -
Cron-демон будет запускать скрипт обновления ежедневно в полночь. Вы можете перечислить cron-задачи командой crontab -l и редактировать их командой crontab -e. Если вы посетите ваш сайт сейчас, вы увидите тестовую страницу Nginx, а не Jenkins. Мы исправим это в ближайшее время, но убедитесь, что предупреждение "Not secure" исчезло из адресной строки Chrome, как показано на изображении ниже.
Чтобы заставить Nginx обслуживать Jenkins, вам нужно сделать некоторые изменения в файле /etc/nginx/nginx.conf. Кредит за этот фрагмент кода идет блогу Kerren на Medium. Использование редактора nano, вероятно, самый простой способ редактировать конфигурационный файл:
nano /etc/nginx/nginx.conf
Найдите server-блок, который перечисляет ваше доменное имя, и добавьте выделенные строки из листинга ниже в ваш файл nginx.conf. Обратите внимание, что первая из трех новых строк идет выше server-блока, а остальные идут в корневой location-блок.
После обновления конфигурационного файла, вам нужно перезагрузить Nginx для вступления изменений в силу. Опционально, вы можете протестировать конфигурационный файл перед перезагрузкой командой:
nginx -t
Nginx выведет OK или скажет вам, на какой строке в файле nginx.conf ошибка. Когда вы довольны изменениями, вы можете перезагрузить веб-сервер, дав следующую команду:
systemctl reload nginx
Когда вы теперь посетите сайт Jenkins в браузере, вы должны увидеть страницу Getting Started Jenkins, как показано на изображении ниже. На этот раз она обслуживается через защищенное соединение, и мы можем безопасно продолжить настройку Jenkins из веб-GUI интерфейса.
Настройка Jenkins
Первый раз, когда вы посещаете ваш веб-сайт Jenkins, он попросит пароль, найденный в файле на Linux-файловой системе. Пока вы залогинены через SSH, используйте команду ниже, чтобы показать пароль. Скопируйте-вставьте его в браузер для получения доступа к веб-GUI:
cat /var/lib/jenkins/secrets/initialAdminPassword
На следующем экране Jenkins спросит, хотите ли вы установить предложенные плагины, или хотите ли вы указать, какие установить. Просто идите с опцией Install suggested plugins для начала. Вы всегда можете добавлять или удалять плагины позже.
На следующей странице вы должны создать админа. Заполните ваши детали и создайте сильный пароль для использования с вашим новым аккаунтом. По умолчанию только залогиненные пользователи могут получить доступ к серверу Jenkins. Анонимные пользователи увидят только диалог логина, если они заглянут на ваш сайт. Единственная причина, по которой вы могли получить доступ к моему *демо-сайту jenkins.vhdlwhiz.com, в том, что я сделал изменения на сервере. Я использовал плагин Matrix Authorization Strategy для предоставления анонимного доступа к некоторым видам.
* Обновление: Я убрал демо-сайт 13 мая 2020 года
Когда Jenkins закончит установку плагинов, вы увидите сообщение "Jenkins is ready!", как показано на изображении выше. Нажмите кнопку, которая приведет вас на пустую обзорную страницу вашей свежей установки Jenkins.
Установка плагинов Jenkins
Первое, что вам нужно сделать — установить кучу плагинов. У Jenkins есть встроенный менеджер плагинов, который вы можете использовать для установки, обновления и удаления расширений. Вы найдете плагины, которые могут позаботиться о большинстве ваших потребностей. Просто используйте функцию поиска в менеджере плагинов, когда вам нужно добавить функциональность к Jenkins.
Давайте перейдем к установке плагинов, которые я использовал при настройке примера сервера Jenkins. Из сайдбара выберите Manage Jenkins->Manage Plugins->Available. Обратите внимание, что плагины не перечислены, пока вы не введете что-то в поле поиска. Как только вы начнете печатать, они появятся.
Blue Ocean
Первый плагин, который я рекомендую установить, называется Blue Ocean. Этот плагин — модернизация рабочего процесса Jenkins, а также пользовательского интерфейса. Он также подтягивает кучу других полезных плагинов, так что вам не нужно устанавливать их индивидуально. Найдите "blue ocean" в менеджере плагинов и выберите его для установки, как показано на изображении ниже.
На странице прогресса установки, появляющейся после нажатия install, у вас есть опция выбрать Restart Jenkins when installation is complete and no jobs are running. Если вы поставите галочку рядом с ним, Jenkins перезагрузится после завершения установки плагинов. Другой способ перезагрузки Jenkins — зайти на сервер через SSH и выполнить следующую команду:
systemctl restart jenkins
Помимо длинного списка других плагинов, установленных Blue Ocean, на первый взгляд нет заметных изменений. Но будет новый пункт меню в сайдбаре, как показано на изображении ниже. При нажатии он приведет вас к Blue Ocean GUI, который выглядит довольно иначе, чем нормальный интерфейс Jenkins. Попробуйте!
Green Balls
Следующий плагин, который я всегда устанавливаю, чисто для эстетики. Плагин Green Balls не требует никакой конфигурации. Просто найдите "green ball" в менеджере плагинов и установите его, как показано на изображении ниже.
По умолчанию Jenkins использует синие шарики на обзорной странице для индикации того, что статус джобы успешен. Причина имеет отношение к тому, что изобретатель Jenkins японец. Интересно, в Японии синий цвет взаимозаменяем с зеленым, когда речь идет об индикации ОК-статуса. Больше об этом в этой статье, где вы можете услышать объяснение автора от первого лица.
Пользователи из большинства других частей мира, вероятно, предпочли бы зеленые шарики статуса. Это легко исправляется плагином Green Balls, как показано на изображении ниже.
Locale plugin
Следующий плагин, который я установил, называется Locale. Найдите "locale" под вкладкой Available в менеджере плагинов. Установите плагин, как показано на изображении ниже.
Плагин позволяет заставить Jenkins использовать один и тот же язык в GUI для всех пользователей. По умолчанию Jenkins переводит пользовательский интерфейс на язык, который использует ваш веб-браузер. Я норвежец, но я бы предпочел иметь Jenkins на английском. Перевод был немного неадекватным. Также так намного легче гуглить ответы на английском, если вам нужно узнать, как сделать что-то в Jenkins.
Конечно, это полностью ваш выбор, хотите ли вы этот плагин. Если вы его установите, вам нужно перейти в Manage Jenkins->Configure System и найти раздел Locale. Затем вам нужно ввести "en_US" (или любой язык, который вы хотите) и поставить галочку ниже, чтобы заставить этот язык для всех пользователей, как показано на изображении ниже. Не забудьте прокрутить вниз страницы и нажать Save.
Последний плагин, который вам нужен для клонирования моей настройки — Sidebar Link plugin. Он позволяет добавлять кастомные ссылки в сайдбар Jenkins. Мы будем использовать его позже для добавления ссылки на FPGA-релизы (битфайлы). Найдите "sidebar" в менеджере плагинов и установите плагин, как показано на изображении ниже.
Подключение Jenkins к GitHub
Независимо от того, публичный или приватный ваш репозиторий, вам нужно дать Jenkins некоторые разрешения на вашем аккаунте GitHub. По крайней мере, если вы хотите сделать это самым легким способом, вы должны позволить плагину Jenkins GitHub управлять интерфейсом с GitHub за вас. Blue Ocean уже установил плагин GitHub. Вот шаги для его конфигурации.
Сначала вы должны установить Git на вашей системе. Плагин GitHub не строго требует этого, но когда вы начнете работать с джобами Jenkins, вы должны его иметь. Выполните эту команду для установки Git в CentOS Linux:
yum -y install git
Персональный токен доступа в GitHub
Зайдите в GitHub, нажмите на вашу аватарку в правом верхнем углу, выберите settings, и идите в Developer Settings. Затем выберите Personal access tokens из левого сайдбара меню, или нажмите на эту ссылку, которая приведет вас прямо туда.
Здесь вам нужно нажать Generate new token, как показано на изображении ниже. GitHub попросит ваш пароль еще раз. То, что вы делаете сейчас — это по сути создание нового, приложения-специфичного пароля. Это лучше, чем делиться вашим реальным паролем, потому что вы можете отозвать его, и вы можете ограничить разрешения, предоставленные токену. Это то, что мы сделаем на открывающейся странице.
Когда вы ввели ваш пароль, вам нужно дать токену имя. Имя — это просто для вас. Это может быть что угодно, "Jenkins", например. Затем вы должны включить как минимум разрешения admin:org_hook, admin:repo_hook и repo, как показано на изображении ниже. Вы можете оставить все остальные чекбоксы непомеченными.
Наконец, когда вы нажмете Generate token, код доступа появится. Вам нужно скопировать его перед тем, как вы покинете эту страницу, потому что невозможно увидеть его снова. Если вы забудете его, удалите токен и создайте заново.
Ввод креденшлов GitHub в Jenkins
Когда вы скопировали токен, идите в Jenkins, выберите Manage Jenkins->Configure System, и найдите раздел GitHub, как показано на изображении ниже. Из выпадающего меню выберите Add GitHub Server->GitHub Server.
В новом разделе GitHub Server, который появится, поставьте галочку Manage hooks. Когда вы это сделаете, Jenkins установит вебхуки на GitHub для репо, которые вы мониторите. Мы увидим позже, что это особенно полезно, потому что мы будем использовать их для запуска симуляции или сборки в Jenkins, когда пользователь пушит код в связанный GitHub-репозиторий.
Выберите Credentials (Add)->Jenkins после того, как вы поставили галочку, как показано на изображении ниже.
В открывшемся окне измените выпадающее меню Kind на Secret text. Затем вставьте персональный токен доступа, который вы ранее сгенерировали в GitHub, в поле Secret. Напишите "GitHub" в поле ID и нажмите Add.
Наконец, когда вы вернетесь в главное меню конфигурации, после добавления секретного текста, выберите новый ключ GitHub из меню Credentials. Затем нажмите Test connection для верификации, что Jenkins может говорить с GitHub, используя токен доступа. Если все прошло хорошо, вы должны увидеть сообщение как показано на изображении ниже.
Убедитесь, что вы прокрутили вниз страницы и нажали Save перед выходом со страницы конфигурации.
Если вы столкнетесь с проблемами и в итоге добавите множество креденшлов, вы можете удалить их, идя в Manage Jenkins->Manage Users, и нажав ваше имя пользователя. Теперь в левом сайдбаре будет пункт меню Credentials. Оттуда вы можете просматривать и редактировать все ключи, которые Jenkins сохранил.
Отправка email из Jenkins
Мы собираемся настроить Jenkins для отправки автоматизированных email, когда что-то ломается в вашем коде. Чтобы это случилось, нам нужно сделать некоторые изменения в меню Manage Jenkins->Configure System.
Первое, что вы должны сделать — ввести from-адрес, который Jenkins будет использовать при отправке автоматизированных email. Найдите поле System Admin e-mail address на странице конфигурации, и введите адрес, который вы хотите, чтобы Jenkins отправлял от.
Краткое примечание: лучше ввести адрес, заканчивающийся на доменное имя Jenkins. Это минимизирует шанс того, что email попадет в спам-папку. Сервер Jenkins не имеет разрешения отправлять email от имени других доменов, но большинство почтовых сервисов принимают from-адреса с тем же доменом, что и отправляющий сервер. Прочитайте больше об этом в этой статье Википедии. На изображении ниже я ввел from-адрес, заканчивающийся тем же доменом, что и сервер Jenkins.
Далее, нам нужно дать Jenkins способ отправки email. Самый прямой способ сделать это — установить SMTP (mail) сервер на VPS. Вы можете сделать это, залогиненвшись и выполнив следующие команды:
yum -y install sendmail systemctl enable sendmail systemctl restart sendmail
После того как вы установили sendmail, вернитесь к конфигурации системы Jenkins и введите "localhost" в поле SMTP server, как показано на изображении ниже.
В этот момент вы также можете поставить галочку, чтобы разрешить отправку незарегистрированным пользователям. Это означает пользователей, у которых нет аккаунта Jenkins. Позже мы настроим Jenkins отправлять email любому человеку, который пушит ошибочный код в GitHub. Jenkins получит email-адрес виновника из GitHub, но это будет работать только если у человека есть соответствующий Jenkins-аккаунт, или если мы поставим эту галочку.
Наконец, вы можете протестировать конфигурацию, как показано на изображении выше. После нажатия Test configuration, сообщение "Email was successfully sent" должно появиться, и email должен дойти в ваш inbox. Проверьте спам-папку, если вы не получаете email в течение пяти минут.
Установка Xilinx Vivado в батч-режиме
Я использую Xilinx Vivado для симуляции, компиляции и реализации кода в этом примере проекта. Целевое устройство — Xilinx Zynq-7000 FPGA на плате разработки ZebBoard. В этом разделе я покажу, как установить Vivado на VPS, используя бесплатную лицензию WebPACK.
Первый шаг — скачать Xilinx Unified Installer: Linux Self Extracting Web Installer, показанный на изображении ниже. Вам понадобится войти или создать новый аккаунт Xilinx для скачивания установщика.
Когда скачивание завершится, вы должны скопировать его с вашего настольного компьютера на сервер Jenkins. Если у вас есть доступ к Linux-шеллу на вашем десктопе, я предлагаю использовать безопасное копирование файлов, как в следующей команде:
scp Xilinx_Unified_2019.2_1106_2127_Lin64.bin root@your_server_ip:/root/
Прежде чем вы сможете запустить установщик, вы должны установить несколько пакетов для удовлетворения зависимостей Vivado. Выполните следующие команды для этого:
yum -y install tar yum -y install java-11-openjdk-devel yum -y install ncurses-compat-libs yum -y install gcc
Затем запустите Xilinx Unified установщик так:
./Xilinx_Unified_2019.2_1106_2127_Lin64.bin --keep --noexec --target Xil_installer
.bin файл распакует установочные файлы в новый каталог Xil_installer. Если вы получите ошибку, перечисленную ниже, это потому, что вы не установили tar.
Verifying archive integrity... All good. Uncompressing Xilinx Installer Extraction failed. Terminated
Xilinx Unified установщик может установить многие разные инструменты Xilinx на вашей системе. Поэтому мы должны запустить файл xsetup в каталоге Xil_installer, чтобы указать, какое ПО нам интересно:
cd Xil_installer/ ./xsetup -b ConfigGen
Скрипт xsetup запросит, какие инструменты вы хотели бы иметь. Введите "2" для Vivado, а затем "1" для Vivado HL WebPACK, как показано в листинге ниже.
Select a Product from the list: 1. Vitis 2. Vivado 3. On-Premises Install for Cloud Deployments 4. BootGen 5. Lab Edition 6. Hardware Server 7. Documentation Navigator (Standalone) Please choose: 2 Select an Edition from the list: 1. Vivado HL WebPACK 2. Vivado HL Design Edition 3. Vivado HL System Edition Please choose: 1
Для установки Xilinx WebPACK издания, вы должны войти в свой аккаунт Xilinx во время установки. На десктопном компьютере GUI установщика проведет вас через этот процесс, но на сервере нет GUI, поэтому мы должны аутентифицироваться, используя скрипт xsetup. Запустите следующую команду для генерации токена аутентификации:
./xsetup -b AuthTokenGen
Мне пришлось запустить команду несколько раз, прежде чем она сработала. Сначала скрипт останавливался с ошибкой "Internet connection validated, can connect to internet." Однако после нескольких попыток я прошел, и смог войти. Скрипт попросит ваш user ID и пароль. Это email и пароль, которые вы использовали для скачивания установщика с xilinx.com.
Наконец, вы готовы установить Vivado в батч-режиме. При вызове скрипта установки, вы должны указать конфигурационный файл установки, чтобы xsetup знал, какие инструменты скачивать. Конфигурационный файл находится в папке .Xilinx в домашней директории root-пользователя. Запустите следующую команду для начала установки, используя конфигурационный файл:
./xsetup -a XilinxEULA,3rdPartyEULA,WebTalkTerms \ -b Install -c ~/.Xilinx/install_config.txt
Процесс установки займет много времени. Установка Vivado использует 24 ГБ места. Все это сейчас скачивается с относительно медленного сервера Xilinx. Для меня скачивание заняло чуть более двух часов.
После завершения установки, вы должны протестировать, что Vivado успешно запускается в батч-режиме. Xilinx предоставляет shell-скрипт, который настраивает окружение для вас. Прежде чем вы сможете запустить Vivado, вам нужно использовать команду source для загрузки содержимого скрипта в ваш активный шелл:
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Тогда вы готовы запустить Vivado. Но нет GUI-окружения на вашем сервере, поэтому мы должны запустить его в батч-режиме, используя эту команду:
vivado -mode batch -source test.tcl
Если Vivado запускается и сразу выходит без печати каких-либо ошибок, это признак того, что Vivado имеет все, что ему нужно, и вы готовы к работе. Обратите внимание, что если вы получаете ошибку, перечисленную ниже, это потому, что вы не установили пакет ncurses-compat-libs, как мы обсуждали в начале этого раздела.
application-specific initialization failed: couldn't load file "librdi_commontasks.so": libtinfo.so.5: cannot open shared object file: No such file or directory
Интеграция Vivado в Jenkins
Для подготовки Jenkins к Vivado, нам нужно сделать некоторые изменения в общих настройках. Идите в Manage Jenkins->Configure System и проверьте, что все настройки по умолчанию имеют смысл для вас.
Как я упоминал ранее, Vivado использует много RAM. Использование ресурсов зависит от вашего целевого FPGA, и вы можете получить индикацию того, сколько вам нужно, со страницы рекомендаций по памяти Xilinx. Поэтому я рекомендую изменить стандартное количество параллельных джоб, которые могут работать, с 2 на 1. Если вы не выделили огромные RAM-ресурсы на вашем VPS, вы, вероятно, захотите установить # of executors в 1, как показано на изображении ниже.
Вместо определения переменных окружения в каждой джобе Jenkins, мы укажем PATH глобально для всех джоб. Это облегчит вам переключение на более новую версию Vivado в будущем. Тогда вы можете ссылаться на исполняемый файл 'vivado' в ваших скриптах, и он всегда будет указывать на последнюю версию, или какую вы решите.
Прокрутите в раздел Global properties и поставьте галочку Environment variables. Нажмите Add для получения новой записи. Убедитесь, что включен стандартный Linux PATH тоже. Я использовал "PATH=/tools/Xilinx/Vivado/2019.2/bin:/sbin:/usr/sbin:/bin:/usr/bin", как показано на изображении ниже.
Не забудьте прокрутить вниз страницы и нажать Save.
Vivado GUI проекты в батч-режиме
Я выбрал управлять Vivado-проектами в GUI-режиме. Для каждого репозитория я создал новый проект из обычного Vivado GUI, добавляя исходные файлы, настраивая библиотеки и все то. Однако файлы проекта .xpr являются бинарными и зависят от множества других временных файлов в директории проекта.
Бинарные файлы не подходят для SCM, таких как Git. К счастью, Xilinx подумал об этом и написал гайдлайн (XAPP1165) для того, как использовать Vivado с системами контроля версий. Что мы делаем — используем команду write_project_tcl в Vivado для экспорта всего проекта в Tcl-скрипт. Скрипт содержит человекочитаемый Tcl-код, подходящий для Git.
Я организовал все Git-репозитории так, что все файлы, принадлежащие Vivado-проектам, находятся в подпапке "vivado", в то время как VHDL-исходные файлы находятся в родительской директории. Посмотрите демо-проект packages на моем GitHub, чтобы увидеть, что я имею в виду. Для каждого репо мы положим Vivado Tcl-скрипты в папку vivado. Вы также найдете файл create_vivado_proj.tcl, который является человекочитаемой версией Vivado-проекта.
Чтобы создать файл create_vivado_proj.tcl, начните с настройки Vivado-проекта так, как вы хотите, в Vivado GUI. Убедитесь, что Vivado-проект находится внутри подпапки vivado. Когда вы довольны проектом, экспортируйте его, введя следующие команды в Vivado Tcl-консоли:
cd [get_property DIRECTORY [current_project]] write_project_tcl -force -target_proj_dir . create_vivado_proj
Добавьте файл create_vivado_proj.tcl в Git, и настройте gitignore для игнорирования остального Vivado-проекта. Вот содержание моего файла .gitignore, который игнорирует всё, кроме Tcl-скриптов в папке vivado:
vivado/* !vivado/*.tcl
Открытие Vivado-проекта в батч-режиме
Хорошая идея — протестировать Vivado-проект вручную на VPS перед тем, как начать создавать джобы Jenkins. По умолчанию демон работает от аккаунта пользователя jenkins на Linux-сервере. Поэтому вы должны протестировать Vivado-проект, используя пользователя jenkins.
Убедитесь, что у вас установлен Git на Linux-сервере перед началом этого эксперимента. Выполните эту команду для установки Git после входа как root:
yum -y install git
Вы не можете зайти в пользователя jenkins напрямую, но вы можете переключиться на него от root-пользователя так:
su - jenkins
Если вы теперь выполните команду pwd, вы увидите, что вы в /var/lib/jenkins:
[jenkins@jenkins ~]$ pwd /var/lib/jenkins
Это потому, что это не обычный пользовательский аккаунт, у которого домашняя директория под /home, как обычно на Linux-системах. Это только для запуска демона Jenkins, но мы можем зайти для выполнения ручного прохождения процесса сборки в окружении Jenkins.
Домашняя папка полна всех динамических данных, таких как логи, настройки пользователей и плагины, которые вы скачали. Когда мы позже начнем запускать джобы в Jenkins GUI, они появятся в папке jobs.
Пойдем в папку jobs для выполнения нашего эксперимента:
cd /var/lib/jenkins/jobs/
Вы можете клонировать ваш Git-репозиторий прямо в папку jobs. Ваш Git-репо должен быть доступен без использования пароля. Либо потому что он публичный, либо потому что вы настроили безпарольный вход, как описано на страницах помощи GitHub.
Если у вас нет Git-репозитория с Vivado-проектом, готового, не стесняйтесь клонировать один из моих репозиториев так:
git clone https://github.com/jonasjj/Jenkins-demo-packages
Затем cd в новую директорию Git-репозитория, и дальше в папку vivado:
cd Jenkins-demo-packages/vivado/
Если вы скачали мой пример, вы найдете два Tcl-файла: create_vivado_proj.tcl и check_syntax.tcl. Первый — это Vivado-проект, преобразованный в Tcl-файл, а второй — скрипт, о котором мы еще не говорили. Он для проверки синтаксиса VHDL-файлов в Vivado-проекте.
Прежде чем мы сможем запустить любую Vivado-команду, нам нужно установить переменную окружения PATH в текущем шелле. В Jenkins мы решили это, используя Global properties, но сейчас мы не идем через Jenkins, поэтому нам нужно подключить setup-скрипт от Xilinx так:
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Теперь, когда исполняемый файл vivado в нашем пути, давайте начнем с пересоздания проекта. Это команда для этого при запуске Vivado в батч-режиме:
vivado -mode batch -source create_vivado_proj.tcl
После нажатия Enter, вы должны увидеть кучу Tcl-кода, эхом выведенного в консоль. Это код для пересоздания Vivado-проекта, который выполняется. Если вы не видели явных ошибок, введите команду "echo $?" в терминале перед тем, как делать что-либо еще. Вывод должен быть 0, если все прошло хорошо, как мы видим из листинга ниже.
INFO: [Common 17-206] Exiting Vivado at Sun Apr 19 18:32:48 2020... [jenkins@jenkins vivado]$ echo $? 0
Команда "echo $?" показывает вам статус выхода от предыдущей команды, которую вы выполнили в Linux. Статус выхода 0 означает, что все ОК, нет ошибки. Любой другой статус выхода, кроме 0, является индикацией ошибки. Это старые Unix-конвенции, о которых можно прочитать больше здесь. В любом случае, статус выхода важен для Jenkins, потому что именно так он решает, является ли стадия джобы успехом или неудачей.
Если вы сейчас сделаете листинг директории, вы увидите, что Vivado пересоздал бинарные файлы проекта:
[jenkins@jenkins vivado]# ls -la total 72 drwxrwxr-x. 6 jenkins jenkins 4096 Apr 19 18:32 . drwxrwxr-x. 4 jenkins jenkins 4096 Apr 19 18:18 .. -rw-rw-r--. 1 jenkins jenkins 217 Apr 19 18:18 check_syntax.tcl -rw-rw-r--. 1 jenkins jenkins 23375 Apr 19 18:18 create_vivado_proj.tcl drwxrwxr-x. 3 jenkins jenkins 16 Apr 19 18:32 packages.cache drwxrwxr-x. 2 jenkins jenkins 26 Apr 19 18:32 packages.hw drwxrwxr-x. 2 jenkins jenkins 6 Apr 19 18:32 packages.ip_user_files -rw-rw-r--. 1 jenkins jenkins 9314 Apr 19 18:32 packages.xpr -rw-rw-r--. 1 jenkins jenkins 638 Apr 19 18:32 vivado.jou -rw-rw-r--. 1 jenkins jenkins 20153 Apr 19 18:32 vivado.log drwxrwxr-x. 2 jenkins jenkins 6 Apr 19 18:32 .Xil
Давайте попробуем другой эксперимент с запуском Tcl-скриптов в Vivado батч-режиме. Создайте однострочный Tcl-скрипт, используя следующую команду:
echo 'exit 1' > test.tcl
Теперь запустите скрипт в Vivado батч-режиме:
vivado -mode batch -source test.tcl
После закрытия Vivado, проверьте код выхода еще раз, используя команду "echo $?":
[jenkins@jenkins vivado]# echo $? 1
Это 1, что означает неудачу выхода в Unix. Если вы измените содержимое скрипта test.tcl на "exit 0", и запустите Vivado еще раз, вы увидите, что статус выхода теперь 0, указывая на успех. Попробуйте!
Ключевое слово exit — стандартный Tcl. Мы будем использовать его как интерфейс между Vivado и Jenkins. Jenkins запускает какой бы Tcl-скрипт мы создадим в Vivado, и смотрит на статус выхода, чтобы решить, должен ли он пометить стадию джобы как успех или неудачу.
Помните, удалить наш маленький тестовый проект из папки jobs, когда вы довольны экспериментом:
cd /var/lib/jenkins/jobs/ [jenkins@jenkins jobs]# rm -rf Jenkins-demo-packages
Tcl-скрипт для проверки синтаксиса кода в Vivado
Этот Tcl-скрипт запускает проверку синтаксиса VHDL-файлов в проекте. Если вы собираетесь симулировать или реализовывать код, вам не понадобится этот скрипт, потому что любые ошибки сломают компиляцию. Но для моего проекта packages не имеет смысла создавать тестбенч для него. Файлы просто содержат объявления констант и типов. Я все равно хочу ловить любые ошибки кодирования, пушнутые в этот репо, и именно здесь проверка синтаксиса пригождается.
В скрипте, приведенном ниже, мы начинаем с открытия файла проекта. Затем мы вызываем Vivado-команду check_syntax, говоря ей сохранить вывод в переменную msg. После завершения проверки, мы смотрим на выходное сообщение, чтобы увидеть, были ли какие-либо ошибки. Если check_syntax сообщил о чем-либо вообще, мы устанавливаем статус выхода в 1 (неудача). Если ошибок не было, мы выходим 0 (успех).
check_syntax.tcl:
# Check for syntax errors
# Return exit code 1 on error, else 0
open_proj packages.xpr
set msg [check_syntax -fileset sim_1 -return_string]
set ret_val 0
if {$msg != ""} {
set ret_val 1
}
puts $msg
exit $ret_val
Vivado поддерживает все стандартные ключевые слова Tcl, и есть также много встроенных команд вроде check_syntax. Я рекомендую взглянуть на эти два документа Xilinx, которые охватывают возможности Tcl-скриптинга в деталях:
Vivado Design Suite Tcl Command Reference Guide (UG835)
Vivado Design Suite User Guide Using Tcl Scripting (UG894)
Tcl-скрипт для симуляции в Vivado
Следующий скрипт, который я создал, для запуска тестбенча в батч-режиме. Для этого вы должны настроить симуляционные файлы в Vivado GUI перед экспортом проекта в Tcl. Пойдите вперед и пересоздайте один из симуляционных проектов на вашем десктопном компьютере, используя скрипт create_vivado_proj.tcl, чтобы увидеть, как я настроил это заранее. Вы можете открыть пересозданные проекты в Vivado GUI.
Как вы можете видеть из листинга ниже, я начинаю с открытия проекта. Затем я устанавливаю имя симуляционного файла в переменную (обычно sim_1). После запуска симуляции, нам также нужно ее закрыть. Иначе статус симуляции не запишется в лог-файлы.
run_simulation.tcl:
open_proj seg7.xpr set sim_fileset sim_1 launch_simulation -simset [get_filesets $sim_fileset] close_sim # Look for assertion failures in the simulation log set log_file [glob *sim/$sim_fileset/behav/xsim/simulate.log] set fp [open $log_file] set file_data [read $fp] exit [regex "Failure:" $file_data]
Теперь я боролся, чтобы найти хороший способ получения статуса симуляции. Мои VHDL-тестбенчи терминируются по ключевому слову VHDL finish при успехе. Ошибки приведут к VHDL assertion failure. Нет очевидного способа узнать, почему симулятор остановился, используя Tcl-команды в Vivado.
К счастью, Tcl — мощный скриптовый язык. Моя обходная дорога — открыть лог симуляции и поискать строку "Failure:", которая указывает на VHDL assertion failure. Наконец, мы выходим 1, если слово в логе, или 0, если его нет.
Tcl-скрипт для синтеза в Vivado
В Tcl-скрипте для синтеза в Vivado батч-режиме, мы начинаем с открытия файла проекта. Затем мы назначаем имя запуска переменной. Вы должны были добавить файлы дизайна в Vivado-проект перед экспортом в Tcl. Если вы не меняли имя синтеза в GUI, оно, вероятно, будет "synth_1".
Вы должны установить переменную CPU count в количество логических процессоров, которые имеет ваш сервер. Это число контролирует степень многопоточности, которую использует Vivado. Я выбрал VPS с 4 CPU на UpCloud, и поэтому установил CPU count в 4.
run_synthesis.tcl:
open_proj seg7.xpr
set run_name synth_1
set cpu_count 4
reset_runs $run_name
launch_runs $run_name -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "synth_design Complete!"} {
exit 1
}
exit 0
Команда launch_runs неблокирующая, означает, что она завершится до фактического синтеза. Если мы попытаемся прочитать статус сразу после вызова launch_run, он будет "Running". Чтобы поставить скрипт на паузу до завершения синтеза, мы вызываем команду wait_on_run.
Наконец, мы получаем статус запуска и выходим 0 или 1, в зависимости от сообщения статуса.
Tcl-скрипт для запуска реализации в Vivado
Скрипт для запуска Place and Route (PAR) в Vivado батч-режиме похож на скрипт синтеза. Разница в том, что имя запуска теперь "impl_1", и мы ищем другое сообщение об успехе.
run_implementation.tcl:
open_proj seg7.xpr
set run_name impl_1
set cpu_count 4
reset_runs $run_name
launch_runs $run_name -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "route_design Complete!"} {
exit 1
}
exit 0
Tcl-скрипт для генерации битстрима в Vivado
Наконец, если реализация завершилась успешно, мы можем сгенерировать битстрим для программирования FPGA. Скрипт похож на предыдущий, но команда launch_runs немного другая. И, конечно, мы ищем другой статус в конце.
generate_bitstream.tcl:
open_proj seg7.xpr
set run_name impl_1
set cpu_count 4
launch_runs $run_name -to_step write_bitstream -jobs $cpu_count
wait_on_run $run_name
set status [get_property STATUS [get_runs $run_name]]
if {$status != "write_bitstream Complete!"} {
exit 1
}
exit 0
Настройка джоб Jenkins
Джоба в Jenkins относится к набору сгруппированных программных задач. Jenkins отображает джобы и их текущий статус как элементы, перечисленные на обзорной странице. Вы можете запускать джобы вручную из веб-интерфейса, или они могут запускаться автоматически, например, когда кто-то пушит код в репо, или в результате завершения другой джобы. Мы будем делать и то, и другое.
Jenkins предлагает несколько способов управления джобами. Традиционный метод — Freestyle project, где вы указываете каждое действие из веб-GUI Jenkins. Более современный способ управления джобами Jenkins — использовать pipeline-скрипт, который хранит всю информацию о потоке выполнения. Pipeline-скрипты имеют выгоду в том, что вы можете добавить их в ваш SCM.
Чтобы создать новый pipeline-скрипт, выберите New item из сайдбара Jenkins. В открывающемся диалоге выберите опцию Pipeline и нажмите OK, как показано на изображении ниже.
Первое, что мы должны сделать в конфигурации джобы — добавить GitHub-репозиторий, содержащий исходный код. В этом примере я использую репозиторий packages, но процедура та же для всех других джоб и репозиториев. Поставьте галочку GitHub project и введите адрес в поле Project url, которое появится, как показано на изображении ниже.
После этого мы можем настроить триггеры сборки для этой джобы. Я хочу, чтобы эта джоба запускалась, когда кто-то пушит код в GitHub-репо. Для этого мы ставим галочку, которая говорит GitHub hook trigger for GITScm polling, как показано на изображении ниже. Обратите внимание, что это будет работать только если вы поставили галочку Manage hooks в глобальных настройках, как мы делали ранее.
Внизу страницы конфигурации джобы находится раздел Pipeline. Здесь у вас есть опция ввести pipeline-скрипт прямо на странице конфигурации. Но мы хотим версионировать pipeline-скрипт. Поэтому мы выбираем опцию Pipeline script from SCM. Убедитесь, что Git выбран, как показано на изображении ниже.
Вставьте URL вашего GitHub-репозитория, и выберите ваши креденшлы, если это приватный репо. Наш публичный, поэтому мы оставим креденшлы пустыми. Мы также пойдем с выбором ветки master по умолчанию.
Наконец, нам нужно выбрать путь к Jenkins-скрипту внутри Git-репозитория. Я создал файл с именем Jenkinsfile в корне каждого репо. Не забудьте нажать Save перед уходом со страницы.
Pipeline-скрипты Jenkins
Pipeline-скрипты следуют тем же синтаксическим правилам, что и язык программирования Apache Groovy, чего я должен признать, я никогда не слышал раньше. Тем не менее, у вас не будет трудно понять pipeline-скрипты, если вы делали любой вид современного программирования. На первый взгляд, это выглядит как JSON-схема без запятых, разделяющих элементы данных.
Скрипты довольно универсальны, и есть много опций для вещей вроде выполнения стадий параллельно или запуска задач на нескольких серверах Jenkins. Я предлагаю взглянуть на официальную документацию Jenkins pipeline, если вы хотите копать глубже в этом вопросе.
К счастью, вам не нужно знать о них всё, чтобы получать выгоду от pipeline-скриптов. Мы будем использовать формат ниже как шаблон для всех ваших скриптов. Мы добавим столько стадий, сколько нужно, чтобы разделить джобу на логические шаги.
pipeline {
agent any
stages {
stage('Stage name 1') {
steps {
// Command 1
// Command 2
// Etc.
}
}
stage('Stage name 2') {
steps {
// Command 1
// Command 2
// Etc.
}
}
}
post {
failure {
emailext attachLog: true, body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Если кто-то пушит ошибочный код в репо, мы хотим, чтобы виновник получил автоматизированный email с информацией о упавшей джобе. Для этого мы используем секцию failure внутри секции post. Эта часть скрипта выполнится только если любая из стадий упадет. Тогда джоба остановится. Jenkins не пойдет к следующей стадии, если одна упадет. Вместо этого он перепрыгнет в секцию failure. Jenkins затем поднимет email-адреса из последних Git-коммитов и отправит им email со ссылкой на сломанную сборку.
Джоба проверки синтаксиса VHDL
Единственный репо в нашем дизайне, у которого нет тестбенча — это репо packages — вместо этого мы используем наш скрипт check_syntax.tcl для верификации, что код — по крайней мере — валидный VHDL.
В первом шаге нашего pipeline-скрипта мы вызываем deleteDir(). Это одна из базовых команд, доступных в pipeline-скриптах Jenkins. Она чистит рабочую директорию, удаляя любые остатки от предыдущих сборок.
На следующей строке мы вызываем git. Обратите внимание, что это не git Linux-команда, а команда, ссылающаяся на git-плагин Jenkins. Мы говорим ему клонировать репозиторий в рабочую область.
Наконец, на третьей строке стадии Create project, мы используем ключевое слово sh для вызова Linux shell-команды. Здесь мы переходим в директорию vivado и запускаем скрипт create_vivado_proj.tcl в Vivado батч-режиме для пересоздания Vivado-проекта.
Jenkinsfile:
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir() // clean up workspace
git 'https://github.com/jonasjj/Jenkins-demo-packages'
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Check VHDL syntax') {
steps {
sh 'cd vivado && vivado -mode batch -source check_syntax.tcl'
}
}
}
post {
failure {
emailext attachLog: true, body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Во второй стадии, названной Check VHDL syntax, Vivado-проект уже существует, поэтому мы можем перепрыгнуть к запуску нашего Tcl-скрипта. Мы используем shell-команду снова для запуска файла check_syntax.tcl, который выйдет 0 при успехе, или 1 при ошибке, заставляя Jenkins пометить сборку как неудачу.
Джобы симуляции VHDL
Для всех других джоб, кроме репо packages, однострочная команда git не сработает для чекаута кода из GitHub. Проблема в том, что эти репо имеют зависимости в виде сабмодулей. Сабмодули ссылаются на другие Git-репозитории, которые простая команда git не пуллит по умолчанию. Но это ОК; мы можем исправить проблему, используя более универсальный вызов checkout, также хорошо документированный на странице Git-плагина.
Jenkinsfile;
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir() // clean up workspace
checkout([$class: 'GitSCM',
branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [
[$class: 'SubmoduleOption',
disableSubmodules: false,
parentCredentials: false,
recursiveSubmodules: true,
reference: '',
trackingSubmodules: true
]
],
submoduleCfg: [],
userRemoteConfigs: [[
url: 'https://github.com/jonasjj/Jenkins-demo-bcd_encoder'
]]
])
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Run simulation') {
steps {
sh 'cd vivado && vivado -mode batch -source run_simulation.tcl'
}
}
}
post {
failure {
emailext attachLog: true, body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Наконец, мы запускаем скрипт run_simulation.tcl в Vivado в следующей стадии.
Вышеприведенный листинг показывает скрипт, использованный в репо bcd_encoder. Идентичные скрипты, только с разными URL репозиториев, используются для репозиториев counter, digit_selector, output_mux, reset и seg7_encoder тоже.
Джоба реализации FPGA
Репозиторий seg7 содержит верхний модуль для нашего FPGA-проекта. Он подтягивает все другие репо как сабмодули. Pipeline-скрипт похож на тот, что использовался для симуляции-только джоб, но с четырьмя добавленными стадиями: Run simulation, Run synthesis, Run implementation, Generate bitstream и Release bitfile.
Первые две стадии создают проект и запускают симуляцию. Я уже описал, как они работают в предыдущих разделах этой статьи. Следующие три стадии работают так же, как стадия симуляции, но с Tcl-скриптом, замененным на соответствующие для задачи.
Jenkinsfile:
pipeline {
agent any
stages {
stage('Create project') {
steps {
deleteDir() // clean up workspace
checkout([$class: 'GitSCM',
branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [
[$class: 'SubmoduleOption',
disableSubmodules: false,
parentCredentials: false,
recursiveSubmodules: true,
reference: '',
trackingSubmodules: true
]
],
submoduleCfg: [],
userRemoteConfigs: [[
url: 'https://github.com/jonasjj/Jenkins-demo-seg7'
]]
])
sh 'cd vivado && vivado -mode batch -source create_vivado_proj.tcl'
}
}
stage('Run simulation') {
steps {
sh 'cd vivado && vivado -mode batch -source run_simulation.tcl'
}
}
stage('Run synthesis') {
steps {
sh 'cd vivado && vivado -mode batch -source run_synthesis.tcl'
}
}
stage('Run implementation') {
steps {
sh 'cd vivado && vivado -mode batch -source run_implementation.tcl'
}
}
stage('Generate bitstream') {
steps {
sh 'cd vivado && vivado -mode batch -source generate_bitstream.tcl'
}
}
stage('Release bitfile') {
steps {
sh '''
PROJ_NAME=seg7
RELEASE_DIR=/usr/share/nginx/html/releases/
BASE_NAME=$PROJ_NAME-`date +"%Y-%m-%d-%H-%H:%M"`
BITFILE=$BASE_NAME.bit
INFOFILE=$BASE_NAME.txt
git log -n 1 --pretty=format:"%H" >> $INFOFILE
echo -n " $PROJ_NAME " >> $INFOFILE
git describe --all >> $INFOFILE
echo "" >> $INFOFILE
echo "Submodules:" >> $INFOFILE
git submodule status >> $INFOFILE
cp $INFOFILE $RELEASE_DIR
cp vivado/seg7.runs/impl_1/top.bit $RELEASE_DIR/$BITFILE
'''
}
}
}
post {
failure {
emailext attachLog: true, body: '''Project name: $PROJECT_NAME
Build number: $BUILD_NUMBER
Build Status: $BUILD_STATUS
Build URL: $BUILD_URL''',
recipientProviders: [culprits()],
subject: 'Project \'$PROJECT_NAME\' is broken'
}
}
}
Финальная стадия джобы реализации названа Release bitfile. Она содержит shell-скрипт, который копирует только что сгенерированный FPGA-программируемый файл в папку релизов. Shell-команда переименовывает файл, чтобы включить имя проекта и временную метку.
Для поддержания трассируемости мы также генерируем текстовый файл, содержащий Git-хеш основного репо (seg7) и всех сабмодулей. При работе с Git сабмодулями недостаточно хранить хеш основного репо. Чтобы сгенерировать хеш для основного репо, включающий изменения во всех сабмодулях, нам пришлось бы закоммитить основное репо после пулла и обновления всех сабмодулей. Мы не хотим делать это автоматически из Jenkins.
Обратите внимание, что реализация FPGA для каждого пуша, как я делаю в примере, вероятно, не то, что вы хотите для реального Jenkins-проекта. Это может занять часы для сборки крупномасштабного FPGA-проекта, и это не сработает, когда у вас есть команда разработчиков, пушащих несколько раз в день. Вместо сборки после каждого пуша в репо, вы можете настроить Jenkins на роутинг FPGA только раз в день. Например, в полночь, как показано на скриншоте ниже со страницы конфигурации джобы.
Запуск сборок после завершения других джоб
Наш пример проекта состоит из нескольких Git-репозиториев, но они все связаны вместе как Git сабмодули. За исключением packages, все другие репо зависят хотя бы от одного другого репозитория. Большинство зависят от репозитория packages. Посмотрите на граф зависимостей, который я представил ранее в этой статье, чтобы увидеть, как все это соединяется вместе.
Поэтому мы должны запускать джобы не только пушами в репо в вопросе, но и после того, как любые из сабмодулей затронуты. Мы можем достичь этого в Jenkins, посетив каждую джобу и установив опцию Build after other projects are built соответствующим образом.
Изображение ниже показывает триггер для проекта bcd_encoder. Он запустится после репо packages, от которого он зависит, завершит сборку успешно.
Верхний модуль зависит от всех других репозиториев. Я добавил их как watch-проекты в списке, разделенном запятыми, как показано на изображении ниже. Обратите внимание, что вы можете не захотеть делать это для джобы реализации FPGA, если она занимает много времени на роутинг, как я упоминал в предыдущем разделе.
Обслуживание битфайлов через Nginx
Поскольку у нас уже запущен веб-сервер, мы можем использовать его для обслуживания файлов релизов через HTTP. Я хочу, чтобы все новые битфайлы появлялись на URL jenkins.vhdlwhiz.com/releases. Давайте посмотрим, как мы можем использовать Nginx для этого.
Наша джоба реализации уже копирует новые битфайлы в директорию на Nginx HTML root, но мы еще не создали её. Создайте директорию релизов и дайте пользователю Jenkins права на запись, выполнив следующие команды:
mkdir /usr/share/nginx/html/releases/ chown jenkins.root /usr/share/nginx/html/releases/
Затем мы должны сделать изменение в файле /etc/nginx/nginx.conf. Найдите server-секцию в конфигурационном файле с именем, равным вашему домену. Добавьте следующую location-секцию внутрь неё, прямо ниже корневой ('/') location-секции:
location ^~ /releases {
alias /usr/share/nginx/html/releases/;
autoindex on;
}
Наконец, после того как вы сохранили файл, протестируйте конфигурационный файл и перезагрузите Nginx-сервер:
nginx -t systemctl reload nginx
Если все сработало, вы должны иметь возможность перечислить содержимое директории релизов, как показано на скриншоте ниже из Google Chrome.
Чтобы связать веб-интерфейс Jenkins с директорией релизов, я хочу создать ссылку на неё из сайдбара Jenkins. Мы уже установили плагин Sidebar Link, который позволяет кастомные ссылки в сайдбаре.
Следующий шаг — идти в Manage Jenkins->Configure System и прокрутить вниз к разделу Additional Sidebar Links. Здесь мы можем указать имя и URL новой ссылки, как показано на изображении ниже. Поле иконки ссылки опционально. Я переиспользовал одну из иконок, которые пришли с сервером Jenkins.
После завершения предыдущего шага, у вас теперь должна быть кастомная ссылка на битфайл-релизы в сайдбаре, с красивой иконкой папки, как вы можете видеть на изображении ниже.
Резюме
Jenkins может быть ценным инструментом также для FPGA-команд. Автоматизация задач может сэкономить вашей компании время и улучшить качество вашего кода. Используя автоматические триггеры сборки и автоматизированные pipeline-джобы, меньше ошибок кодирования останется незамеченными.
Как мы видели из примера проекта, представленного в этой статье, Jenkins может реализовать полный набор регрессионных тестов для вашего VHDL-кода. Он показывает текущее здоровье вашего проекта в приятном графическом веб-интерфейсе, подходящем даже для самых VHDL-неграмотных менеджеров проектов.
Если вы хотите попробовать Jenkins для FPGA-разработки, я рекомендую следовать шагам в этой статье на инстансе UpCloud VPS. Я тщательно исследовал всех VPS-провайдеров несколько лет назад перед перемещением VHDLwhiz на VPS. Я обнаружил, что UpCloud был самым быстрым и лучшим альтернативой. Я все еще на 100% доволен сервисом.
Если вы решите открыть аккаунт на UpCloud, я прошу вас использовать мою реферальную ссылку или код: NV78V6. Не только вы поддержите VHDLwhiz, но вы также получите $25 кредита на UpCloud при использовании промокода.
VHDL
- Создание Tcl-управляемого тестбенча для VHDL-модуля кодового замка
- Построение надежного таймера в VHDL: подсчет тактовых циклов до часов
- Генерация случайных чисел в VHDL: от Uniform к OSVVM
- Использование записей (Records) в VHDL для чистых, повторно используемых интерфейсов FIFO
- Различия между сигналами и переменными в VHDL
- VHDL контроллер двух 7-сегментных дисплеев для Pmod SSD — простое FPGA-интегрирование
- Продвинутый тест по владению VHDL — Часть 3
- Проектирование конечного автомата в VHDL: практический пример светофора
- Освоение ограниченной случайной верификации с OSVVM
- Освоение конструкций Loop и Exit в VHDL: практическое руководство