Automatiser le développement FPGA avec Jenkins, Vivado et GitHub sur un VPS Linux
* Cet article contient un lien affilié pour VPS UpCloud
La livraison continue et l'intégration continue sont des méthodologies de développement logiciel agile qui raccourcissent le cycle entre modification de code et déploiement. En utilisant l'automatisation pour vérifier les changements de code et construire les fichiers de release, les équipes deviennent plus productives et efficaces.
Les entreprises logicielles pratiquent le développement continu depuis longtemps, mais vous pouvez tout aussi bien appliquer ces méthodes à vos projets FPGA. Ce tutoriel vous apprend à configurer un serveur d'automatisation sur un serveur privé virtuel (VPS) en utilisant Jenkins, Xilinx Vivado et le système de gestion de code source (SCM) Git / GitHub.
Qu'est-ce que Jenkins ?
Le serveur d'automatisation Jenkins est un programme gratuit et open-source écrit en Java. Il fonctionne sur Windows ou Linux. Nous utiliserons Linux dans ce tutoriel car c'est la plateforme la plus courante pour les serveurs headless.
Jenkins s'exécute comme un processus daemon sous Linux ou comme un service sous Windows. Un serveur web intégré que Jenkins lance au démarrage fournit l'interface utilisateur. La plupart des utilisateurs interagissent avec Jenkins via l'interface web. Vous pouvez ajouter de nouveaux projets d'automatisation et gérer les existants via l'interface graphique web.
L'image ci-dessus montre la page principale du serveur Jenkins que nous allons configurer. Par défaut, seuls les utilisateurs connectés peuvent accéder à Jenkins, mais pour cet article, j'ai activé l'accès public à certaines parties de mon *serveur de démonstration.
* Mise à jour : j'ai arrêté le serveur de démonstration le 13 mai 2020
Ce que vous voyez sur la page principale est une liste de jobs. Ces jobs peuvent contenir n'importe quelles tâches, et peuvent être déclenchés manuellement depuis l'interface web. Ou ils peuvent être déclenchés automatiquement via des scripts, webhooks, ou suite à la completion d'autres jobs. D'où le terme serveur d'automatisation.
Dans notre exemple, chaque job correspond à un module VHDL conservé dans un dépôt GitHub séparé. Nous ferons en sorte que Jenkins lance une simulation et construise le projet à chaque fois qu'un développeur pousse du code vers l'un des dépôts Git surveillés. Si un testbench échoue ou si la construction casse, Jenkins marquera le job comme échoué dans l'interface web et enverra automatiquement un email à la personne ayant commis le code défectueux.
Le projet d'exemple
Les serveurs d'automatisation sont plus utiles pour les équipes travaillant sur des projets plus importants. J'ai donc construit un projet FPGA d'exemple composé de huit dépôts Git. Le projet est le compteur afficheur 7 segments du cours Fast-Track porté sur la carte Xilinx ZedBoard.
Liens vers les huit dépôts sur GitHub :
- packages (packages VHDL)
- bcd_encoder (Module)
- counter (Module)
- digit_selector (Module)
- output_mux (Module)
- reset (Module)
- seg7_encoder (Module)
- seg7 (Module principal)
Chaque dépôt contient un module VHDL et son testbench. Exception pour le dépôt packages, qui ne contient que trois packages VHDL définissant constantes et types. De plus, le module principal seg7 contient un fichier de contraintes définissant la fréquence d'horloge et les affectations de broches de l'implémentation physique.
La plupart des projets VHDL à grande échelle utilisent des modules de plus d'un dépôt. Les entreprises ont généralement une bibliothèque de packages et modules qu'elles réutilisent dans de nombreux designs. C'est ce que j'émule en découpant ce design relativement simple en autant de modules.
Dans notre exemple, tous les modules dépendent du dépôt packages, et le module principal dépend de tous les sous-modules. J'ai résolu cela en les important selon les besoins via des Git Submodules standards. Le graphe ci-dessus montre le contenu et les dépendances de tous les dépôts de ce projet.
Les dépôts Git contiennent également plusieurs fichiers non-design, comme la configuration Jenkins et les scripts de build. Nous en parlerons dans les sections suivantes.
Serveur privé virtuel (VPS)
Bien que Jenkins puisse tourner sur n'importe quel ordinateur Windows ou Linux, pour toutes fins pratiques, vous voudrez l'exécuter sur un serveur dédié. Le serveur d'automatisation doit être toujours en ligne et accessible à tous les membres de votre équipe. Si vous avez un serveur physique avec une capacité suffisante, c'est parfait. Mais pour la plupart d'entre nous, une solution plus rapide et moins chère est d'utiliser un VPS.
Un VPS est un ordinateur virtuel que vous louez à une société d'hébergement via Internet. Il apparaît comme un vrai ordinateur Windows ou Linux avec lequel vous pouvez interagir et installer les logiciels souhaités. Nous allons utiliser un ordinateur Linux car c'est le plus sensé pour notre cas d'usage.
Le site VHDLwhiz tourne sur un VPS depuis deux ans. J'ai déjà fait le travail de trouver le fournisseur VPS le plus rapide et le meilleur, qui est UpCloud. Naturellement, nous allons utiliser UpCloud pour configurer le VPS de notre serveur d'automatisation.
Obtenir le bonus de 25 $ UpCloud
Si vous souhaitez essayer UpCloud, j'ai un code de parrainage qui vous donnera 25 $ de crédit à l'inscription.
>> Cliquez ici pour obtenir le bonus de 25 $ UpCloud <<
Ou utilisez mon code promo lors du paiement : NV78V6
En utilisant le code, vous obtiendrez le bonus et soutiendrez VHDLwhiz en même temps. Je pourrai recevoir des fonds crédités sur mon compte UpCloud pour chaque client qui l'utilise.
Assez de promotion, passons à la configuration du serveur.
Déploiement du VPS UpCloud
Après vous être connecté à votre nouveau compte UpCloud, vous pouvez commencer la création d'une nouvelle instance VPS en naviguant vers Servers → Deploy server.
UpCloud a de nombreux centres de données dans le monde. Sélectionnez l'emplacement le plus proche de vous pour héberger votre nouveau serveur. Puis choisissez un plan pour les ressources de votre machine virtuelle. Jenkins ne consomme pas beaucoup de ressources, mais Xilinx Vivado est très gourmand en RAM. Choisissez donc au moins le plan avec 4 Go de RAM, comme montré dans l'image ci-dessous.
Je recommande de consulter la page Recommandations Mémoire de Xilinx car l'usage mémoire est étroitement lié à la complexité du FPGA cible. La page indique une utilisation mémoire maximale de 1,9 Go pour le FPGA Zynq-7000 XC7Z045 que j'utilise. J'ai constaté que le plan 2 Go était insuffisant pour le routage du design. Vivado a planté, et le message suivant est apparu dans le log dmesg :
[807816.678940] Out of memory: Killed process 22605 (vivado) total-vm:2046684kB, anon-rss:782916kB, file-rss:308kB, shmem-rss:0kB
Notez que vous pouvez toujours augmenter la RAM et le CPU de votre serveur facilement depuis votre compte UpCloud. Vous n'obtiendrez pas automatiquement l'espace disque supplémentaire des packages plus chers sans repartitionner le système de fichiers du VPS, mais cela fonctionnera. Pour référence, j'ai commencé avec le plan 50 Go de stockage, et j'en ai utilisé 61 % après avoir complété tout le serveur d'automatisation. Vivado seul prend 24 Go d'espace.
Je recommande de sélectionner la dernière distribution CentOS Linux comme système d'exploitation, comme montré dans l'image ci-dessous. Xilinx Vivado supporte officiellement seulement Red Hat Linux, qui n'est pas gratuit. Mais CentOS est une distribution Linux gratuite, soutenue par la communauté, qui suit de près Red Hat.
Il y a ensuite des options réseau que vous pouvez laisser par défaut. Il y a aussi une section sur la page web où vous pouvez uploader vos clés SSH pour une connexion sans mot de passe. Vous pourrez toujours configurer cela plus tard avec la méthode Linux conventionnelle pour uploader les clés SSH.
Enfin, vous devez spécifier le nom d'hôte et le nom du serveur, comme montré dans l'image ci-dessous. Le nom d'hôte est le domaine public que les utilisateurs entreront dans le navigateur pour accéder au serveur Jenkins. Si vous n'avez pas de domaine ou sous-domaine prêt, vous pouvez toujours accéder au serveur via son adresse IP. Quand vous êtes satisfait des paramètres, appuyez sur le bouton Deploy pour créer le serveur.
Après la création du serveur, le mot de passe généré automatiquement s'affichera en notification. Vous pourrez le changer plus tard avec la commande Linux passwd. Si vous avez fourni votre clé SSH avant le déploiement, vous n'aurez pas besoin du mot de passe. Si vous perdez un jour l'accès à votre serveur, vous pouvez toujours vous connecter depuis votre compte UpCloud en cliquant sur Open the console connection, comme montré dans l'image ci-dessous.
Configuration DNS
Le nouveau serveur se voit attribuer des adresses IPv4 et IPv6 permanentes, trouvées dans votre compte UpCloud à Servers → Network. Vous pouvez accéder au serveur par SSH sur le compte root de l'adresse IPv4 publique.
En utilisant l'adresse IP d'exemple de l'image ci-dessous, la commande appropriée à entrer sur votre ordinateur Linux personnel serait :
C'est OK d'utiliser seulement l'adresse IP si vous faites cela en test. Mais une solution plus pratique est d'assigner un nom de domaine permanent au serveur. Pour cela, vous devez acheter un domaine auprès de l'un des nombreux registrars en ligne.
Comme je possède déjà le domaine vhdlwhiz.com, j'ai décidé de créer un sous-domaine pour le serveur Jenkins nommé jenkins.vhdlwhiz.com. Nous avons correctement configuré le nom de domaine sur le serveur UpCloud lors du déploiement. La prochaine étape est de pointer le sous-domaine vers l'adresse IPv4 publique.
L'image ci-dessous montre les paramètres que j'entre dans le fichier de zone DNS de mon registrar. Si je voulais le serveur sur le domaine principal (vhdlwhiz.com), j'aurais laissé le champ hostname vide. Mais je le veux sur le sous-domaine « jenkins » de vhdlwhiz.com. J'entre donc le nom du sous-domaine.
Cela prendra un certain temps après le changement des paramètres DNS avant de pouvoir utiliser le nom de domaine pour accéder à votre site. Généralement pas plus de 20 minutes, mais dans les cas extrêmes, jusqu'à 48 heures pour la propagation à tous les coins d'Internet.
Quand les changements ont pris effet, vous pouvez utiliser le nom de domaine au lieu de l'adresse IP pour vous connecter au serveur via SSH :
ssh root@yoursub.yourdomain.com
Installation de Jenkins
La première chose à faire après vous être connecté au compte root sur votre nouveau serveur Linux est de mettre à jour tous les packages installés. Sous CentOS Linux, yum est le gestionnaire de packages par défaut. Nous allons utiliser la commande yum pour installer la plupart des logiciels.
Exécutez la commande suivante pour mettre à jour tous les packages installés vers les dernières versions :
yum -y update
Maintenant que notre système est à jour, nous pouvons procéder à l'installation. Mais avant d'exécuter la commande yum pour installer Jenkins, nous allons installer explicitement Java version 11. Cela nous évitera des soucis plus tard lors de l'installation de Xilinx Vivado.
Actuellement, aucun interpréteur Java n'est présent sur notre serveur, et si nous disons à yum d'installer Jenkins, il installera Java version 8. Cela fonctionne bien pour Jenkins, mais créera des problèmes plus tard car Vivado dépend de Java version 11.
Installez Java 11 avec cette commande avant d'installer Jenkins :
yum -y install java-11-openjdk-devel
Jenkins n'est pas disponible dans le dépôt logiciel par défaut de CentOS. Heureusement, nous pouvons importer le dépôt Jenkins de Red Hat avec les commandes suivantes :
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
Enfin, nous pouvons installer Jenkins :
yum -y install jenkins
Le serveur Jenkins démarrera automatiquement au prochain démarrage, mais vous pouvez le démarrer sans redémarrer ainsi :
systemctl start jenkins
Vous pouvez toujours vérifier le statut du serveur Jenkins avec la commande systemctl :
systemctl status jenkins
Cela affichera le statut du serveur ainsi que tout message d'erreur :
Jenkins via HTTP non sécurisé
À ce stade, Jenkins tourne sur le port 8080 du VPS, mais vous n'avez aucun moyen de vous y connecter avec votre navigateur. C'est parce que le pare-feu CentOS bloque le port 8080 et le port 80 (HTTP) par défaut. Ce que nous pouvons faire pour corriger cela est d'ouvrir le port 80 dans le pare-feu et de le rediriger vers le port 8080 via iptables.
Mais avant de faire cela, vous devez décider si vous voulez sécuriser votre site avec HTTPS. Le problème avec l'utilisation du seul HTTP et du port 80 est que votre site sera non sécurisé. Si vous y accédez via Wi-Fi public, une personne malveillante sur le même Wi-Fi avec un ordinateur portable et des logiciels de piratage facilement disponibles peut écouter votre connexion et voler vos identifiants de connexion à Jenkins.
Si vous voulez éviter le risque de sécurité du HTTP non chiffré, passez à la section suivante sur la configuration de HTTPS pour Jenkins. Sinon, continuez la lecture.
L'activation de l'accès HTTP non sécurisé à Jenkins est aussi simple que l'exécution des commandes suivantes :
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
Vous pouvez alors entrer votre nom de domaine dans votre navigateur favori, et la page Getting Started de Jenkins devrait apparaître. Au moins dans Google Chrome, l'avertissement « Not secure » s'affichera dans la barre d'adresse, comme montré dans l'image ci-dessous.
Passez à la section Configuration de Jenkins si cela vous convient.
Jenkins via HTTPS sécurisé
Avoir un site web non sécurisé accessible au public est un risque de sécurité énorme. Jenkins peut accéder à votre code source, et tout pirate qui réussit à s'introduire dans le serveur le peut aussi. Heureusement, sécuriser le site n'est qu'à quelques commandes copier-coller.
Jenkins ne peut pas gérer HTTPS seul. Nous devons donc installer un serveur web générique pour rediriger les requêtes arrivant via le canal sécurisé vers le serveur Jenkins non sécurisé. J'utiliserai Nginx, l'un des serveurs web gratuits et open-source les plus populaires aujourd'hui.
Exécutez la commande suivante pour installer et démarrer Nginx :
yum -y install nginx systemctl start nginx
Ensuite, nous devons ouvrir les ports HTTP et HTTPS dans le pare-feu. Nous ne servirons que des requêtes HTTPS, mais nous devons garder le port HTTP ouvert car nous configurerons Nginx pour rediriger toutes les requêtes non sécurisées vers le port sécurisé.
Ces commandes ouvriront le pare-feu pour le trafic web :
firewall-cmd --permanent --zone=public --add-port=80/tcp firewall-cmd --permanent --zone=public --add-port=443/tcp firewall-cmd --reload
L'étape suivante est d'installer un certificat que les navigateurs pourront utiliser pour certifier qu'ils interagissent avec votre site et non un imposteur. Nous allons utiliser l'autorité de certification gratuite Let's Encrypt. Les étapes individuelles sont complexes, mais heureusement, certbot fournit un script qui le fait automatiquement.
Téléchargez et préparez le script avec les commandes suivantes :
apt update apt install snapd snap install core; snap refresh core snap install --classic certbot
Ensuite, lancez le script, qui installera le certificat et fera les modifications nécessaires au fichier de config Nginx :
certbot --nginx
Pendant l'exécution du script, il vous demandera des informations. Répondez par l'affirmative (Yes, Accept) à toutes les questions jusqu'à ce qu'on vous demande de choisir de rediriger ou non le trafic HTTP vers HTTPS. La liste ci-dessous montre les questions, et ma réponse suggérée (2). Permettre à Nginx de rediriger les requêtes non sécurisées assure que personne ne peut entrer explicitement https://yoursite.com et accéder à la version non sécurisée de Jenkins. Nginx les redirigera vers la version sécurisée.
... 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
Enfin, vous devriez activer une tâche cron pour renouveler le certificat périodiquement. Sinon, il expirera, et les navigateurs refuseront d'ouvrir votre site.
Exécutez la commande suivante pour ajouter la tâche cron quotidienne :
echo "0 0 * * * /snap/bin/certbot renew --quiet" | crontab -
Le démon cron exécutera le script de renouvellement quotidiennement à minuit. Vous pouvez lister les tâches cron avec crontab -l et les éditer avec crontab -e. Si vous visitez votre site maintenant, vous verrez la page de test Nginx, et pas Jenkins. Nous corrigerons cela sous peu, mais assurez-vous que l'avertissement « Not secure » a disparu de la barre d'adresse Chrome, comme le montre l'image ci-dessous.
Pour que Nginx serve Jenkins, vous devez modifier le fichier /etc/nginx/nginx.conf. Le crédit pour ce snippet de code revient au blog de Kerren sur Medium. L'éditeur nano est probablement le plus simple pour éditer le fichier de config :
nano /etc/nginx/nginx.conf
Localisez le bloc server qui liste votre nom de domaine et ajoutez les lignes surlignées de la liste ci-dessous à votre fichier nginx.conf. Notez que la première des trois nouvelles lignes va au-dessus du bloc server, et le reste dans le bloc location racine.
Après avoir mis à jour le fichier de config, vous devez recharger Nginx pour que les changements prennent effet. Optionnellement, vous pouvez tester le fichier de config avant de recharger avec la commande :
nginx -t
Nginx affichera OK ou vous indiquera sur quelle ligne du fichier nginx.conf se trouve l'erreur. Quand vous êtes satisfait des changements, vous pouvez recharger le serveur web avec :
systemctl reload nginx
Quand vous visitez maintenant le site Jenkins dans votre navigateur, vous devriez voir la page Getting Started de Jenkins, comme montré dans l'image ci-dessous. Cette fois, c'est servi via une connexion sécurisée, et nous pouvons continuer à configurer Jenkins en toute sécurité depuis l'interface web GUI.
Configuration de Jenkins
La première fois que vous visitez votre site Jenkins, il vous demandera un mot de passe trouvé dans un fichier du système de fichiers Linux. Connecté via SSH, utilisez la commande ci-dessous pour afficher le mot de passe. Copiez-collez-le dans le navigateur pour accéder à l'interface web GUI :
cat /var/lib/jenkins/secrets/initialAdminPassword
À l'écran suivant, Jenkins demandera si vous voulez installer les plugins suggérés, ou si vous voulez spécifier lesquels installer. Choisissez simplement l'option Install suggested plugins pour l'instant. Vous pourrez toujours ajouter ou supprimer des plugins plus tard.
À la page suivante, vous devez créer un utilisateur admin. Remplissez vos détails et créez un mot de passe fort pour votre nouveau compte. Par défaut, seuls les utilisateurs connectés peuvent accéder au serveur Jenkins. Les utilisateurs anonymes ne verront que la boîte de dialogue de connexion s'ils visitent votre site. La seule raison pour laquelle vous pouviez accéder à mon *site de démonstration jenkins.vhdlwhiz.com est que j'ai fait des modifications sur le serveur. J'ai utilisé le plugin Matrix Authorization Strategy pour accorder un accès anonyme à certaines vues.
* Mise à jour : j'ai arrêté le site de démonstration le 13 mai 2020
Quand Jenkins a fini d'installer les plugins, vous verrez le message « Jenkins is ready ! », comme montré dans l'image ci-dessus. Cliquez sur le bouton qui vous mènera à la page de vue d'ensemble vide de votre nouvelle installation Jenkins.
Installation des plugins Jenkins
La première chose à faire est d'installer un certain nombre de plugins. Jenkins a un gestionnaire de plugins intégré pour installer, mettre à jour et supprimer les extensions. Vous trouverez des plugins pour la plupart de vos besoins. Utilisez simplement la fonction de recherche dans le gestionnaire de plugins quand vous avez besoin d'ajouter une fonctionnalité à Jenkins.
Passons à l'installation des plugins que j'ai utilisés pour configurer le serveur Jenkins d'exemple. Dans la barre latérale, choisissez Manage Jenkins → Manage Plugins → Available. Notez qu'aucun plugin n'est listé à moins que vous n'entriez quelque chose dans le champ de recherche. Une fois que vous tapez, ils apparaîtront.
Blue Ocean
Le premier plugin que je recommande d'installer s'appelle Blue Ocean. Ce plugin modernise le flux de travail Jenkins ainsi que l'interface utilisateur. Il installe aussi tout un tas d'autres plugins utiles pour que vous n'ayez pas à les installer individuellement. Recherchez « blue ocean » dans le gestionnaire de plugins et sélectionnez-le pour installation, comme montré dans l'image ci-dessous.
Sur la page de progression d'installation qui apparaît après avoir cliqué sur installer, vous avez l'option de sélectionner Restart Jenkins when installation is complete and no jobs are running. Si vous cochez la case à côté, Jenkins redémarrera après la fin de l'installation du plugin. Une autre façon de redémarrer Jenkins est de vous connecter au serveur via SSH et d'exécuter :
systemctl restart jenkins
Hormis la longue liste d'autres plugins installés par Blue Ocean, il n'y a pas de changement visible au premier coup d'œil. Mais il y aura un nouvel élément de menu dans la barre latérale, comme montré dans l'image ci-dessous. Quand on clique dessus, cela mène à l'interface Blue Ocean, qui a l'air assez différente de l'interface Jenkins normale. Essayez !
Green Balls
Le prochain plugin que j'installe toujours est purement esthétique. Le plugin Green Balls ne nécessite aucune configuration. Recherchez simplement « green ball » dans le gestionnaire de plugins et installez-le comme montré dans l'image ci-dessous.
Par défaut, Jenkins utilise des boules bleues dans la page de vue d'ensemble pour indiquer qu'un job a réussi. La raison est liée au fait que l'inventeur de Jenkins est japonais. Intéressant, au Japon, la couleur bleue est interchangeable avec le vert pour indiquer un statut OK. Plus d'infos dans cet article, où vous pouvez entendre l'auteur l'expliquer de première main.
Les utilisateurs de la plupart des autres régions du monde préféreraient probablement des boules de statut vertes. C'est facilement corrigé par le plugin Green Balls, comme montré dans l'image ci-dessous.
Plugin Locale
Le prochain plugin que j'ai installé s'appelle Locale. Recherchez « locale » sous l'onglet Available dans le gestionnaire de plugins. Installez le plugin, comme montré dans l'image ci-dessous.
Le plugin permet de forcer Jenkins à utiliser la même langue dans l'interface pour tous les utilisateurs. Par défaut, Jenkins traduit l'interface utilisateur vers la langue de votre navigateur web. Je suis norvégien, mais je préfère avoir Jenkins en anglais. La traduction était un peu inadéquate. De plus, c'est beaucoup plus facile de googler des réponses en anglais si vous avez besoin de savoir comment faire quelque chose dans Jenkins.
Bien sûr, c'est entièrement à vous de décider si vous voulez ce plugin. Si vous l'installez, vous devez aller à Manage Jenkins → Configure System et trouver la section Locale. Ensuite, entrez « en_US » (ou la langue que vous voulez) et cochez la case en dessous pour forcer cette langue pour tous les utilisateurs, comme montré dans l'image ci-dessous. N'oubliez pas de descendre en bas de la page et de cliquer Save.
Plugin Sidebar Link
Le dernier plugin dont vous avez besoin pour cloner ma configuration est le plugin Sidebar Link. Il permet d'ajouter des liens personnalisés à la barre latérale Jenkins. Nous l'utiliserons plus tard pour ajouter un lien vers les releases FPGA (bitfiles). Recherchez « sidebar » dans le gestionnaire de plugins et installez le plugin, comme montré dans l'image ci-dessous.
Connexion de Jenkins à GitHub
Que votre dépôt soit public ou privé, vous devez donner à Jenkins certaines permissions sur votre compte GitHub. Au moins si vous voulez le faire de la façon la plus simple, vous devriez laisser le plugin GitHub de Jenkins gérer l'interface avec GitHub pour vous. Blue Ocean a déjà installé le plugin GitHub. Voici les étapes pour le configurer.
D'abord, vous devez installer Git sur votre système. Le plugin GitHub n'en a pas strictement besoin, mais quand vous commencez à travailler avec les jobs Jenkins, vous en avez besoin. Exécutez cette commande pour installer Git sous CentOS Linux :
yum -y install git
Token d'accès personnel dans GitHub
Connectez-vous à GitHub, cliquez sur votre photo de profil en haut à droite, choisissez Settings, et allez dans Developer Settings. Ensuite, choisissez Personal access tokens dans le menu latéral gauche, ou cliquez sur ce lien qui vous y mènera directement.
Ici, vous devez cliquer sur Generate new token, comme montré dans l'image ci-dessous. GitHub vous demandera votre mot de passe une fois de plus. Ce que vous faites maintenant est essentiellement la création d'un nouveau mot de passe spécifique à l'application. C'est mieux que de partager votre vrai mot de passe car vous pouvez le révoquer, et vous pouvez limiter les permissions accordées au token. C'est ce que nous ferons sur la page qui s'ouvre.
Après avoir entré votre mot de passe, vous devez donner un nom au token. Le nom est juste pour vous. Peut-être « Jenkins ». Ensuite, vous devez activer au minimum les permissions admin:org_hook, admin:repo_hook et repo, comme montré dans l'image ci-dessous. Vous pouvez laisser toutes les autres cases décochées.
Enfin, quand vous cliquez sur Generate token, le code d'accès apparaît. Vous devez le copier avant de quitter cette page car il est impossible de le revoir. Si vous l'oubliez, supprimez le token et recréez-le.
Saisie des identifiants GitHub dans Jenkins
Une fois le token copié, allez dans Jenkins, sélectionnez Manage Jenkins → Configure System, et trouvez la section GitHub, comme montré dans l'image ci-dessous. Dans le menu déroulant, sélectionnez Add GitHub Server → GitHub Server.
Dans la nouvelle section GitHub Server qui apparaît, cochez la case Manage hooks. Quand vous faites cela, Jenkins installera des webhooks sur GitHub pour les repos que vous surveillez. Nous verrons plus tard que c'est particulièrement utile car nous les utiliserons pour déclencher une simulation ou un build dans Jenkins quand un utilisateur pousse du code vers le dépôt GitHub associé.
Sélectionnez Credentials (Add) → Jenkins après avoir coché la case, comme montré dans l'image ci-dessous.
Dans la fenêtre qui s'ouvre, changez le menu déroulant Kind à Secret text. Ensuite, collez le token d'accès personnel que vous avez généré précédemment dans GitHub dans le champ Secret. Écrivez « GitHub » dans le champ ID et appuyez sur Add.
Enfin, quand vous revenez au menu de config principal, après avoir ajouté le secret text, sélectionnez la nouvelle clé GitHub dans le menu Credentials. Ensuite, appuyez sur Test connection pour vérifier que Jenkins peut communiquer avec GitHub en utilisant le token d'accès. Si tout s'est bien passé, vous devriez voir un message comme celui montré dans l'image ci-dessous.
Assurez-vous de descendre en bas de la page et de cliquer Save avant de quitter la page de config.
Si vous rencontrez des problèmes et finissez par ajouter plusieurs identifiants, vous pouvez les supprimer en allant à Manage Jenkins → Manage Users, et cliquer sur votre nom d'utilisateur. Maintenant, dans la barre latérale gauche, il y aura un élément de menu nommé Credentials. Depuis là, vous pouvez voir et éditer toutes les clés que Jenkins a stockées.
Envoi d'emails depuis Jenkins
Nous allons configurer Jenkins pour envoyer des emails automatisés quand quelque chose casse dans votre code. Pour que cela se produise, nous devons faire des changements dans le menu Manage Jenkins → Configure System.
La première chose à faire est d'entrer l'adresse d'expéditeur que Jenkins utilisera pour envoyer les emails automatisés. Trouvez le champ System Admin e-mail address sur la page de config, et entrez l'adresse que vous voudriez que Jenkins utilise comme expéditeur.
Note rapide : il est préférable d'entrer une adresse se terminant par le nom de domaine du serveur Jenkins. Cela minimise les chances que l'email finisse dans le dossier spam. Le serveur Jenkins n'a pas la permission d'envoyer des emails au nom d'autres domaines, mais la plupart des services email acceptent les adresses d'expéditeur avec le même domaine que le serveur d'envoi. En savoir plus dans cet article Wikipédia. Dans l'image ci-dessous, j'ai entré une adresse d'expéditeur se terminant par le même domaine que le serveur Jenkins.
Ensuite, nous devons donner à Jenkins un moyen d'envoyer des emails. La façon la plus directe est d'installer un serveur SMTP (mail) sur le VPS. Vous pouvez le faire en vous connectant et en exécutant les commandes suivantes :
yum -y install sendmail systemctl enable sendmail systemctl restart sendmail
Après avoir installé sendmail, retournez à la configuration système de Jenkins et entrez « localhost » dans le champ SMTP server, comme montré dans l'image ci-dessous.
À ce stade, vous pouvez aussi cocher la case pour permettre l'envoi aux utilisateurs non enregistrés. Cela signifie les utilisateurs qui n'ont pas de compte Jenkins. Plus tard, nous configurerons Jenkins pour envoyer un email à toute personne qui pousse du code défectueux vers GitHub. Jenkins récupérera l'adresse email du responsable depuis GitHub, mais cela ne marchera que si la personne a un compte Jenkins correspondant, ou si nous cocher cette case.
Enfin, vous pouvez tester la configuration, comme montré dans l'image ci-dessus. Après avoir appuyé sur Test configuration, le message « Email was successfully sent » devrait apparaître, et l'email devrait atteindre votre boîte de réception. Vérifiez votre dossier spam si vous ne recevez pas l'email dans les cinq minutes.
Installation de Xilinx Vivado en mode batch
J'utilise Xilinx Vivado pour simuler, compiler et implémenter le code dans cet exemple de projet. Le dispositif cible est le FPGA Xilinx Zynq-7000 sur la carte de développement ZebBoard. Dans cette section, je vais vous montrer comment installer Vivado sur le VPS en utilisant la licence gratuite WebPACK.
La première étape est de télécharger l'installeur unifié Xilinx : Linux Self Extracting Web Installer, montré dans l'image ci-dessous. Vous devrez vous connecter ou créer un nouveau compte Xilinx pour télécharger l'installeur.
Une fois le téléchargement terminé, vous devez le copier de votre ordinateur de bureau vers le serveur Jenkins. Si vous avez accès à un shell Linux sur votre bureau, je suggère d'utiliser la copie sécurisée de fichiers comme dans la commande suivante :
scp Xilinx_Unified_2019.2_1106_2127_Lin64.bin root@yourserver:~
Avant de pouvoir lancer l'installeur, vous devez installer quelques packages pour satisfaire les dépendances de Vivado. Exécutez les commandes suivantes pour cela :
yum -y install tar yum -y install java-11-openjdk-devel yum -y install ncurses-compat-libs yum -y install gcc
Ensuite, lancez l'installeur unifié Xilinx comme ceci :
./Xilinx_Unified_2019.2_1106_2127_Lin64.bin --keep --noexec --target Xil_installer
Le fichier .bin décompressera les fichiers d'installation dans un nouveau répertoire nommé Xil_installer. Si vous obtenez l'erreur ci-dessous, c'est parce que vous n'avez pas installé tar.
Verifying archive integrity... All good. Uncompressing Xilinx Installer Extraction failed. Terminated
L'installeur unifié Xilinx peut installer de nombreux outils Xilinx différents sur votre système. Nous devons donc lancer le fichier xsetup dans le répertoire Xil_installer pour spécifier quels logiciels nous voulons :
cd Xil_installer/ ./xsetup -b ConfigGen
Le script xsetup vous demande quels outils vous souhaitez. Entrez « 2 » pour Vivado, puis « 1 » pour Vivado HL WebPACK, comme montré dans la liste ci-dessous.
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
Pour installer l'édition Xilinx WebPACK, vous devez vous connecter à votre compte Xilinx pendant l'installation. Sur un ordinateur de bureau, l'interface graphique de l'installeur vous guide dans ce processus, mais sur le serveur, il n'y a pas d'interface graphique, donc nous devons nous authentifier en utilisant le script xsetup. Exécutez la commande suivante pour générer le token d'authentification :
./xsetup -b AuthTokenGen
J'ai dû lancer la commande plusieurs fois avant que ça marche. Au début, le script s'arrêtait avec l'erreur « Internet connection validated, can connect to internet. » Cependant, après quelques essais, j'ai réussi à me connecter. Le script demandera votre identifiant et mot de passe. C'est l'email et le mot de passe que vous avez utilisés pour télécharger l'installeur depuis xilinx.com.
Enfin, vous êtes prêt à installer Vivado en mode batch. En appelant le script de setup, vous devez spécifier le fichier de config d'installation pour que xsetup sache quels outils télécharger. Le fichier de config est dans le dossier .Xilinx dans le répertoire home de l'utilisateur root. Exécutez la commande suivante pour lancer l'installation en utilisant le fichier de config :
./xsetup -a XilinxEULA,3rdPartyEULA,WebTalkTerms \ -b Install -c ~/.Xilinx/install_config.txt
Le processus d'installation prendra beaucoup de temps. L'installation de Vivado utilise 24 Go d'espace. Tout cela est maintenant en téléchargement depuis le serveur Xilinx relativement lent. Pour moi, le téléchargement a pris un peu plus de deux heures.
Après la fin de l'installation, vous devriez tester que Vivado démarre correctement en mode batch. Xilinx fournit un script shell qui configure l'environnement pour vous. Avant de pouvoir lancer Vivado, vous devez utiliser la commande source pour charger le contenu du script dans votre shell actif :
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Ensuite, vous êtes prêt à lancer Vivado. Mais il n'y a pas d'environnement GUI installé sur votre serveur, donc nous devons le démarrer en mode batch avec cette commande :
vivado -mode batch -source test.tcl
Si Vivado démarre et quitte immédiatement sans afficher d'erreurs, c'est une indication que Vivado a tout ce qu'il faut, et vous êtes prêt à partir. Notez que si vous obtenez l'erreur ci-dessous, c'est parce que vous n'avez pas installé le package ncurses-compat-libs, comme nous en parlions au début de cette section.
application-specific initialization failed: couldn't load file "librdi_commontasks.so": libtinfo.so.5: cannot open shared object file: No such file or directory
Intégration de Vivado dans Jenkins
Pour préparer Jenkins à Vivado, nous devons faire quelques changements dans les paramètres généraux. Allez à Manage Jenkins → Configure System et vérifiez que tous les paramètres par défaut ont du sens pour vous.
Comme mentionné plus haut, Vivado utilise beaucoup de RAM. L'usage des ressources dépend de votre FPGA cible, et vous pouvez avoir une indication de combien vous en avez besoin depuis la page Recommandations Mémoire de Xilinx. Je recommande donc de changer le nombre par défaut de jobs parallèles qui peuvent tourner de 2 à 1. À moins que vous n'ayez alloué d'énormes ressources RAM sur votre VPS, vous voulez probablement régler # of executors à 1, comme montré dans l'image ci-dessous.
Au lieu de définir les variables d'environnement dans chaque job Jenkins, nous allons spécifier le PATH globalement pour tous les jobs. Cela facilite le passage à une version plus récente de Vivado à l'avenir. Vous pourrez alors faire référence à l'exécutable 'vivado' dans vos scripts, et il pointera toujours vers la dernière version, ou celle que vous décidez.
Descendez à la section Global properties et cochez Environment variables. Cliquez Add pour obtenir une nouvelle entrée. Assurez-vous d'inclure le PATH Linux standard aussi. J'ai utilisé « PATH=/tools/Xilinx/Vivado/2019.2/bin:/sbin:/usr/sbin:/bin:/usr/bin », comme montré dans l'image ci-dessous.
N'oubliez pas de descendre en bas de la page et de cliquer Save.
Projets Vivado GUI en mode batch
J'ai choisi de gérer les projets Vivado en mode GUI. Pour chaque dépôt, j'ai créé un nouveau projet depuis l'interface graphique Vivado habituelle, en ajoutant les fichiers sources, configurant les bibliothèques, etc. Cependant, les fichiers de projet .xpr sont binaires et dépendent de nombreux autres fichiers temporaires dans le répertoire du projet.
Les fichiers binaires ne conviennent pas aux SCM comme Git. Heureusement, Xilinx a pensé à cela et écrit une directive (XAPP1165) pour utiliser Vivado avec des systèmes de contrôle de version. Ce qu'on fait est d'utiliser la commande write_project_tcl dans Vivado pour exporter tout le projet en script Tcl. Le script contient du code Tcl lisible par l'homme, adapté à Git.
J'ai organisé tous les dépôts Git pour que tous les fichiers appartenant aux projets Vivado soient dans un sous-dossier nommé « vivado », tandis que les fichiers sources VHDL sont dans le répertoire parent. Consultez le projet demo packages sur mon GitHub pour voir ce que je veux dire. Pour chaque dépôt, nous mettrons les scripts Tcl Vivado dans le dossier vivado. Vous y trouverez aussi le fichier create_vivado_proj.tcl, qui est la version lisible du projet Vivado.
Pour créer le fichier create_vivado_proj.tcl, commencez par configurer le projet Vivado comme vous le souhaitez dans l'interface graphique Vivado. Assurez-vous que le projet Vivado réside dans un sous-dossier vivado. Quand vous êtes satisfait du projet, exportez-le en entrant les commandes suivantes dans la console Tcl Vivado :
cd [get_property DIRECTORY [current_project]] write_project_tcl -force -target_proj_dir . create_vivado_proj
Ajoutez le fichier create_vivado_proj.tcl à Git, et configurez le gitignore pour ignorer le reste du projet Vivado. Voici le contenu de mon fichier .gitignore qui ignore tout sauf les scripts Tcl dans le dossier vivado :
Ouverture du projet Vivado en mode batch
C'est une bonne idée de tester le projet Vivado manuellement sur le VPS avant de commencer à créer des jobs Jenkins. Par défaut, le daemon tourne sous un compte utilisateur nommé jenkins sur le serveur Linux. Vous devriez donc tester le projet Vivado en utilisant l'utilisateur jenkins.
Assurez-vous que Git est installé sur le serveur Linux avant de commencer cette expérience. Exécutez cette commande pour installer Git après vous être connecté en root :
yum -y install git
Vous ne pouvez pas vous connecter directement à l'utilisateur jenkins, mais vous pouvez basculer vers lui depuis l'utilisateur root comme ceci :
su - jenkins
Si vous lancez maintenant une commande pwd, vous verrez que vous êtes à /var/lib/jenkins :
[jenkins@jenkins ~]$ pwd /var/lib/jenkins
C'est parce que ce n'est pas un compte utilisateur régulier qui a son répertoire home sous /home, comme c'est la norme sur les systèmes Linux. C'est seulement pour faire tourner le daemon Jenkins, mais nous pouvons nous connecter pour effectuer une visite manuelle du processus de build dans l'environnement Jenkins.
Le dossier home est plein de toutes les données dynamiques comme les logs, les paramètres utilisateur, et les plugins que vous avez téléchargés. Quand nous lancerons plus tard des jobs dans l'interface Jenkins, ils apparaîtront dans le dossier jobs.
Allons dans le dossier jobs pour notre expérience :
cd /var/lib/jenkins/jobs/
Vous pouvez cloner votre dépôt Git directement dans le dossier jobs. Votre dépôt Git doit être accessible sans mot de passe. Soit parce qu'il est public, soit parce que vous avez configuré une connexion sans mot de passe comme décrit sur les pages d'aide GitHub.
Si vous n'avez pas de dépôt Git avec le projet Vivado prêt, n'hésitez pas à cloner l'un des miens comme ceci :
git clone https://github.com/jonasjj/Jenkins-demo-packages
Ensuite, cd dans le nouveau répertoire du dépôt Git, et plus loin dans le dossier vivado :
cd Jenkins-demo-packages/vivado/
Si vous avez téléchargé mon exemple, vous trouverez deux fichiers Tcl : create_vivado_proj.tcl et check_syntax.tcl. Le premier est le projet Vivado converti en fichier Tcl, et le second est un script dont nous n'avons pas encore parlé. Il sert à vérifier la syntaxe des fichiers VHDL dans le projet Vivado.
Avant de pouvoir lancer une commande Vivado, nous devons définir la variable d'environnement PATH dans le shell actuel. Dans Jenkins, nous avons résolu cela en utilisant Global properties, mais maintenant nous ne passons pas par Jenkins, donc nous devons sourcer le script de setup Xilinx comme ceci :
source /tools/Xilinx/Vivado/2019.2/settings64.sh
Maintenant que l'exécutable vivado est dans notre path, commençons par recréer le projet. Voici la commande pour le faire en mode batch Vivado :
vivado -mode batch -source create_vivado_proj.tcl
Après avoir appuyé sur Entrée, vous devriez voir beaucoup de code Tcl affiché dans la console. C'est le code pour recréer le projet Vivado qui s'exécute. Si vous ne voyez pas d'erreurs évidentes, tapez la commande « echo $? » dans le terminal avant de faire quoi que ce soit d'autre. La sortie devrait être 0 si tout s'est bien passé, comme on peut le voir dans la liste ci-dessous.
INFO: [Common 17-206] Exiting Vivado at Sun Apr 19 18:32:48 2020... [jenkins@jenkins vivado]$ echo $? 0
La commande « echo $? » vous montre le statut de sortie de la commande précédente que vous avez exécutée sous Linux. Un statut de sortie de 0 signifie que tout est OK, pas d'erreur. Tout autre statut de sortie que 0 indique une erreur. Ce sont de vieilles conventions Unix que vous pouvez lire ici. Quoi qu'il en soit, le statut de sortie est important pour Jenkins car c'est ainsi qu'il décide si une étape de job est un succès ou un échec.
Si vous faites maintenant un listing de répertoire, vous verrez que Vivado a recréé les fichiers binaires du projet :
[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
Essayons une autre expérience avec l'exécution de scripts Tcl en mode batch Vivado. Créez un script Tcl one-liner avec la commande suivante :
echo "exit 1" > test.tcl
Maintenant, lancez le script en mode batch Vivado :
vivado -mode batch -source test.tcl
Après la fermeture de Vivado, vérifiez à nouveau le code de sortie avec la commande « echo $? » :
[jenkins@jenkins vivado]# echo $? 1
C'est 1, ce qui signifie échec de sortie sous Unix. Si vous changez le contenu du script test.tcl à « exit 0 », et relancez Vivado une fois de plus, vous verrez que le statut de sortie est maintenant 0, indiquant le succès. Essayez !
Le mot-clé exit est du Tcl standard. Nous allons l'utiliser comme interface entre Vivado et Jenkins. Jenkins exécute quel que soit le script Tcl que nous créons dans Vivado, et regarde le statut de sortie pour décider s'il doit marquer l'étape du job comme succès ou échec.
N'oubliez pas de supprimer notre petit projet de test du dossier jobs quand vous êtes satisfait de l'expérience :
cd /var/lib/jenkins/jobs/ [jenkins@jenkins jobs]# rm -rf Jenkins-demo-packages
Script Tcl pour vérifier la syntaxe du code dans Vivado
Ce script Tcl exécute une vérification de syntaxe des fichiers VHDL dans le projet. Si vous allez simuler ou implémenter le code, vous n'aurez pas besoin de ce script car les erreurs de syntaxe casseront la compilation de toute façon. Mais pour mon projet packages, il n'a pas de sens de créer un testbench. Les fichiers ne contiennent que des déclarations de constantes et de types. Je veux quand même attraper les erreurs de code poussées vers ce repo, et c'est là que la vérification de syntaxe est utile.
Dans le script listé ci-dessous, nous commençons par ouvrir le fichier de projet. Ensuite, nous appelons la commande Vivado check_syntax » en lui demandant de sauvegarder la sortie dans une variable appelée msg. Après la fin de la vérification, nous regardons le message de sortie pour voir s'il y a des erreurs signalées. Si check_syntax a signalé quelque chose, nous mettons le statut de sortie à 1 (échec). S'il n'y a pas d'erreurs, nous sortons avec 0 (succès).
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 supporte tous les mots-clés Tcl standards, et il y a aussi beaucoup de commandes intégrées comme check_syntax. Je recommande de consulter ces deux documents Xilinx qui couvrent les capacités de script Tcl en détail :
- Vivado Design Suite Tcl Command Reference Guide (UG835)
- Vivado Design Suite User Guide Using Tcl Scripting (UG894)
Script Tcl pour simuler dans Vivado
Le prochain script que j'ai créé sert à lancer le testbench en mode batch. Pour que cela fonctionne, vous devez configurer les jeux de fichiers de simulation dans l'interface graphique Vivado avant d'exporter le projet en Tcl. Allez-y et recréez l'un des projets de simulation sur votre ordinateur de bureau en utilisant le script create_vivado_proj.tcl pour voir comment je l'ai configuré au préalable. Vous pouvez ouvrir les projets reconstruits dans l'interface graphique Vivado.
Comme vous pouvez le voir dans la liste ci-dessous, je commence par ouvrir le projet. Ensuite, je définis le nom du jeu de fichiers de simulation dans une variable (généralement sim_1). Après avoir lancé la simulation, nous devons aussi la fermer. Sinon, le statut de la simulation ne sera pas écrit dans les fichiers de log.
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]
J'ai eu du mal à trouver un bon moyen d'obtenir le statut de la simulation. Mes testbenchs VHDL se terminent sur un mot-clé VHDL finish en cas de succès. Les erreurs résultent en un échec d'assertion VHDL. Il n'y a pas de moyen évident de savoir pourquoi le simulateur s'est arrêté en utilisant des commandes Tcl dans Vivado.
Heureusement, Tcl est un langage de script puissant. Ma solution de contournement est d'ouvrir le log de simulation et de chercher la chaîne « Failure: », qui indique un échec d'assertion VHDL. Finalement, nous sortons 1 si le mot est dans le log, ou 0 s'il n'y est pas.
Script Tcl pour la synthèse dans Vivado
Dans le script Tcl pour la synthèse en mode batch Vivado, nous commençons par ouvrir le fichier de projet. Ensuite, nous assignons le nom du run à une variable. Vous devez avoir ajouté les fichiers de design au projet Vivado avant de l'exporter en Tcl. Si vous n'avez pas changé le nom du run de synthèse dans l'interface graphique, ce sera probablement « synth_1 ».
Vous devez définir la variable du nombre de CPU au nombre de processeurs logiques de votre serveur. Ce nombre contrôle le degré de multithreading que Vivado utilise. J'ai opté pour le VPS avec 4 CPU sur UpCloud, et j'ai donc mis le 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
La commande launch_runs est non-bloquante, ce qui signifie qu'elle se termine avant la synthèse réelle. Si nous essayons de lire le statut juste après avoir appelé launch_run, il sera « Running ». Pour mettre le script en pause jusqu'à la fin de la synthèse, nous appelons la commande wait_on_run.
Finalement, nous récupérons le statut du run et sortons 0 ou 1, selon le message de statut.
Script Tcl pour l'implémentation dans Vivado
Le script pour lancer Place and Route (PAR) en mode batch Vivado est similaire au script de synthèse. La différence est que le nom du run est maintenant « impl_1 », et que nous cherchons un autre message de succès.
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
Script Tcl pour générer le bitstream dans Vivado
Finalement, après si l'implémentation se termine avec succès, nous pouvons générer un bitstream pour programmer le FPGA. Le script est similaire au précédent, mais la commande launch_runs est légèrement différente. Et bien sûr, nous cherchons un statut différent à la fin.
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
Configuration des jobs Jenkins
Un job dans Jenkins fait référence à un ensemble de tâches logicielles groupées. Jenkins affiche les jobs et leur statut actuel comme des éléments listés sur la page de vue d'ensemble. Vous pouvez démarrer les jobs manuellement depuis l'interface web, ou ils peuvent être déclenchés automatiquement, par exemple quand quelqu'un pousse du code vers un repo, ou suite à la completion d'un autre job. Nous ferons les deux.
Jenkins offre plusieurs façons de gérer les jobs. La méthode traditionnelle est le Freestyle project, où vous spécifiez chaque action depuis l'interface web Jenkins. La façon plus moderne de gérer les jobs Jenkins est d'utiliser un script pipeline qui stocke toutes les informations sur le flux d'exécution. Les scripts pipeline ont l'avantage de pouvoir être ajoutés à votre SCM.
Pour créer un nouveau script pipeline, sélectionnez New item dans la barre latérale Jenkins. Dans la boîte de dialogue qui s'ouvre, sélectionnez l'option Pipeline et cliquez OK, comme montré dans l'image ci-dessous.
La première chose à faire dans la configuration du job est d'ajouter le dépôt GitHub qui contient le code source. Dans cet exemple, j'utilise le dépôt packages, mais la procédure est la même pour tous les autres jobs et dépôts. Cochez la case GitHub project et entrez l'adresse dans le champ Project url qui apparaît, comme montré dans l'image ci-dessous.
Après cela, nous pouvons configurer les déclencheurs de build pour ce job. Je veux que ce job démarre quand quelqu'un pousse du code vers le dépôt GitHub. Pour cela, nous cochons la case GitHub hook trigger for GITScm polling, comme montré dans l'image ci-dessous. Notez que cela ne marchera que si vous avez coché la case Manage hooks dans les paramètres globaux, comme nous l'avons fait plus tôt.
Au bas de la page de configuration du job se trouve la section Pipeline. Ici, vous avez l'option d'entrer le script pipeline directement dans la page de config. Mais nous voulons versionner le script pipeline. Donc nous choisissons l'option Pipeline script from SCM. Assurez-vous que Git est sélectionné, comme montré dans l'image ci-dessous.
Collez l'URL de votre dépôt GitHub, et sélectionnez vos identifiants si c'est un repo privé. Le nôtre est public, donc nous laisserons les identifiants vides. Nous irons aussi avec la sélection de branche master par défaut.
Finalement, nous devons sélectionner le chemin vers le script Jenkins dans le dépôt Git. J'ai créé un fichier nommé Jenkinsfile à la racine de chaque repo. N'oubliez pas de cliquer Save avant de quitter la page.
Scripts pipeline Jenkins
Les scripts pipeline suivent les mêmes règles de syntaxe que le langage de programmation Apache Groovy, que je dois avouer n'avoir jamais entendu parler avant. Néanmoins, vous n'aurez pas de mal à comprendre les scripts pipeline si vous avez fait n'importe quel type de programmation moderne. Au premier coup d'œil, ça ressemble à un schéma JSON sans les virgules séparant les éléments de données.
Les scripts sont assez polyvalents, et il y a beaucoup d'options pour des choses comme l'exécution d'étapes en parallèle ou l'exécution de tâches sur plusieurs serveurs Jenkins. Je suggère de jeter un œil à la documentation officielle Jenkins pipeline si vous voulez creuser la question.
Heureusement, vous n'avez pas besoin de tout savoir sur eux pour bénéficier des scripts pipeline. Nous utiliserons le format ci-dessous comme template pour tous vos scripts. Nous ajouterons autant d'étapes que nécessaire pour diviser le job en étapes logiques.
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'
}
}
}
Si quelqu'un pousse du code défectueux vers le repo, nous voulons que le responsable reçoive un email automatisé avec des infos sur le job échoué. Pour cela, nous utilisons une section failure dans une section post. Cette partie du script ne s'exécutera que si l'une des étapes échoue. Alors, le job s'arrêtera. Jenkins n'ira pas à l'étape suivante si l'une échoue. Au lieu de cela, il sautera dans la section failure. Jenkins récupère alors les adresses email des derniers commits Git et leur envoie un email avec un lien vers le build cassé.
Job de vérification syntaxe VHDL
Le seul repo dans notre design qui n'a pas de testbench est le repo packages — à la place, nous utilisons notre script check_syntax.tcl pour vérifier que le code est au moins du VHDL valide.
Dans la première étape de notre script pipeline, nous appelons deleteDir(). C'est une des commandes de base disponibles dans les scripts pipeline Jenkins. Elle nettoie le répertoire de travail en supprimant les restes des builds précédents.
À la ligne suivante, nous appelons git. Notez que ce n'est pas la commande Linux git, mais une commande référençant le plugin git Jenkins. Nous lui disons de cloner le dépôt dans l'espace de travail.
Finalement, à la troisième ligne de l'étape Create project, nous utilisons le mot-clé sh pour appeler une commande shell Linux. Ici, nous changeons vers le répertoire vivado et lançons le script create_vivado_proj.tcl en mode batch Vivado pour recréer le projet 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'
}
}
}
Dans la deuxième étape, nommée Check VHDL syntax, le projet Vivado existe déjà, donc nous pouvons passer directement à l'exécution de notre script Tcl. Nous utilisons à nouveau la commande shell pour lancer le fichier check_syntax.tcl, qui sortira 0 en cas de succès, ou 1 en cas d'erreur, ce qui fera marquer le build comme échec par Jenkins.
Jobs de simulation VHDL
Pour tous les autres jobs que le repo packages, la commande one-liner git ne marchera pas pour checker le code depuis GitHub. Le problème est que ces repos ont des dépendances sous forme de sous-modules. Les sous-modules référencent d'autres dépôts Git, que la simple commande git ne récupère pas par défaut. Mais ce n'est pas grave ; on peut corriger le problème en utilisant l'appel checkout plus polyvalent, aussi bien documenté sur la page du plugin 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'
}
}
}
Finalement, nous lançons le script run_simulation.tcl dans Vivado à l'étape suivante.
La liste ci-dessus montre le script utilisé dans le repo bcd_encoder. Des scripts identiques, seulement avec des URLs de repo différentes, sont utilisés pour les repos counter, digit_selector, output_mux, reset, et seg7_encoder également.
Job d'implémentation FPGA
Le repo seg7 contient le module principal de notre projet FPGA. Il intègre tous les autres repos comme sous-modules. Le script pipeline est similaire à celui utilisé pour les jobs de simulation seule, mais avec quatre étapes ajoutées : Run simulation, Run implementation, Generate bitstream, et Release bitfile.
Les deux premières étapes créent le projet et lancent la simulation. Je les ai déjà couvertes dans les sections précédentes de cet article. Les trois étapes suivantes fonctionnent de la même façon que l'étape de simulation, mais avec le script Tcl remplacé par ceux pertinents pour la tâche.
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'
}
}
}
L'étape finale du job d'implémentation s'appelle Release bitfile. Elle contient un script shell qui copie le fichier de programmation FPGA nouvellement généré vers un dossier de release. La commande shell renomme le fichier pour inclure le nom du projet et un horodatage.
Pour maintenir la traçabilité, nous générons aussi un fichier texte contenant le hash Git du repo principal (seg7) et de tous les sous-modules. Quand on travaille avec des sous-modules Git, il ne suffit pas de stocker le hash du repo principal. Pour générer un hash pour le repo principal qui inclut les changements dans tous les sous-modules, il faudrait commiter le repo principal après avoir pullé et mis à jour tous les sous-modules. Nous ne voulons pas faire cela automatiquement depuis Jenkins.
Notez qu'implémenter le FPGA à chaque push, comme je le fais dans l'exemple, n'est probablement pas ce que vous voulez pour un vrai projet Jenkins. Ça peut prendre des heures de construire un projet FPGA à grande échelle, et ça ne marcherait pas quand vous avez une équipe de développeurs qui poussent plusieurs fois par jour. Au lieu de builder après chaque push vers le repo, vous pouvez configurer Jenkins pour router le FPGA seulement une fois par jour. Par exemple, à minuit, comme montré par la capture d'écran ci-dessous depuis la page de configuration du job.
Déclencher les builds après la completion d'autres jobs
Notre projet d'exemple consiste en plusieurs dépôts Git, mais ils sont tous liés comme sous-modules Git. Excepté packages, tous les autres repos dépendent d'au moins un autre dépôt. La plupart dépendent du dépôt packages. Regardez le graphe de dépendances que j'ai présenté plus tôt dans cet article pour voir comment tout s'imbrique.
Donc, nous devrions déclencher les jobs non seulement par des pushes vers le repo en question, mais aussi après que l'un des sous-modules a été touché. Nous pouvons y parvenir dans Jenkins en visitant chaque job et en configurant l'option Build after other projects are built en conséquence.
L'image ci-dessous montre le déclencheur pour le projet bcd_encoder. Il démarrera après le repo packages, dont il dépend, complete un build avec succès.
Le module principal dépend de tous les autres repos. Je les ai ajoutés comme projets surveillés dans une liste séparée par des virgules, comme montré dans l'image ci-dessous. Notez que vous ne voudrez peut-être pas faire cela pour le job d'implémentation FPGA s'il prend beaucoup de temps à router, comme mentionné dans la section précédente.
Servir les bitfiles avec Nginx
Puisque nous avons déjà un serveur web en cours d'exécution, nous pouvons l'utiliser pour servir les fichiers de release via HTTP. Je veux que tous les nouveaux bitfiles apparaissent sur l'URL jenkins.vhdlwhiz.com/releases. Voyons comment utiliser Nginx pour cela.
Notre job d'implémentation copie déjà les nouveaux bitfiles vers un répertoire sur la racine HTML de Nginx, mais nous ne l'avons pas encore créé. Créez le répertoire de release et donnez les permissions d'écriture à l'utilisateur Jenkins en exécutant les commandes suivantes :
mkdir /usr/share/nginx/html/releases/ chown jenkins.root /usr/share/nginx/html/releases/
Ensuite, nous devons modifier le fichier /etc/nginx/nginx.conf. Trouvez la section server dans le fichier de config avec un nom égal à votre domaine. Ajoutez la section location suivante à l'intérieur, directement sous la section location racine ('/') :
location ^~ /releases {
alias /usr/share/nginx/html/releases/;
autoindex on;
}
Finalement, après avoir sauvegardé le fichier, testez le fichier de configuration, et rechargez le serveur Nginx :
nginx -t systemctl reload nginx
Si tout a fonctionné, vous devriez pouvoir lister le contenu du répertoire de release, comme montré dans la capture d'écran ci-dessous depuis Google Chrome.
Pour lier l'interface web Jenkins au répertoire de release, je veux créer un lien vers celui-ci depuis la barre latérale Jenkins. Nous avons déjà installé le plugin Sidebar Link qui permet des liens personnalisés dans la barre latérale.
L'étape suivante est d'aller à Manage Jenkins → Configure System et de descendre à la section Additional Sidebar Links. Ici, nous pouvons spécifier le nom et l'URL du nouveau lien, comme montré dans l'image ci-dessous. Le champ icône de lien est optionnel. J'ai réutilisé une des icônes qui venaient avec le serveur Jenkins.
Après avoir complété l'étape précédente, vous devriez maintenant avoir un lien personnalisé vers les releases de bitfiles dans la barre latérale, avec une belle icône de dossier, comme vous pouvez le voir sur l'image ci-dessous.
Résumé
Jenkins peut être un outil précieux aussi pour les équipes FPGA. L'automatisation des tâches peut faire gagner du temps à votre entreprise et améliorer la qualité de votre code. En utilisant des déclencheurs de build automatiques et des pipelines de jobs automatisés, moins d'erreurs de code passeront inaperçues.
Comme nous l'avons vu avec le projet d'exemple présenté dans cet article, Jenkins peut implémenter une suite complète de tests de régression pour votre code VHDL. Il montre la santé actuelle de votre projet dans une interface graphique web agréable, adaptée même au chef de projet le plus illettré en VHDL.
Si vous souhaitez essayer Jenkins pour le développement FPGA, je recommande de suivre les étapes de cet article sur une instance VPS UpCloud. J'ai minutieusement étudié tous les fournisseurs VPS il y a quelques années avant de déplacer VHDLwhiz sur un VPS. J'ai trouvé qu'UpCloud était l'alternative la plus rapide et la meilleure. Je suis toujours 100 % satisfait du service.
Si vous décidez d'ouvrir un compte sur UpCloud, je vous demande aimablement d'utiliser mon lien de parrainage ou mon code : NV78V6. Non seulement vous soutenez VHDLwhiz, mais vous obtenez aussi 25 $ de crédit sur UpCloud en utilisant le code promo.
VHDL
- VUnit 101 : Guide pratique pour la vérification VHDL automatisée
- Quiz VHDL Basics - Partie 4 : Vérifiez votre compréhension
- Qu'est-ce que le VHDL ? Guide pratique du langage de description matériel
- Maîtriser les boucles For en VHDL : guide pratique
- Quiz VHDL Avancé - Partie 2 : Testez votre expertise HDL
- Maîtriser les types Signé vs Non-signé en VHDL : insights pratiques
- Exploiter les records VHDL pour des interfaces FIFO propres et réutilisables
- Implémenter une FIFO AXI en RAM bloc avec handshake Ready/Valid
- Comment construire votre premier clignotant LED FPGA : Tutoriel pas à pas