<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[ju_hnny5]]></title><description><![CDATA[Le savoir n'a guère d'intérêt s'il n'est pas partagé.]]></description><link>https://blog.jbriault.fr/</link><image><url>https://blog.jbriault.fr/favicon.png</url><title>ju_hnny5</title><link>https://blog.jbriault.fr/</link></image><generator>Ghost 3.25</generator><lastBuildDate>Sun, 16 Nov 2025 17:52:10 GMT</lastBuildDate><atom:link href="https://blog.jbriault.fr/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[L'outil ultime pour vos salons ! 👀]]></title><description><![CDATA[<blockquote>Disclaimer : Ne vous attendez pas à un article ultra tech, là, l'idée est plus de vous partager une astuce.</blockquote><p>Il y a quelques temps, aux <a href="https://www.restosducoeur.org/">Restos du Coeur</a>, un collègue m'a demandé d'afficher des vidéos en boucle pour le forum des associations de <a href="https://www.chartres.fr/salon-des-associations">Chartres</a>. </p><p>La première chose qui m'est venue</p>]]></description><link>https://blog.jbriault.fr/loutil-parfait-pour-vos-salons/</link><guid isPermaLink="false">66dfb7a54df47200010880e2</guid><category><![CDATA[-divers-]]></category><category><![CDATA[~$linux]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Sun, 24 Nov 2024 10:34:44 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1528782322959-37d194f50b34?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDE0fHxmYWlyfGVufDB8fHx8MTczMjQ0NDQyOXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<blockquote>Disclaimer : Ne vous attendez pas à un article ultra tech, là, l'idée est plus de vous partager une astuce.</blockquote><img src="https://images.unsplash.com/photo-1528782322959-37d194f50b34?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDE0fHxmYWlyfGVufDB8fHx8MTczMjQ0NDQyOXww&ixlib=rb-4.0.3&q=80&w=2000" alt="L'outil ultime pour vos salons ! 👀"><p>Il y a quelques temps, aux <a href="https://www.restosducoeur.org/">Restos du Coeur</a>, un collègue m'a demandé d'afficher des vidéos en boucle pour le forum des associations de <a href="https://www.chartres.fr/salon-des-associations">Chartres</a>. </p><p>La première chose qui m'est venue en tête était de mettre un VLC sur un PC en plein écran en mode "<em>boucle</em>". 🤘</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/4Lyd8tJk410iI" width="480" height="269" style frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/loop-animal-drums-4Lyd8tJk410iI"></a></p><!--kg-card-end: html--><p>Sur le papier c'était OK, mais cette solution posée quelques problèmes :</p><ul><li>Pas super pratique pour les personnes ne travaillant pas dans l'informatique (dans l'associatif on a tous les niveaux) 😜</li><li> Cette solution prend pas mal de place</li><li>Elle est relativement honéreuse (car nécessite un pc à minima)</li><li>Il faut tout relancer manuellement à chaque coupure/réinstallation</li></ul><p>J'avais un Raspberry Pi sous la main, je me suis donc mis à la recherche d'une solution avant de vouloir réinventer la roue. 🙃</p><p>Mon besoin était simple, je veux que l'utilisateur n'ait qu'une clé usb à connecter avec ses vidéso et que ça tourne en boucle. Et là, bingo ! J'ai trouvé la solution.</p><p>Elle se nomme "<strong>Raspberry Pi Video Looper</strong>". Autant vous dire qu'avec un tel nom, je n'ai pas mis 15 ans à la trouver. 😍</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://videolooper.de/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Raspberry Pi Video Looper</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"></div></div></a></figure><p>Son fonctionnement est plutôt simple, vous devez récupérer l'image et l'installer sur une Carte SD/microSD de votre choix. Je ne vais pas vous expliquer comment flasher ici une carte, il y a une r<a href="https://www.framboise314.fr/creez-votre-carte-sd-pour-le-raspberry-pi-avec-raspberry-pi-imager/">ibambelle d'articles sur le sujet</a>. 🫡</p><p>Une fois que l'image est présente sur la carte et que cette dernière est installée, vous n'avez plus qu'à démarrer le Raspberry. Et là, encore une fois, magie, ce dernier vous demande d'insérer votre clé USB.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.jbriault.fr/content/images/2024/11/image.png" class="kg-image" alt="L'outil ultime pour vos salons ! 👀" srcset="https://blog.jbriault.fr/content/images/size/w600/2024/11/image.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2024/11/image.png 1000w, https://blog.jbriault.fr/content/images/2024/11/image.png 1074w" sizes="(min-width: 720px) 720px"><figcaption>Ecran de Video Looper attendant une clé USB.</figcaption></figure><p>Vidéo Looper va lire toutes les vidéos présentent sur le support, idéalement, faites une clé dédiée pour cet usage, enfin, c'est ce que je recommande. 😜</p><p>Voilà, maintenant, vous avez une solution qui charge et lit les vidéos en boucle de manière totalement fluide et sans effort/configuration.</p><p>La solution étant portable, elle peut être réutilisée sans à devoir repasser par de la configuration. Eteindre et rallumer fait refonctionner la chose automatiquement.</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2024/11/SCR-20241124-g0o-1-.jpeg" class="kg-image" alt="L'outil ultime pour vos salons ! 👀" srcset="https://blog.jbriault.fr/content/images/size/w600/2024/11/SCR-20241124-g0o-1-.jpeg 600w, https://blog.jbriault.fr/content/images/size/w1000/2024/11/SCR-20241124-g0o-1-.jpeg 1000w, https://blog.jbriault.fr/content/images/size/w1600/2024/11/SCR-20241124-g0o-1-.jpeg 1600w, https://blog.jbriault.fr/content/images/2024/11/SCR-20241124-g0o-1-.jpeg 1636w" sizes="(min-width: 720px) 720px"></figure><p>Magique ! 🥳</p>]]></content:encoded></item><item><title><![CDATA[2 deuxième Devoxx France, 2 talks ! 📺]]></title><description><![CDATA[<p>Cette année j'ai eu la chance et le privilège d'avoir été sélectionné pour 2 talks.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/L4Bb7zCaP8FB5C769T" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/thelonelyisland-wow-amazing-whoa-L4Bb7zCaP8FB5C769T"></a></p><!--kg-card-end: html--><p>Un premier sur VictoriaMetrics, une solution que j'apprécie tout particulièrement et qui vient donner un coup de neuf à Prometheus. 👀</p><p>Un très grand merci une nouvelle fois à l'organisation et au CFP pour m'avoir donné</p>]]></description><link>https://blog.jbriault.fr/devoxx-fr-2024/</link><guid isPermaLink="false">6637536b42c1010001483f6b</guid><category><![CDATA[conference]]></category><category><![CDATA[-divers-]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Sun, 05 May 2024 09:50:07 GMT</pubDate><media:content url="https://blog.jbriault.fr/content/images/2024/05/53686281662_0acb4b57f1_o.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jbriault.fr/content/images/2024/05/53686281662_0acb4b57f1_o.jpg" alt="2 deuxième Devoxx France, 2 talks ! 📺"><p>Cette année j'ai eu la chance et le privilège d'avoir été sélectionné pour 2 talks.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/L4Bb7zCaP8FB5C769T" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/thelonelyisland-wow-amazing-whoa-L4Bb7zCaP8FB5C769T"></a></p><!--kg-card-end: html--><p>Un premier sur VictoriaMetrics, une solution que j'apprécie tout particulièrement et qui vient donner un coup de neuf à Prometheus. 👀</p><p>Un très grand merci une nouvelle fois à l'organisation et au CFP pour m'avoir donné la chance de parler de solutions que j'affectionne et que j'utilise au quotidien (notamment dans un cadre associatif 🩷).</p><h3 id="observabilit-d-poussi-rer-prometheus-avec-victoriametrics-30-mn-">Observabilité : dépoussiérer Prometheus avec VictoriaMetrics (30 mn)</h3><p><strong>Asbtract :</strong></p><p><em>Prometheus s'est imposé comme un standard de facto dans nos infrastructures lorsque l'on souhaite faire de l'observabilité en collectant des métriques. Dans un contexte où l'on a besoin de se mettre rapidement à l'échelle (scalable), Prometheus commence à montrer ses faiblesses.</em></p><p><em>Prometheus ne possède pas de système de haute disponibilité de manière native, il faut obligatoirement passer par des solutions plus ou moins complexes comme Thanos ou Cortex. Ces solutions s'ajoutent à la lourdeur originelle de Prometheus.</em></p><p><em>VictoriaMetrics vient corriger tout cela en offrant une architecture micro-services où tout est découpé pour de meilleures performances et une meilleure disponibilité sans perte de données. <br>Ainsi je ferais un bref historique de l'observabilité, des solutions existantes, et du pourquoi complet de VictoriaMetrics, car il y en a beaucoup à dire sur cet outil prometteur !</em></p><p><em>Je vous ferais également un retour d'expérience sur l'utilisation de VictoriaMetrics Cluster aux Restos du Cœur et comment nous avons pu ainsi réduire les coûts en consommant plus de métriques qu'auparavant.</em></p><p><strong>Le replay 📺 :</strong></p><figure class="kg-card kg-embed-card"><iframe width="356" height="200" src="https://www.youtube.com/embed/bzLtWjUj2k0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="Observabilité : dépoussiérer Prometheus avec VictoriaMetrics"></iframe></figure><p><strong>Les slides 📄 :</strong></p><figure class="kg-card kg-embed-card"><iframe id="talk_frame_1172418" class="speakerdeck-iframe" src="//speakerdeck.com/player/c2ea193bef93499195b7e6960692ff7a" width="1280" height="720" style="aspect-ratio:1280/720; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe>
</figure><p>Pour le second talk, c'est la toute première fois que je donnais une université (3h - deep dive) avec les amis <a href="https://twitter.com/idriss_neumann">Idriss Neumann</a> et <a href="https://twitter.com/ElFamosoKwak">Alexis Fala</a>. Très certainement la première d'une longue série ! 💜 On a déjà quelques idées pour une prochaine université, on en reparlera sûrement très bientôt.</p><h3 id="pulumi-ou-comment-g-rer-votre-infrastructure-avec-votre-langage-pr-f-r-3h-">Pulumi, ou comment gérer votre infrastructure avec votre langage préféré (3h)</h3><p><strong>Abstract :</strong></p><p><em>N’avez-vous jamais rêvé de pouvoir gérer votre infrastructure avec votre langage de programmation préféré ? D'exposer vos scripts de provisionnement et déploiement d'infrastructure comme un véritable service web moderne et utilisable par le plus grand nombre ?</em></p><p><em>Vous connaissez certainement Terraform ; Pulumi se positionne comme une alternative sérieuse à cette solution extrêmement populaire dans le domaine de l'infrastructure en tant que code (IaC).</em></p><p><em>Dans cette université nous vous proposons de découvrir ce challenger en mettant en lumière ses points forts comme la programmation multi-langages, la possibilité de mieux tester son code, d'avoir une couche d'abstraction multi-cloud plus efficace et même la capacité de réaliser de véritables applications web modernes de déploiement ...</em></p><p><em>Venez découvrir Pulumi, l'essayer et qui sait ? Peut-être l'adopter !</em></p><p><strong>Le replay 📺 :</strong></p><figure class="kg-card kg-embed-card"><iframe width="356" height="200" src="https://www.youtube.com/embed/IAwu-WCN6Nw?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="Pulumi, ou comment gérer votre infrastructure avec votre langage préféré"></iframe></figure><p><strong>Les slides 📄 :</strong></p><figure class="kg-card kg-embed-card"><iframe id="talk_frame_1172570" class="speakerdeck-iframe" src="//speakerdeck.com/player/1228cbee5d0b4f6ebe82298fb0ad21ab" width="1280" height="720" style="aspect-ratio:1280/720; border:0; padding:0; margin:0; background:transparent;" frameborder="0" allowtransparency="true" allowfullscreen="allowfullscreen"></iframe>
</figure><p>On se retrouvera peut-être l'année prochaine, qui sait ! 😇</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/MDJ9IbxxvDUQM" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/cat-kisses-hugs-MDJ9IbxxvDUQM"></a></p><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Déployer l'agent Rudder sur Ubuntu avec Cloud-Init 😇]]></title><description><![CDATA[<p>Au quotidien, j'utilise Rudder pour maintenir une certaine cohérence dans la configuration de base appliquée sur mes différents serveurs et de reprendre la main sur les drifts de configuration qui peuvent être observés.</p><p>Cet article va être hyper rapide mais je souhaitais partager avec vous comment y arriver. 🙏</p><p>Pour des</p>]]></description><link>https://blog.jbriault.fr/deployer-rudder-sur-ubuntu-avec-cloud-init/</link><guid isPermaLink="false">65a681b742c1010001483f14</guid><category><![CDATA[>>devops<<]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Thu, 18 Jan 2024 16:00:21 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1567789884554-0b844b597180?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fGF1dG9tYXRpb258ZW58MHx8fHwxNzA1NTkyODk0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1567789884554-0b844b597180?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fGF1dG9tYXRpb258ZW58MHx8fHwxNzA1NTkyODk0fDA&ixlib=rb-4.0.3&q=80&w=2000" alt="Déployer l'agent Rudder sur Ubuntu avec Cloud-Init 😇"><p>Au quotidien, j'utilise Rudder pour maintenir une certaine cohérence dans la configuration de base appliquée sur mes différents serveurs et de reprendre la main sur les drifts de configuration qui peuvent être observés.</p><p>Cet article va être hyper rapide mais je souhaitais partager avec vous comment y arriver. 🙏</p><p>Pour des raisons de lisibilité, vous trouverez le fichier de configuration Cloud-Init ici :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://gist.github.com/juhnny5/44a4035cd9d7bed748678e93ef91541d"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Deploy Rudder Agent with Cloud-Init on Ubuntu Server 22.04</div><div class="kg-bookmark-description">Deploy Rudder Agent with Cloud-Init on Ubuntu Server 22.04 - rudder-agent-cloud-init</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Déployer l'agent Rudder sur Ubuntu avec Cloud-Init 😇"><span class="kg-bookmark-author">262588213843476</span><span class="kg-bookmark-publisher">Gist</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://github.githubassets.com/assets/gist-og-image-54fd7dc0713e.png" alt="Déployer l'agent Rudder sur Ubuntu avec Cloud-Init 😇"></div></a></figure><p>En complément, vous pouvez facilement accepter cette machine (qui arrive dans les "pending nodes") une fois l'agent exécuté via l'API. 😎</p><p>Pour y arriver, vous devez vous générer un token d'API puis :</p><pre><code class="language-bash"># Stocker le nom de la machine à accepter
RUDDER_AGENT_HOSTNAME="demo-rudder-cloud-init"

# Récupérer l'ID de la machine en question
NODE_ID=$(curl -sk -H "X-API-Token: xxxxxx" 'https://rudder.example.org/rudder/api/latest/nodes/pending?where=\[\{"objectType":"node","attribute":"OS","comparator":"eq","value":"Linux"\},\{"objectType":"node","attribute":"nodeHostname","comparator":"regex","value":"${RUDDER_AGENT_HOSTNAME}"\}\]' | jq '.data.nodes[0].id' | tr -d '"')

# L'accepter
curl -sk -H "X-API-Token: xxxxxxx" --request POST https://rudder.example.org/rudder/api/latest/nodes/pending/${NODE_ID} --data "status=accepted"</code></pre><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/3o84U6421OOWegpQhq" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/tipsyelves-rainbow-magic-3o84U6421OOWegpQhq"></a></p><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Split brain DNS sur macOS 🤯]]></title><description><![CDATA[<p>Cet article est là pour donner une astuce rapide si vous souhaitez éviter de commuter d'un résolveur DNS à un autre (lorsque vous changez d'environnement).</p><p>A noter qu'il également possible d'utiliser des outils comme Unbound localement sur votre poste, le but de cet article est de montrer comment le faire</p>]]></description><link>https://blog.jbriault.fr/split-dns/</link><guid isPermaLink="false">656ed7f242c1010001483e4e</guid><category><![CDATA[<--network-->]]></category><category><![CDATA[-macos-]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Tue, 05 Dec 2023 08:09:18 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1558494949-ef010cbdcc31?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fHNlcnZlcnxlbnwwfHx8fDE3MDE3NjM3Mzh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1558494949-ef010cbdcc31?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDF8fHNlcnZlcnxlbnwwfHx8fDE3MDE3NjM3Mzh8MA&ixlib=rb-4.0.3&q=80&w=2000" alt="Split brain DNS sur macOS 🤯"><p>Cet article est là pour donner une astuce rapide si vous souhaitez éviter de commuter d'un résolveur DNS à un autre (lorsque vous changez d'environnement).</p><p>A noter qu'il également possible d'utiliser des outils comme Unbound localement sur votre poste, le but de cet article est de montrer comment le faire directement avec les outils proposés par Apple. 😌</p><p>Apple macOS fournit l'outil <code>scutil</code> qui va nous permettre de modifier la configuration système.</p><p>Pour spécifier à votre système d'utiliser un résolveur spécifique pour un domaine donné, il faut utiliser la syntaxe suivante :</p><pre><code class="language-bash">sudo echo 'nameserver 10.0.0.1' &gt; /etc/resolver/example.org
sudo echo 'nameserver 10.0.0.2' &gt;&gt; /etc/resolver/example.org</code></pre><p>A noter que la commande <code>dig</code> ne prendra pas les résolveurs déclarés de cette sorte. Il faudra donc spécifier l'adresse du résolveur lors de la tentative de résolution. 😎</p><p>Exemple :</p><pre><code class="language-bash">dig @10.0.0.1 -t A example.org</code></pre><p>Sinon, vous pouvez utiliser l'outil directement fournit par Apple pour réaliser une résolution DNS : </p><pre><code>dscacheutil -q host -a name example.org</code></pre><p>Et voilà ! C'était ma petite astuce du jours. 🤓</p>]]></content:encoded></item><item><title><![CDATA[FreeBSD + Cloud-Init + Proxmox VE 🚀]]></title><description><![CDATA[<p>Cet article va être très rapide. Je voulais simplement vous partager commenter créer un template Proxmox VE de FreeBSD avec Cloud-init. 😁</p><p>Cet article vient en complément de celui-ci :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.jbriault.fr/pulumi-proxmox-cloudinit/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Pulumi + Proxmox VE + Cloud-Init = ❤️</div><div class="kg-bookmark-description">&gt; Cet article sera très certainement le premier d’une longue série sur ce sujet.
Il est là</div></div></a></figure>]]></description><link>https://blog.jbriault.fr/freebsd-cloud-init/</link><guid isPermaLink="false">64edb8ae0aee100001d9fe59</guid><category><![CDATA[>>devops<<]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Tue, 29 Aug 2023 09:41:28 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1640552435845-d65c23b75934?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDQ0fHxsaW51eHxlbnwwfHx8fDE2OTMyMzgyNTF8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1640552435845-d65c23b75934?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDQ0fHxsaW51eHxlbnwwfHx8fDE2OTMyMzgyNTF8MA&ixlib=rb-4.0.3&q=80&w=2000" alt="FreeBSD + Cloud-Init + Proxmox VE 🚀"><p>Cet article va être très rapide. Je voulais simplement vous partager commenter créer un template Proxmox VE de FreeBSD avec Cloud-init. 😁</p><p>Cet article vient en complément de celui-ci :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.jbriault.fr/pulumi-proxmox-cloudinit/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Pulumi + Proxmox VE + Cloud-Init = ❤️</div><div class="kg-bookmark-description">&gt; Cet article sera très certainement le premier d’une longue série sur ce sujet.
Il est là pour vous donner un premier exemple concret.
Bon, il y a de très fortes chances que vous soyez tombés dessus, mais il y a peu
de temps, Hashicorp annoncé le passage à la licence BSL (Business Source
License) […</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.jbriault.fr/favicon.png" alt="FreeBSD + Cloud-Init + Proxmox VE 🚀"><span class="kg-bookmark-author">Julien Briault</span><span class="kg-bookmark-publisher">ju_hnny5</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1535378620166-273708d44e4c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI1fHxyb2JvdHxlbnwwfHx8fDE2OTIzMDI1OTl8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="FreeBSD + Cloud-Init + Proxmox VE 🚀"></div></a></figure><p>A noter que cette procédure fonctionne pour toutes les images disponibles ici :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://bsd-cloud-image.org/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">A collection of prebuilt BSD cloud images</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Mark Otto, Jacob Thornton, and Bootstrap contributors</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://bsd-cloud-image.org/icons/freebsd.svg" alt="FreeBSD + Cloud-Init + Proxmox VE 🚀"></div></a></figure><p>Voici l'ensemble des commandes à utiliser pour y arriver :</p><pre><code class="language-bash">cd /tmp
wget https://object-storage.public.mtl1.vexxhost.net/swift/v1/1dbafeefbd4f4c80864414a441e72dd2/bsd-cloud-image.org/images/freebsd/13.2/2023-04-21/zfs/freebsd-13.2-zfs-2023-04-21.qcow2

qm create 9001 --name freebsd132-cloudinit-template --memory 1024 --net0 virtio,bridge=vmbr0

qm importdisk 9001 freebsd-13.2-zfs-2023-04-21.qcow2 local-lvm
qm set 9001 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9001-disk-0
qm set 9001 --ide2 local-lvm:cloudinit
qm set 9001 --boot c --bootdisk scsi0
qm set 9001 --ide2 local-lvm:cloudinit
qm set 9001 --serial0 socket --vga serial0
qm template 9001</code></pre><p>Ainsi, à la toute fin, vous aurez votre template disponible avec l'id <code>9001</code>.</p>]]></content:encoded></item><item><title><![CDATA[Utiliser le Pulumi Terraform Bridge - Partie 1 😍]]></title><description><![CDATA[<p>L'infrastructure en tant que code (IaC) a transformé la gestion informatique, et Terraform d'HashiCorp a été un pilier dans ce domaine. </p><p>Mais que se passerait-il si vous pouviez combiner la puissance des providers de Terraform avec la flexibilité des langages de programmation populaires comme <strong>Python</strong> et <strong>JavaScript</strong> ?</p><p>C'est précisément ce</p>]]></description><link>https://blog.jbriault.fr/pulumi-terraform-bridge/</link><guid isPermaLink="false">64e864d80aee100001d9fd5f</guid><category><![CDATA[<dev/>]]></category><category><![CDATA[>>devops<<]]></category><category><![CDATA[~$linux]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Sat, 26 Aug 2023 12:24:11 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1692513873777-40ec199fc071?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8YWxsfDJ8fHx8fHwyfHwxNjkzMDQ2NTczfA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1692513873777-40ec199fc071?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8YWxsfDJ8fHx8fHwyfHwxNjkzMDQ2NTczfA&ixlib=rb-4.0.3&q=80&w=2000" alt="Utiliser le Pulumi Terraform Bridge - Partie 1 😍"><p>L'infrastructure en tant que code (IaC) a transformé la gestion informatique, et Terraform d'HashiCorp a été un pilier dans ce domaine. </p><p>Mais que se passerait-il si vous pouviez combiner la puissance des providers de Terraform avec la flexibilité des langages de programmation populaires comme <strong>Python</strong> et <strong>JavaScript</strong> ?</p><p>C'est précisément ce que propose <strong>Pulumi</strong> et le <a href="https://github.com/pulumi/pulumi-terraform-bridge">Pulumi Terraform Bridge</a>. 🙏</p><p>Vous avez été relativement nombreux/ses à vouloir un article sur ce sujet, c'est maintenant chose faite.</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/08/image-3.png" class="kg-image" alt="Utiliser le Pulumi Terraform Bridge - Partie 1 😍"></figure><p> Avant de commencer, je souhaiterais préciser qu'il vous faudra quelques connaissances en Go pour y arriver sans trop de difficulté. 🫡</p><p>C'est parti, allons-y !</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/RrVzUOXldFe8M" width="480" height="360" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/excited-yes-nicolas-cage-RrVzUOXldFe8M"></a></p><!--kg-card-end: html--><h3 id="r-cup-ration-des-pr-requis-">Récupération des prérequis 😄</h3><p>Vous devez, avant de commencer avoir en votre possession :</p><ul><li>GNU Make (pour le Makefile)</li><li>Golang (vers 1.18 ou supérieur)</li><li>Goreleaser</li><li>Git (obviously).</li></ul><p>Et le "Terraform Bridge Provider Boilerplate" : <a href="https://github.com/pulumi/pulumi-tf-provider-boilerplate">https://github.com/pulumi/pulumi-tf-provider-boilerplate</a></p><p>Ce projet doit être forké chez vous, en respectant le format suivant :</p><pre><code>pulumi-&lt;provider_name&gt;</code></pre><p>Ce qui donne par exemple :</p><pre><code>pulumi-maas</code></pre><p>Ni plus, ni moins ! Ne reste plus qu'à cloner le repo chez vous :</p><pre><code class="language-bash">git clone https://github.com/juhnny5/pulumi-maas.git
cd pulumi-maas/</code></pre><h3 id="initialiser-le-repo">Initialiser le repo</h3><p>Le boilerplate, comme son nom l'indique fournit une base qu'il va falloir un peu adapter par rapport à notre provider à créer.</p><p>Pour ce faire, nous allons utiliser la commande suivante :</p><pre><code class="language-bash">make prepare NAME=maas REPOSITORY=github.com/juhnny5/pulumi-maas</code></pre><p>Cette commande va venir modifier les différents fichiers nécessaires au build et à la transformation, notamment le <code>go.mod</code> par exemple.</p><p>Elle va également générer les ressources qui vont nous être utiles par la suite :</p><ul><li><code>provider/cmd/pulumi-resource-maas</code></li><li><code>provider/cmd/pulumi-tfgen-maas</code></li><li><code>provider/resources.go</code></li></ul><p>Cette commande modifie pas mal de choses, mais, dans mon cas, je vais chercher à convertir un provider qui n'est pas dans le repo officiel de Terraform. En effet, le provider de MaaS est sur le repo de l'orga du même nom, à savoir :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/maas/terraform-provider-maas"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - maas/terraform-provider-maas: Terraform MAAS provider</div><div class="kg-bookmark-description">Terraform MAAS provider. Contribute to maas/terraform-provider-maas development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Utiliser le Pulumi Terraform Bridge - Partie 1 😍"><span class="kg-bookmark-author">maas</span><span class="kg-bookmark-publisher">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/e5f282417aa7d950b06346f902f20e11b37184aab9201062eac2c10377413acf/maas/terraform-provider-maas" alt="Utiliser le Pulumi Terraform Bridge - Partie 1 😍"></div></a></figure><p>Ainsi, dans le fichier <code>Makefile</code>, il me suffira de modifier les variables de cette sorte : </p><pre><code>PROJECT_NAME := maas Package

SHELL            := /bin/bash
PACK             := maas
ORG              := juhnny5
PROJECT          := github.com/${ORG}/pulumi-${PACK}
NODE_MODULE_NAME := @juhnny5/${PACK}
TF_NAME          := ${PACK}
PROVIDER_PATH    := provider
VERSION_PATH     := ${PROVIDER_PATH}/pkg/version.Version

TFGEN           := pulumi-tfgen-${PACK}
PROVIDER        := pulumi-resource-${PACK}
VERSION         := $(shell pulumictl get version)

TESTPARALLELISM := 4

WORKING_DIR     := $(shell pwd)

OS := $(shell uname)
EMPTY_TO_AVOID_SED := ""
</code></pre><p>Dans mon exemple, j'utilise un provider Terraform en source qui est un peu particulier. En effet, si on regarde le <code>go.mod</code> du projet, celui-ci, on se rend compte que le nom du projet n'est pas le FQDN du projet sur GitHub mais simplement le nom du repo.</p><pre><code>module terraform-provider-maas

go 1.19

require (
	github.com/bflad/tfproviderlint v0.28.1
	github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
	github.com/hashicorp/terraform-plugin-docs v0.16.0
	github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0
	github.com/maas/gomaasclient v0.0.0-20230512141257-d73401ee0dc8
	github.com/stretchr/testify v1.8.4
)</code></pre><p>Ainsi, côté boilerplate, il faudra modifier notre <code>go.mod</code> également pour que nous puissions utiliser cette lib en entrée. Ainsi donc :</p><pre><code>vi provider/go.mod</code></pre><p>On va remplacer le nom en spécifiant la version souhaitée. 🙃</p><pre><code>module github.com/juhnny5/pulumi-maas/provider

go 1.19

replace (
	github.com/hashicorp/terraform-plugin-sdk/v2 =&gt; github.com/pulumi/terraform-plugin-sdk/v2 v2.0.0-20230710100801-03a71d0fca3d
	terraform-provider-maas v1.2.0 =&gt; github.com/maas/terraform-provider-maas v1.2.0
)

require (
	github.com/pulumi/pulumi-terraform-bridge/v3 v3.57.0
	github.com/pulumi/pulumi/sdk/v3 v3.76.1
	terraform-provider-maas v1.2.0
)</code></pre><p>Ainsi, nous pourrons utiliser le nom <code>terraform-provider-maas</code> dans notre code. A noter que cette subtilité n'est pas toujours présente, cette manipulation est à réaliser dans le cas ou le provider source ne spécifie pas le FQDN Github dans son <code>go.mod</code>.</p><p>Maintenant, il suffit de rajouter la dépendance vers ce provider Terraform dans notre fichier de resources. 🫡</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/xoHntNXFYkfzGAftEv" width="480" height="480" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/WBPictures-movie-sunglasses-barbie-xoHntNXFYkfzGAftEv"></a></p><!--kg-card-end: html--><p>Pour ce faire :</p><pre><code>vi provider/resources.go</code></pre><p>Et y ajouter <code>terraform-provider-maas/maas</code>, de cette sorte :</p><pre><code class="language-Go">package maas

import (
	"fmt"
	"path/filepath"

	"terraform-provider-maas/maas"

	"github.com/juhnny5/pulumi-maas/provider/pkg/version"
	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
	"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/tokens"
	shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
	shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
	"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
)</code></pre><h3 id="un-coup-de-tfgen-">Un coup de tfgen 🥸</h3><p>Pour continuer, il faut lancer la commande :</p><pre><code class="language-bash">make tfgen</code></pre><h3 id="modifier-les-infos-du-futur-provider-pulumi-">Modifier les infos du futur provider Pulumi 👀</h3><p>Par défaut, lorsque vous avez fait initialisé le projet, le fichier <code>resources.go</code> a ajouté plusieurs infos concernant le projet.  😋</p><p>Nous allons y modifier d'autres infos avant de générer les SDKs. Le nom du <code>Publisher</code> :</p><figure class="kg-card kg-code-card"><pre><code class="language-Go">	prov := tfbridge.ProviderInfo{
		P:    p,
		Name: "maas",
		// DisplayName is a way to be able to change the casing of the provider
		// name when being displayed on the Pulumi registry
		DisplayName: "MAAS",
		// The default publisher for all packages is Pulumi.
		// Change this to your personal name (or a company name) that you
		// would like to be shown in the Pulumi Registry if this package is published
		// there.
		Publisher: "Julien Briault",</code></pre><figcaption>provider/resources.go</figcaption></figure><p>Mais également la description et l'org Github si celle-ci n'a pas été correctement modifiée.</p><pre><code class="language-Go">Description:       "A Pulumi package for creating and managing Canonical Metal-As-A-Service (MAAS) resources.",
GitHubOrg: "juhnny5",
Repository: "https://github.com/juhnny5/pulumi-maas",
Keywords:   []string{"pulumi", "maas", "category/cloud"},</code></pre><p>Ensuite, nous allons spécifier la configuration de chaque SDK à générer. Quand je parle de chaque SDK, j'entends par chaque langage de programmation à supporter par votre provider. 😈</p><p>Ainsi, vous pouvez obtenir ce résultat :</p><pre><code class="language-Go">		JavaScript: &amp;tfbridge.JavaScriptInfo{
			// List any npm dependencies and their versions
			Dependencies: map[string]string{
				"@pulumi/pulumi": "^3.0.0",
			},
			DevDependencies: map[string]string{
				"@types/node": "^10.0.0", // so we can access strongly typed node definitions.
				"@types/mime": "^2.0.0",
			},
			// See the documentation for tfbridge.OverlayInfo for how to lay out this
			// section, or refer to the AWS provider. Delete this section if there are
			// no overlay files.
			//Overlay: &amp;tfbridge.OverlayInfo{},
		},
		Python: &amp;tfbridge.PythonInfo{
			// List any Python dependencies and their version ranges
			PackageName: "pulumi-maas",
			Requires: map[string]string{
				"pulumi": "&gt;=3.0.0,&lt;4.0.0",
			},
		},
		Golang: &amp;tfbridge.GolangInfo{
			ImportBasePath: filepath.Join(
				fmt.Sprintf("github.com/juhnny5/pulumi-%[1]s/sdk/", mainPkg),
				tfbridge.GetModuleMajorVersion(version.Version),
				"go",
				mainPkg,
			),
			GenerateResourceContainerTypes: true,
		},
		CSharp: &amp;tfbridge.CSharpInfo{
			PackageReferences: map[string]string{
				"Pulumi": "3.*",
			},
		},</code></pre><h3 id="g-n-rer-le-code-">Générer le code ! ☺️</h3><p>Maintenant que l'on est tout bon sur les dépendances et dans l'initialisation du projet, nous allons pouvoir transformer notre code Terraform en code Pulumi et générer les SDKs appropriés. 😄</p><pre><code class="language-bash">make build_sdks</code></pre><p>Vous retrouverez automatiquement le code des différents SDKS dans <code>sdk/</code>.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/8DUxtTxFntY7lpJnzy" width="480" height="480" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/HBOMax-hbomax-satcthemovie-sex-and-the-city-movie-8DUxtTxFntY7lpJnzy"></a></p><!--kg-card-end: html--><p>Une fois que c'est fait, il ne reste plus qu'à release votre code sur Github, je ne vais pas expliquer comment fonctionne Goreleaser ici, par contre, je vous invite à créer votre fichier de cette sorte :</p><figure class="kg-card kg-code-card"><pre><code class="language-yaml">archives:
  - id: archive
    name_template: '{{ .Binary }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}'
before:
  hooks:
    - make tfgen
builds:
  - binary: pulumi-resource-maas
    dir: provider
    env:
      - CGO_ENABLED=0
    goarch:
      - amd64
      - arm64
    goos:
      - darwin
      - windows
      - linux
    ldflags:
      # The line below MUST align with the module in current provider/go.mod
      - -X github.com/juhnny5/pulumi-maas/provider/pkg/version.Version={{.Tag }}
    main: ./cmd/pulumi-resource-maas/
changelog:
  skip: true
release:
  disable: false
  prerelease: auto
snapshot:
  name_template: '{{ .Tag }}-SNAPSHOT'</code></pre><figcaption>.goreleaser.yml</figcaption></figure><p>A noter que vous trouverez un exemple dans le dossier <code>deploymen-templates/</code>. Vous y trouverez également le README expliquant comment release votre projet.</p><p>Pour terminer, vous trouverez tout le code disponible ici si vous souhaitez un exemple concret :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/juhnny5/pulumi-maas"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - juhnny5/pulumi-maas</div><div class="kg-bookmark-description">Contribute to juhnny5/pulumi-maas development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Utiliser le Pulumi Terraform Bridge - Partie 1 😍"><span class="kg-bookmark-author">juhnny5</span><span class="kg-bookmark-publisher">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/e0a2355910f01e00d6e68518f62a6aedac993db839cf6a7c43bbe8d648472253/juhnny5/pulumi-maas" alt="Utiliser le Pulumi Terraform Bridge - Partie 1 😍"></div></a></figure><p>Vous l'aurez compris, plus d'excuse pour ne pas migrer vers Pulumi. Le prochain article traitera de comment publier ces différentes ressources (sdks). 🤭</p>]]></content:encoded></item><item><title><![CDATA[Pulumi + Proxmox VE + Cloud-Init = ❤️]]></title><description><![CDATA[<blockquote>Cet article sera très certainement le premier d'une longue série sur ce sujet. Il est là pour vous donner un premier exemple concret.</blockquote><p>Bon, il y a de très fortes chances que vous soyez tombés dessus, mais il y a peu de temps, Hashicorp annoncé le passage à la licence</p>]]></description><link>https://blog.jbriault.fr/pulumi-proxmox-cloudinit/</link><guid isPermaLink="false">64de7d020aee100001d9fc12</guid><category><![CDATA[<dev/>]]></category><category><![CDATA[>>devops<<]]></category><category><![CDATA[CLI<3]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Fri, 18 Aug 2023 10:03:46 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1535378620166-273708d44e4c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI1fHxyb2JvdHxlbnwwfHx8fDE2OTIzMDI1OTl8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<blockquote>Cet article sera très certainement le premier d'une longue série sur ce sujet. Il est là pour vous donner un premier exemple concret.</blockquote><img src="https://images.unsplash.com/photo-1535378620166-273708d44e4c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDI1fHxyb2JvdHxlbnwwfHx8fDE2OTIzMDI1OTl8MA&ixlib=rb-4.0.3&q=80&w=2000" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"><p>Bon, il y a de très fortes chances que vous soyez tombés dessus, mais il y a peu de temps, Hashicorp annoncé le passage à la licence <a href="https://www.hashicorp.com/bsl">BSL (Business Source License)</a> pour leur projet Terraform. 💩</p><p>Je vous conseil d'ailleurs d'aller consulter le site du collègue et ami Denis aka <strong>Zwindler</strong>, qui a écrit <a href="https://blog.zwindler.fr/2023/08/16/d-open-source-a-bullshit-licence-bsl/">un billet</a> sur le sujet.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.zwindler.fr/2023/08/16/d-open-source-a-bullshit-licence-bsl/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">D open source à BullShit Licence (BSL)</div><div class="kg-bookmark-description">Résumé des épisodes précédents Il y a à peine un mois, j&amp;rsquo;écrivais mon billet d&amp;rsquo;humeur annuel sur une boite, championne de l&amp;rsquo;open source (RHEL), qui utilise une faille de la licence GPL pour gratter un peu de thune en fermant ses sources aux &amp;ldquo;rebuilders&amp;rdquo; (je parle évidem…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://blog.zwindler.fr/misc/nyanonymous_rond.png" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"><span class="kg-bookmark-publisher">Zwindler's Reflection</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://blog.zwindler.fr/2023/08/28c1d418-5dd4-43c2-8345-4f4ce34f9ff2.png" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"></div></a></figure><p>De mon côté, j'utilise <strong>Pulumi</strong> depuis un bon moment à titre personnel, j'ai d'ailleurs préparé un talk sur ce sujet pour expliquer son fonctionnement. Ce talk arrivera dès la rentrée. 😊</p><p>Dans cet article, je vais simplement vous partager un usage simple pour commencer.</p><h3 id="contexte-">Contexte 😬</h3><p>J'utilise Proxmox VE à la maison pour réaliser des PoCs. Proxmox VE (ou pve) possède une API qui permet d'intéragir avec celui-ci. Pour des raisons de simplicité, j'ai passé un peu de temps à déporter la création de vms dans un fichier YAML dédié.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/l0IybQ6l8nfKjxQv6" width="480" height="400" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/reactionseditor-reaction-l0IybQ6l8nfKjxQv6"></a></p><!--kg-card-end: html--><h3 id="cr-ation-du-premier-projet-">Création du premier projet 😎</h3><p>Pour une question de simplicité, ici je vais créer un projet Python pour la compréhension d'un plus grand nombre. A noter que le gros avantage de Pulumi est de pouvoir utiliser son langage de prédilection (dans la limite de ceux supportés).</p><pre><code class="language-bash">mkdir -p pulumi-proxmox
cd pulumi-proxmox/
pulumi new python --name pulumi-proxmox --stack dev --description "Pulumi with Proxmox VE" --force
pip install pulumi-proxmoxve
pulumi stack init dev</code></pre><p>Maintenant que notre projet est intialisé, nous allons attaquer la configuration de l'utilisateur Pulumi sur Proxmox VE pour que l'outil du même nom puisse intérragir avec l'API de Proxmox VE. 😊</p><p>Il est important de souligner que par défaut, Pulumi stock le <em>state</em> sur sa plateforme. Il est possible de le garder localement ou de l'envoyer dans du stockage objet (type S3).</p><h3 id="configuration-de-l-utilisateur-pulumi-sur-proxmox-ve">Configuration de l'utilisateur Pulumi sur Proxmox VE</h3><p>Il faut commencer par créer le role Pulumi avec les bons droits :</p><pre><code class="language-bash">pveum role add Pulumi -privs "VM.Allocate VM.Clone VM.Config.CDROM VM.Config.CPU VM.Config.Cloudinit VM.Config.Disk VM.Config.HWType VM.Config.Memory VM.Config.Network VM.Config.Options VM.Monitor VM.Audit VM.PowerMgmt Datastore.AllocateSpace Datastore.Audit"</code></pre><p>Ensuite, ajouter l'utilisateur :</p><pre><code class="language-bash">pveum user add pulumi@pve -password &lt;password&gt; -comment "Pulumi account"</code></pre><p>Spécifier le rôle que doit utiliser l'utilisateur <code>pulumi@pve</code> :</p><pre><code class="language-bash">pveum aclmod / -user pulumi@pve -role Pulumi</code></pre><p>Créer un token :</p><pre><code class="language-bash">pveum user token add pulumi@pve pulumi -expire 0 -privsep 0 -comment "Pulumi token"</code></pre><p>Ne reste plus qu'à tester que celui-ci fonctionne ! ☺️</p><pre><code class="language-bash">curl -X GET 'https://mox.homelab.lan:8006/api2/json/nodes' -H 'Authorization: PVEAPIToken=pulumi@pve!pulumi=xxxxxxxxxxxxxxx'</code></pre><p>Ok, maintenant que la configuration de l'utilisateur Pulumi est faite côté Proxmox VE, nous allons créer le template Ubuntu Server 22.04 via la`cloudimg` qui supporte l'utilisation de cloud-init.</p><p>D'ailleurs, si vous ne connaissez pas <code>cloud-init</code>, je vous conseil de lire cette introduction (en Français) :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.grottedubarbu.fr/introduction-cloud-init/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Introduction à Cloud-init</div><div class="kg-bookmark-description">Lors de précédents articles, nous avons vu comment installer et déployer des applications à l’aide de Docker, et de cloud providers.
Faut-il que je réalise mon installation de Docker à chaque création d’instance ? Comment garantir une homogénéité dans mes installations ? Gagner du temps ?</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.grottedubarbu.fr/favicon.png" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"><span class="kg-bookmark-author">Loïc FACHE</span><span class="kg-bookmark-publisher">La Grotte du Barbu</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.grottedubarbu.fr/content/images/2020/06/dallas-reedy-F2HTC_CF4Jo-unsplash.jpg" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"></div></a></figure><h3 id="cr-ation-du-template-">Création du template 🥸</h3><p>Pour ce faire on va récupérer l'image sur le site de Canonical et installer les dépendances. 😁</p><pre><code>cd /tmp
wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img

apt update -y &amp;&amp; apt install libguestfs-tools -y</code></pre><p>On va ensuite installer le paquet <code>qemu-guest-agent</code>, ajouter notre premier utilisateur (ici <code>jbriault</code>), créer le path et injecter la clé SSH. On termine par définir les bons droits.</p><pre><code>virt-customize -a jammy-server-cloudimg-amd64.img --install qemu-guest-agent

virt-customize -a jammy-server-cloudimg-amd64.img --run-command 'useradd jbriault'

virt-customize -a jammy-server-cloudimg-amd64.img --run-command 'mkdir -p /home/jbriault/.ssh'

virt-customize -a jammy-server-cloudimg-amd64.img --ssh-inject jbriault:file:/home/jbriault/.ssh/id_rsa.pub

virt-customize -a jammy-server-cloudimg-amd64.img --run-command 'chown -R jbriault: /home/jbriault'</code></pre><p>Maintenant, on rentre dans le dur et on créé le template qui aura pour id <code>9000</code>. 🚀</p><pre><code class="language-bash">qm create 9000 --name "ubuntu-2204-cloudinit-template" --memory 2048 --cores 2 --net0 virtio,bridge=vmbr0
qm importdisk 9000 jammy-server-cloudimg-amd64.img local-lvm
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-lvm:vm-9000-disk-0
qm set 9000 --boot c --bootdisk scsi0
qm set 9000 --ide2 local-lvm:cloudinit
qm set 9000 --serial0 socket --vga serial0
qm set 9000 --agent enabled=1

qm template 9000</code></pre><p>Vous devriez voir sur Proxmox VE:</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/08/image-2.png" class="kg-image" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"></figure><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/b8RfbQFaOs1rO10ren" width="480" height="400" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/theoffice-b8RfbQFaOs1rO10ren"></a></p><!--kg-card-end: html--><p>Maintenant, pour une question de simplification (dans cette première version du projet), j'ai fait en sorte de pouvoir déclarer ses vms au format <strong>YAML</strong>. ☺️</p><p>Voici un exemple :</p><figure class="kg-card kg-code-card"><pre><code class="language-yaml">---
vms:
  - name: "vm1"
    node_name: "mox"
    resource_name: "vm1"
    vm_id: 1000
    agent:
      enabled: false
      trim: true
      type: "virtio"
    bios: "seabios"
    cpu:
      cores: 1
      sockets: 1
    cloud_init:
      type: "nocloud"
      datastore_id: "local-lvm"
      dns:
        domain: "homelab.lan"
        server: "1.1.1.1 1.0.0.1"
      ip_configs:
        - ipv4:
            address: "192.168.0.110/24"
            gateway: "192.168.0.254"
        - ipv6:
            address: "fd91:0812:a17f:6194::10/64"
            gateway: "fd91:0812:a17f:6194::1"
      user_account:
        username: "ubuntu"
        password: "ubuntu"
        keys:
          - ssh-rsa AAAAB3Nza .........
    clone:
      node_name: "mox"
      vm_id: 9000
      full: true
    disks:
      - disk1:
          interface: "scsi0"
          datastore_id: "local-lvm"
          size: 32
          file_format: "raw"
          cache: "none"
      - disk2:
          interface: "scsi1"
          datastore_id: "local-lvm"
          size: 32
          file_format: "raw"
          cache: "none"
    memory:
      dedicated: 512
    network_devices:
      - net1:
          bridge: "vmbr0"
          model: "virtio"
      - net2:
          bridge: "vmbr0"
          model: "virtio"
    on_boot: true
  - name: "vm2"
    node_name: "mox"
    resource_name: "vm2"
    vm_id: 1001
    agent:
      enabled: false
      trim: true
      type: "virtio"
    bios: "seabios"
    cpu:
      cores: 1
      sockets: 1
    cloud_init:
      type: "nocloud"
      datastore_id: "local-lvm"
      dns:
        domain: "homelab.lan"
        server: "1.1.1.1 1.0.0.1"
      ip_configs:
        - ipv4:
            address: "192.168.0.111/24"
            gateway: "192.168.0.254"
        - ipv6:
            address: "fd91:0812:a17f:6194::10/64"
            gateway: "fd91:0812:a17f:6194::1"
      user_account:
        username: "ubuntu"
        password: "ubuntu"
        keys:
          - ssh-rsa AAAAB3Nza .........
    clone:
      node_name: "mox"
      vm_id: 9000
      full: true
    disks:
      - disk1:
          interface: "scsi0"
          datastore_id: "local-lvm"
          size: 32
          file_format: "raw"
          cache: "none"
      - disk2:
          interface: "scsi1"
          datastore_id: "local-lvm"
          size: 32
          file_format: "raw"
          cache: "none"
    memory:
      dedicated: 512
    network_devices:
      - net1:
          bridge: "vmbr0"
          model: "virtio"
      - net2:
          bridge: "vmbr0"
          model: "virtio"
    on_boot: true
</code></pre><figcaption>vms.yaml</figcaption></figure><p>Et le coeur du projet en Python qui vient lire les informations du fichier <code>vms.yaml</code> et les importer pour les créer avec Pulumi sur Proxmox VE.</p><pre><code class="language-python">import yaml
import pulumi
import pulumi_proxmoxve as proxmox

with open('vms.yaml', 'r') as file:
    yaml_content = file.read()

parsed_data = yaml.safe_load(yaml_content)

for vm in parsed_data['vms']:
    disks = []
    nets = []
    ip_configs = []
    ssh_keys = []

    for disk_entry in vm.get('disks', []):
        disk = disk_entry.popitem()[1]
        disks.append(
            proxmox.vm.VirtualMachineDiskArgs(
                interface=disk.get('interface', ''),
                datastore_id=disk.get('datastore_id', ''),
                size=disk.get('size', 0),
                file_format=disk.get('file_format', ''),
                cache=disk.get('cache', '')
            )
        )

    for ip_config_entry in vm['cloud_init']['ip_configs']:
        ipv4 = ip_config_entry.get('ipv4')
        ipv6 = ip_config_entry.get('ipv6')

        if ipv4:
            ip_configs.append(
                proxmox.vm.VirtualMachineInitializationIpConfigArgs(
                    ipv4=proxmox.vm.VirtualMachineInitializationIpConfigIpv4Args(
                        address=ipv4.get('address', ''),
                        gateway=ipv4.get('gateway', '')
                    )
                )
            )

        if ipv6:
            ip_configs.append(
                proxmox.vm.VirtualMachineInitializationIpConfigArgs(
                    ipv6=proxmox.vm.VirtualMachineInitializationIpConfigIpv6Args(
                        address=ipv6.get('address', ''),
                        gateway=ipv6.get('gateway', '')
                    )
                )
            )

    for ssk_keys_entry in vm['cloud_init']['user_account']['keys']:
        ssh_keys.append(ssk_keys_entry)


    for net_entry in vm.get('network_devices', []):
        net = net_entry.popitem()[1]
        nets.append(
            proxmox.vm.VirtualMachineNetworkDeviceArgs(
                bridge=net.get('bridge', ''),
                model=net.get('model', '')
            )
        )

    virtual_machine = proxmox.vm.VirtualMachine(
        vm_id=vm['vm_id'],
        resource_name=vm['resource_name'],
        node_name=vm['node_name'],
        agent=proxmox.vm.VirtualMachineAgentArgs(
            enabled=vm['agent']['enabled'],
            trim=vm['agent']['trim'],
            type=vm['agent']['type']
        ),
        bios=vm['bios'],
        cpu=proxmox.vm.VirtualMachineCpuArgs(
            cores=vm['cpu']['cores'],
            sockets=vm['cpu']['sockets']
        ),
        clone=proxmox.vm.VirtualMachineCloneArgs(
            node_name=vm['clone']['node_name'],
            vm_id=vm['clone']['vm_id'],
            full=vm['clone']['full'],
        ),
        disks=disks,
        memory=proxmox.vm.VirtualMachineMemoryArgs(
            dedicated=vm['memory']['dedicated']
        ),
        name=vm['name'],
        network_devices=nets,
        initialization=proxmox.vm.VirtualMachineInitializationArgs(
            type=vm['cloud_init']['type'],
            datastore_id=vm['cloud_init']['datastore_id'],
            dns=proxmox.vm.VirtualMachineInitializationDnsArgs(
                domain=vm['cloud_init']['dns']['domain'],
                server=vm['cloud_init']['dns']['server']
            ),
            ip_configs=ip_configs,
            user_account=proxmox.vm.VirtualMachineInitializationUserAccountArgs(
                username=vm['cloud_init']['user_account']['username'],
                password=vm['cloud_init']['user_account']['password'],
                keys=ssh_keys
            ),
        ),
        on_boot=vm['on_boot']
    )
    
    pulumi.export(vm['name'], virtual_machine.id)
</code></pre><p>Il ne reste plus qu'à vérifier les modifications qui vont être apportées (équivalent du <code>plan</code> sur Terraform) :</p><pre><code class="language-bash">pulumi preview
Previewing update (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/........

     Type                            Name       Plan       
     pulumi:pulumi:Stack             pulumi-pro             
 +   ├─ proxmoxve:VM:VirtualMachine  vm2        create     
 +   └─ proxmoxve:VM:VirtualMachine  vm1        create   </code></pre><p>Il ne reste plus qu'à déployer nos modifications.</p><pre><code>pulumi up</code></pre><p>Vous pouvez retrouver tout le code ici :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/juhnny5/pulumi-proxmox-cloud-init"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - juhnny5/pulumi-proxmox-cloud-init: Manage Proxmox VE vms with Pulumi</div><div class="kg-bookmark-description">Manage Proxmox VE vms with Pulumi. Contribute to juhnny5/pulumi-proxmox-cloud-init development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"><span class="kg-bookmark-author">juhnny5</span><span class="kg-bookmark-publisher">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/30ac9d438470a9b72ffc0dad2bc7f7461a521a3206c5edcd1944f8a2eb030eb8/juhnny5/pulumi-proxmox-cloud-init" alt="Pulumi + Proxmox VE + Cloud-Init = ❤️"></div></a></figure><p></p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/pWO49XP9L7TxbgQVib" width="480" height="400" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/theoffice-pWO49XP9L7TxbgQVib"></a></p><!--kg-card-end: html--><p>Si vous souhaitez clean tout ça, vous pouvez lancer un <code>destroy</code>. 😈</p><pre><code>pulumi destroy</code></pre>]]></content:encoded></item><item><title><![CDATA[OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎]]></title><description><![CDATA[<p>Il y a pas très longtemps sur Twitter, j'annoncais avoir installé <a href="https://openwrt.org/">OpenWRT</a> sur des bornes Cisco Meraki MR42 (non pas sans mal). 😅</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png" class="kg-image" alt srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png 1000w, https://blog.jbriault.fr/content/images/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png 1100w" sizes="(min-width: 720px) 720px"></figure><p>Lien du Tweet en question : <a href="https://twitter.com/ju_hnny5/status/1679581547513389057?s=20">https://twitter.com/ju_hnny5/status/1679581547513389057?s=20</a></p><p>Avant de commencer, j'imagine que le projet OpenWRT ne parle pas à tout le</p>]]></description><link>https://blog.jbriault.fr/openwisp-openwrt/</link><guid isPermaLink="false">64ba3b680aee100001d9fae5</guid><category><![CDATA[<--network-->]]></category><category><![CDATA[~$linux]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Fri, 21 Jul 2023 17:56:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1516044734145-07ca8eef8731?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDZ8fHdpZml8ZW58MHx8fHwxNjg5OTI2NTEwfDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1516044734145-07ca8eef8731?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDZ8fHdpZml8ZW58MHx8fHwxNjg5OTI2NTEwfDA&ixlib=rb-4.0.3&q=80&w=2000" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎"><p>Il y a pas très longtemps sur Twitter, j'annoncais avoir installé <a href="https://openwrt.org/">OpenWRT</a> sur des bornes Cisco Meraki MR42 (non pas sans mal). 😅</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png 1000w, https://blog.jbriault.fr/content/images/2023/07/tweet_1679581547513389057_20230721_125625_via_10015_io.png 1100w" sizes="(min-width: 720px) 720px"></figure><p>Lien du Tweet en question : <a href="https://twitter.com/ju_hnny5/status/1679581547513389057?s=20">https://twitter.com/ju_hnny5/status/1679581547513389057?s=20</a></p><p>Avant de commencer, j'imagine que le projet OpenWRT ne parle pas à tout le monde, pour faire sur ce qu'est ce projet puisque sa présentation n'est pas le but de cet article est :</p><ul><li>Un firmware open source (basé sur GNU/Linux) permettant de recycler du vieux matériel ou du matériel propriétaire en routeur libre. 😍</li></ul><p>Ce n'est pas forcémment toujours très facile à déployer mais ça a le mérite de permettre de recycler du matériel voué à la poubelle (comme le matériel Cisco Meraki, qui sans licence ne sert à rien).</p><p>J'avais d'aillers déjà écrit un précédent article sur le déploiement d'OpenWRT sur une borne MR33 qui est lisible <a href="https://blog.jbriault.fr/installer-openwrt-sur-cisco-meraki-mr33/">ici</a>. 😎</p><p>Intéressant mais commençons à détailler ce qu'est OpenWISP.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/toz7qXlLyHy9n8KfKO" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/thefastsaga-fast-and-furious-tokyo-drift-toz7qXlLyHy9n8KfKO"></a></p><!--kg-card-end: html--><h2 id="qu-est-ce-qu-un-contr-leur-wi-fi-">Qu'est-ce qu'un contrôleur Wi-Fi ? 🤪</h2><p>Avant de parler d'OpenWISP, j'aimerais simplement faire un rappel de ce qu'est un contrôleur Wi-FI, de son intérêt pour que vous puissiez facilement comprendre l'intérêt d'OpenWISP. 😋</p><p>Ainsi un contrôleur Wi-Fi va principalement servir à :</p><ul><li>Gérer de manière centralisée un ensemble de bornes Wi-Fi (leurs configurations, leurs utilisateurs; leurs mises à jours, etc).</li><li>Collecter (superviser) l'état en temps réel des différentes bornes.</li><li>Fournir des informations rapide sur l'emplacement des bornes et intéragir avec elles.</li><li>Fournir de l'accès dynamique (via RADIUS ou autre) et/ou un portail captif (pratique dans des contextes de lieux publiques comme des hôtels, restaurants mais aussi du BYOD).</li><li>Et bien d'autres choses ! 😎</li></ul><p>Ok cool, mais OpenWISP dans tout ça ? Eh bien globalement il fait tout ce qui est cité plus haut ! 🤓</p><h2 id="installer-openwisp-2">Installer OpenWISP 2</h2><p>Globalement, la meilleure manière (et surtout la plus simple), c'est par le biais de la collection Ansible fournit par OpenWISP.</p><p>Pour ce faire, il faut commencer par install cette collection :</p><pre><code class="language-bash">ansible-galaxy install openwisp.openwisp2
ansible-galaxy collection install "community.general:&gt;=3.6.0"
ansible-galaxy collection install "ansible.posix"</code></pre><p>On va créer ensuite le dossier où l'on va travailler :</p><pre><code class="language-bash">mkdir ~/openwisp2-ansible-playbook
cd ~/openwisp2-ansible-playbook</code></pre><p>On va créer le fichier d'inventaire : </p><pre><code class="language-bash">[controller]
openwisp.homelab.lan</code></pre><p>Et maintenant créer le <code>playbook.yml</code> :</p><pre><code>- hosts: controller
  become: "{{ become | default('yes') }}"
  roles:
    - openwisp.homelab.lan
  vars:
    openwisp2_default_from_email: "contact@homelab.lan"</code></pre><p>Ne reste plus qu'à appliquer le playbook :</p><p>Biensûr, il faudra remplacer <code>&lt;user&gt;</code> par votre nom d'utilisateur souhaité ! 😁</p><p>Il ne restera plus qu'à tenter d'accéder à l'interface Web : </p><ul><li>https://mon_ip/admin</li></ul><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image.png 1000w, https://blog.jbriault.fr/content/images/size/w1600/2023/07/image.png 1600w, https://blog.jbriault.fr/content/images/2023/07/image.png 1659w" sizes="(min-width: 720px) 720px"></figure><p>Maintenant, nous devons y joindre nos bornes Wi-Fi.</p><h2 id="installer-l-agent-openwisp-2">Installer l'agent OpenWISP 2</h2><p>Ce n'est pas magique, pour qu'OpenWISP soit capable de déployer des configurations et intérragir avec les bornes, il faut déployer l'agent sur celles-ci. 😄</p><p>Pour ce faire : </p><pre><code>opkg update
opkg install https://storage.googleapis.com/downloads.openwisp.io/openwisp-config/latest/openwisp-config_1.1.0a-1_all.ipk
</code></pre><p>Il faut redémarrer le service après installation :</p><pre><code>/etc/init.d/openwisp_config start</code></pre><p>On va à présent configurer l'agent pour qu'il sache qui contacter en éditant le fichier <code>/etc/config/openwisp</code> et en ajoutant le contenu suivant : </p><pre><code>config controller 'http'
        option url 'https://192.168.4.1'
        option verify_ssl '0'
        option management_interface 'br-lan'
        option uuid '4917xxxxxxxx'
        option key '91d9xxxxxx'
        option shared_secret 'dPacHxxxxxx'</code></pre><p>Il ne restera qu'à redémarrer une nouvelle fois le service :  </p><pre><code>/etc/init.d/openwisp_config start</code></pre><p>A noter que la partie <code>uuid</code>, <code>key</code> et <code>shared_secret</code> est à récupérer dans l'interface lorsque vous déclarez votre nouvel AP. 😇</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-1.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-1.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-1.png 1000w, https://blog.jbriault.fr/content/images/2023/07/image-1.png 1349w" sizes="(min-width: 720px) 720px"></figure><p>Une fois que c'est OK, on peut visualiser les bornes ici :</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-2.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-2.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-2.png 1000w, https://blog.jbriault.fr/content/images/size/w1600/2023/07/image-2.png 1600w, https://blog.jbriault.fr/content/images/2023/07/image-2.png 1670w" sizes="(min-width: 720px) 720px"></figure><ul><li><a href="https://192.168.0.252/admin/config/device/">https://mon_ip/admin/config/device/</a></li></ul><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/cL4pqu8GGRIihabgSM" width="480" height="480" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/djkhaled-dj-khaled-popstar-cL4pqu8GGRIihabgSM"></a></p><!--kg-card-end: html--><h2 id="publier-un-ssid-en-roaming-">Publier un SSID en roaming 🥸</h2><p>Comme première configuration, nous allons déployer un nouveau réseau Wi-Fi (visible via le SSID) en roaming, quand je parle de roaming, je parle de la norme 802.11r.</p><p>Cette norme permet aux appareils de se déplacer sans se déconnecter en passant d'une borne à l'autre (ce que l'on appelle également donc du "roaming"). 😎</p><p>Sur le lab, nous avons 3 bornes espacées pour que le roaming puisse fonctionner.</p><p>Ainsi pour commencer, nous allons créer un nouveau "template" de configuration dans la section du même nom dans l'interface.</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-3.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-3.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-3.png 1000w, https://blog.jbriault.fr/content/images/size/w1600/2023/07/image-3.png 1600w, https://blog.jbriault.fr/content/images/2023/07/image-3.png 1669w" sizes="(min-width: 720px) 720px"></figure><p>Dans notre cas, nous allons le nommer "SSID Home" (mais peu importe son nom à vrai dire ...).</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-4.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-4.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-4.png 1000w, https://blog.jbriault.fr/content/images/2023/07/image-4.png 1362w" sizes="(min-width: 720px) 720px"></figure><p>Pour simplifier la suite de la configuration, nous allons devoir ajouter 2 variables qui seront réutilisées, à savoir le nom du SSID et le mot de passe :</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-5.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-5.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-5.png 1000w, https://blog.jbriault.fr/content/images/2023/07/image-5.png 1334w" sizes="(min-width: 720px) 720px"></figure><p>Ensuite, il faudra ajouter une nouvelle interface que l'on nommera <code>wlan0</code> si celle-ci n'est pas déjà utilisée sur vos bornes : </p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-6.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-6.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-6.png 1000w, https://blog.jbriault.fr/content/images/2023/07/image-6.png 1304w" sizes="(min-width: 720px) 720px"></figure><p>Dans mon cas je vais utiliser la radio2 de mes bornes Cisco Meraki MR42 car c'est celle qui est compatible avec le plus de normes.</p><p>Il nous faudra utiliser notre variable <code>wlan0_ssid</code> pour référer le SSID. A noter que le moteur de templating est <code>jinja2</code> puisque l'application est écrite en Python 3.</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-9.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-9.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-9.png 1000w, https://blog.jbriault.fr/content/images/2023/07/image-9.png 1264w" sizes="(min-width: 720px) 720px"></figure><p>Il faudra absolument cocher les cases :</p><ul><li>Roaming</li><li>FT PSK Generate local</li></ul><p>Les autres sont normalement pré-cochées. 🙃</p><p>Pour continuer on va déclarer la carte réseau qui fournira le réseau, dans notre cas il se nomme "lan". Et pour terminer la configuration, on va spécifier le type de chiffrement de mot de passe et la clé.</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2023/07/image-10.png" class="kg-image" alt="OpenWISP, le contrôleur Wi-Fi universel pour OpenWRT 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/07/image-10.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/07/image-10.png 1000w, https://blog.jbriault.fr/content/images/2023/07/image-10.png 1251w" sizes="(min-width: 720px) 720px"></figure><p>Cette configuration devrait s'appliquer automatiquement sur vos bornes. Pour vérifier, vous pouvez vous rendre sur l'interface LuCI des bornes. ☺️</p><h2 id="conclusion">Conclusion</h2><p>Vous l'aurez compris, on peut facilement déployer de la configuration par le bias d'OpenWISP sur des bornes OpenWRT sans trop de difficulté et ainsi maintenir un parc homogène en terme de configuration. 😇</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/l4pSWL2VovHsl4yqY" width="480" height="265" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/recordingacademy-grammys-red-carpet-l4pSWL2VovHsl4yqY"></a></p><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Homebrew: Installer un package non maintenu 🙄]]></title><description><![CDATA[<p>Bon, on va pas se le cacher, en terme de sécurité c'est pas terrible de faire ça. Dans certains cas en entreprise (ou en perso d'ailleurs), on est parfois <em>obligé</em> d'utiliser une version d'un package d'antan. 😆</p><p>Globalement, c'est pas hyper compliqué, pour ce faire, vous devez éditer le package :</p><pre><code>brew</code></pre>]]></description><link>https://blog.jbriault.fr/installer-un-package-non-maintenu-dans-homebrew/</link><guid isPermaLink="false">649e81980aee100001d9fabb</guid><category><![CDATA[>>devops<<]]></category><category><![CDATA[<dev/>]]></category><category><![CDATA[CLI<3]]></category><category><![CDATA[- NetDevOps -]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Fri, 30 Jun 2023 07:23:40 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1517336714731-489689fd1ca8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDV8fG1hY3xlbnwwfHx8fDE2ODgxMDk3NjN8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1517336714731-489689fd1ca8?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMTc3M3wwfDF8c2VhcmNofDV8fG1hY3xlbnwwfHx8fDE2ODgxMDk3NjN8MA&ixlib=rb-4.0.3&q=80&w=2000" alt="Homebrew: Installer un package non maintenu 🙄"><p>Bon, on va pas se le cacher, en terme de sécurité c'est pas terrible de faire ça. Dans certains cas en entreprise (ou en perso d'ailleurs), on est parfois <em>obligé</em> d'utiliser une version d'un package d'antan. 😆</p><p>Globalement, c'est pas hyper compliqué, pour ce faire, vous devez éditer le package :</p><pre><code>brew edit ansible@2.9</code></pre><p>Supprimez la ligne suivante :</p><pre><code>disable! date: "2022-07-31", because: :unmaintained</code></pre><p>Et ensuite, ne reste plus qu'à l'installer ! 🤷🏼‍♂️</p><pre><code>HOMEBREW_NO_INSTALL_FROM_API=1 brew install ansible@2.9</code></pre><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/8P1oO2JbrZK2uSYnL6" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/RobertEBlackmon-french-voila-8P1oO2JbrZK2uSYnL6"></a></p><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Mon premier talk à DevoxxFR (2023) 😎]]></title><description><![CDATA[Petit retour sur mon premier talk à Devoxx FR.]]></description><link>https://blog.jbriault.fr/mon-premier-talk-a-devoxxfr-2023/</link><guid isPermaLink="false">644918d02573db00017ef618</guid><category><![CDATA[>>devops<<]]></category><category><![CDATA[<dev/>]]></category><category><![CDATA[<--network-->]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Wed, 26 Apr 2023 12:59:57 GMT</pubDate><media:content url="https://blog.jbriault.fr/content/images/2023/04/Ftm5ovpWAAgKXMe.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.jbriault.fr/content/images/2023/04/Ftm5ovpWAAgKXMe.jpg" alt="Mon premier talk à DevoxxFR (2023) 😎"><p><em>Avant toutes choses, merci Idriss pour la photo. 😊</em></p><p>Après avoir publié mon premier article dans <a href="https://boutique.ed-diamond.com/en-kiosque/1652-linux-pratique-136.html">Linux Pratique</a>, magazine spécialisé, autour du projet <a href="https://github.com/octodns/octodns">OctoDNS</a>, je me suis lancé dans la conception d'un talk autour de ce sujet. 🤠</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.jbriault.fr/content/images/2023/04/Untitled--1-.jpg" class="kg-image" alt="Mon premier talk à DevoxxFR (2023) 😎" srcset="https://blog.jbriault.fr/content/images/size/w600/2023/04/Untitled--1-.jpg 600w, https://blog.jbriault.fr/content/images/size/w1000/2023/04/Untitled--1-.jpg 1000w, https://blog.jbriault.fr/content/images/2023/04/Untitled--1-.jpg 1536w" sizes="(min-width: 720px) 720px"><figcaption>Linux Pratique n°136 - "DNS as code avec OctoDNS"</figcaption></figure><p><br>Dans l'article je présentais le fonctionnement de l'outil en donnant des exemples techniques. Intéressant mais rien ne vaut une démo et un véritable cas pratique d'utilisation de cet outil ainsi qu'un retour d'expérience.</p><p>C'est donc pour cela que je me suis lancé en croisade pour vous présenter cet outil durant <a href="https://www.devoxx.fr/">Devoxx FR</a> (encore merci à eux de m'avoir fait confiance). 🙏</p><p>J'ai donc pu y présenter d'où on vient sur la gestion des entrées DNS, les différentes tentatives réalisées avec d'autres outils comme <a href="https://www.ansible.com/">Ansible</a> ou <a href="https://www.terraform.io/">Terraform</a> qui sont bien plus utilisés. Je présente également ce pour quoi ces outils ne sont pas toujours adaptés.</p><p>J'aurais pu également présenter <a href="https://dnscontrol.org/">dnscontrol</a> ou <a href="https://github.com/AnalogJ/lexicon">lexicon</a> qui ont un fonctionnement similaire à OctoDNS, mais j'ai choisi ce dernier pour sa simplicité d'utilisation et de syntaxe, syntaxe à la portée de tout le monde.‌</p><p>J'ai pris la décision de faire 3 démos simples pour des raisons de temps (30 minutes ça passe vite) :</p><ul><li><em>créer des enregistrements sur une instance PowerDNS (on-prem)</em></li><li><em>récupérer les enregistrements de l'instance PowerDNS au format OctoDNS (dump)</em></li><li><em>migrer de l'on-prem (PowerDNS) vers du Cloud (AWS)</em></li></ul><p>Vous retrouverez ici le code de la présentation ainsi que les slides :</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/juhnny5/DevoxxFR2023-OctoDNS"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - juhnny5/DevoxxFR2023-OctoDNS: DevoxxFR 2023 | Infra : Donnez de l’autonomie à vos développeurs avec OctoDNS</div><div class="kg-bookmark-description">DevoxxFR 2023 | Infra : Donnez de l’autonomie à vos développeurs avec OctoDNS - GitHub - juhnny5/DevoxxFR2023-OctoDNS: DevoxxFR 2023 | Infra : Donnez de l’autonomie à vos développeurs avec OctoDNS</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" alt="Mon premier talk à DevoxxFR (2023) 😎"><span class="kg-bookmark-author">juhnny5</span><span class="kg-bookmark-publisher">GitHub</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/fe36d61a7fa3385d1450c331d34c21d58a828d21a967f271bb4179c6ed6410b2/juhnny5/DevoxxFR2023-OctoDNS" alt="Mon premier talk à DevoxxFR (2023) 😎"></div></a></figure><p>Bon, je commence à vieillir et certains diront (Cc Antoine Daniel) que ce n'est qu'être un boomer que de faire référence à <a href="https://fr.wikipedia.org/wiki/The_Office_(s%C3%A9rie_t%C3%A9l%C3%A9vis%C3%A9e,_2005)">The Office</a>, mais bon, je n'ai que 24 ans donc bon ... Je vieillis. 😬</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/cXblnKXr2BQOaYnTni" width="480" height="400" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/theoffice-the-office-tv-moroccan-christmas-cXblnKXr2BQOaYnTni"></a></p><!--kg-card-end: html--><p>Sur ce, bon visionnage.</p><figure class="kg-card kg-embed-card"><iframe width="356" height="200" src="https://www.youtube.com/embed/aZvsplOAd7c?list=PLTbQvx84FrATkUhLB2WWwC4Im5QcCj6ih" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe></figure><p>N'hésitez pas à me faire des retours, je reste novice pour le moment en tant que speaker je prends toutes vos remarques (bienveillantes). 😊</p><p><em>PS : J'ai déjà eu une première suggestion : Autonomie ➡️ Octonomie, merci Geoffrey. 😆</em></p>]]></content:encoded></item><item><title><![CDATA[Astuce Go : récupérer le nom d'un dépôt Git 🤘]]></title><description><![CDATA[<p>Il peut être parfois intéressant d'avoir à récupérer le nom du dépôt Git dans lequel vous travaillez. Git possède une commande pour le faire et nous allons l'utiliser pour récupérer cette information.</p><p>Cette fameuse commande est <code>git rev-parse --show-toplevel</code>. 😁</p><p>Le seul problème avec cette commande est quelle vous retourne le</p>]]></description><link>https://blog.jbriault.fr/go-recuperer-le-nom-dun-depot-git/</link><guid isPermaLink="false">63b1780f2573db00017ef5cb</guid><category><![CDATA[<dev/>]]></category><category><![CDATA[>>devops<<]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Sun, 01 Jan 2023 12:15:30 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1642367340318-96fdbc5d30f5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGdvbGFuZ3xlbnwwfHx8fDE2NzI1NzUxMjQ&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1642367340318-96fdbc5d30f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDF8fGdvbGFuZ3xlbnwwfHx8fDE2NzI1NzUxMjQ&ixlib=rb-4.0.3&q=80&w=2000" alt="Astuce Go : récupérer le nom d'un dépôt Git 🤘"><p>Il peut être parfois intéressant d'avoir à récupérer le nom du dépôt Git dans lequel vous travaillez. Git possède une commande pour le faire et nous allons l'utiliser pour récupérer cette information.</p><p>Cette fameuse commande est <code>git rev-parse --show-toplevel</code>. 😁</p><p>Le seul problème avec cette commande est quelle vous retourne le chemin complet du dépôt Git localement stocké.</p><p>Ainsi, nous récupèrerons le nom du dépôt avec Go :</p><pre><code class="language-Go">package main

import (
	"bytes"
	"fmt"
	"os/exec"
	"strings"
)

func main() {
	// Run the "git rev-parse --show-toplevel" command to get the path of the top-level directory of the repository.
	cmd := exec.Command("git", "rev-parse", "--show-toplevel")

	// Get the output of the command.
	var out bytes.Buffer
	cmd.Stdout = &amp;out
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Failed to run command: %v\n", err)
	}

	// Extract the repository name from the path.
	repoPath := strings.TrimSpace(out.String())
	repoName := filepath.Base(repoPath)

	fmt.Printf("Current repository name: %s\n", repoName)
}</code></pre><p>Le code va extraire le nom du dépôt à partir du chemin en utilisant la fonction <code>filepath.Base</code>.</p><p>J'espère que cela vous aidera ! 🤷🏼‍♂️</p><p>Sur ce, bonne année 2023 ! 🚀</p>]]></content:encoded></item><item><title><![CDATA[Supprimer d'un coup tous les packages Homebrew 😎]]></title><description><![CDATA[<p>Au travail, je suis passé du côté obscur de la force, je me suis laissé tenté par un Macbook Pro M1, la machine marche plutôt bien et j'utilise un classique pour gérer les packages à installer sur celui-ci qui est : <a href="https://brew.sh/index_fr">homebrew</a>. 😄</p><p>J'étais curieux de trouver la commande qui permet de</p>]]></description><link>https://blog.jbriault.fr/supprimer-dun-coup-tous-les-packages-homebrew/</link><guid isPermaLink="false">6342937412bcde0001eccf73</guid><category><![CDATA[-macos-]]></category><category><![CDATA[CLI<3]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Sun, 09 Oct 2022 09:30:46 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1611262588019-db6cc2032da3?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE2fHxtYWN8ZW58MHx8fHwxNjY1MzA3NTM2&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1611262588019-db6cc2032da3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE2fHxtYWN8ZW58MHx8fHwxNjY1MzA3NTM2&ixlib=rb-1.2.1&q=80&w=2000" alt="Supprimer d'un coup tous les packages Homebrew 😎"><p>Au travail, je suis passé du côté obscur de la force, je me suis laissé tenté par un Macbook Pro M1, la machine marche plutôt bien et j'utilise un classique pour gérer les packages à installer sur celui-ci qui est : <a href="https://brew.sh/index_fr">homebrew</a>. 😄</p><p>J'étais curieux de trouver la commande qui permet de clean tous les packages installés avec ce gestionnaire, histoire de faire un peu de ménage.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/McVcE1YJrsze1qtgnP" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/RobertEBlackmon-reactions-germs-rubber-glove-McVcE1YJrsze1qtgnP"></a></p><!--kg-card-end: html--><p>Eh bien la réponse est relativement simple :</p><pre><code class="language-bash">brew remove --force $(brew list --formula) --ignore-dependencies</code></pre><p>Et voilà !</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/1BFEEIo4h1BuTH8eqP" width="480" height="403" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/theoffice-episode-3-the-office-tv-1BFEEIo4h1BuTH8eqP"></a></p><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Installer OpenWRT sur Cisco Meraki MR33 😆]]></title><description><![CDATA[<p>J'avais depuis quelques temps, une borne d'accès Wi-Fi (autrement appelée <em>Access Point, </em><strong>Cisco Meraki MR33</strong>) qui prenait la poussière dans l'un de mes tiroir, j'ai décidé d'essayer (sans mal), d'installer OpenWRT et de vous donner la manip à suivre pour que vous puissiez y arriver du premier coup. 😊</p><p>Cette borne</p>]]></description><link>https://blog.jbriault.fr/installer-openwrt-sur-cisco-meraki-mr33/</link><guid isPermaLink="false">6218b68512bcde0001eccd59</guid><category><![CDATA[<--network-->]]></category><category><![CDATA[~$linux]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Sat, 26 Feb 2022 09:39:26 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1592919347498-69564e361791?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fHdpcmVsZXNzfGVufDB8fHx8MTY0NTg2NTY2Ng&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1592919347498-69564e361791?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDV8fHdpcmVsZXNzfGVufDB8fHx8MTY0NTg2NTY2Ng&ixlib=rb-1.2.1&q=80&w=2000" alt="Installer OpenWRT sur Cisco Meraki MR33 😆"><p>J'avais depuis quelques temps, une borne d'accès Wi-Fi (autrement appelée <em>Access Point, </em><strong>Cisco Meraki MR33</strong>) qui prenait la poussière dans l'un de mes tiroir, j'ai décidé d'essayer (sans mal), d'installer OpenWRT et de vous donner la manip à suivre pour que vous puissiez y arriver du premier coup. 😊</p><p>Cette borne m'avait été offerte à l'époque par <strong>Cisco Meraki</strong> en ayant simplement suivi un webinar, d'ailleurs ce format est toujours d'actualité <a href="https://meraki.cisco.com/fr-fr/freeap/">chez eux</a>. 😱</p><p>D'ailleurs, j'avais également reçu un switch PoE+ 8 ports en suivant <a href="https://meraki.cisco.com/fr-fr/webinars/la-nouvelle-generation-de-switches/">ce webinar</a>.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/SVH9y2LQUVVCRcqD7o" width="480" height="358" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/moodman-very-cool-SVH9y2LQUVVCRcqD7o"></a></p><!--kg-card-end: html--><p>Bon, revenon à nos moutons, avant d'entreprendre quoi que ce-soit, vous devez possèder le matériel suivant :</p><ul><li>Des câbles Jumper Wire (x3), <a href="https://www.amazon.fr/gp/product/B07KYHBVR7/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&amp;psc=1">lien</a>.</li><li>Un RaspberryPI avec <a href="https://www.raspberrypi.com/software/">RaspberryPI OS</a></li><li>Un tournevis torx, diammètre 4</li><li>Un câble RJ45</li><li>Et votre cerveau 🤯</li></ul><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2022/02/273068634_1367699313680164_6997616816159969594_n.jpg" class="kg-image" alt="Installer OpenWRT sur Cisco Meraki MR33 😆" srcset="https://blog.jbriault.fr/content/images/size/w600/2022/02/273068634_1367699313680164_6997616816159969594_n.jpg 600w, https://blog.jbriault.fr/content/images/size/w1000/2022/02/273068634_1367699313680164_6997616816159969594_n.jpg 1000w, https://blog.jbriault.fr/content/images/2022/02/273068634_1367699313680164_6997616816159969594_n.jpg 1536w" sizes="(min-width: 720px) 720px"></figure><p>Une fois que vous avez tout celà, vous allez devoir cloner le repo suivant sur votre Raspberry.</p><pre><code class="language-bash">git clone https://github.com/julienbriault/mr33-openwrt.git</code></pre><h3 id="installation-des-pr-requis-">Installation des prérequis 😆</h3><p>Si vous avez installé la toute dernière version de RaspberryPI OS et que vous avez fait un <code>cat /etc/debian-release</code> vous vous rendrez compte que celui-ci est basé sur <strong>Debian 11</strong> (obviously). 😇</p><p>Cette version ne possède plus dans ses repos <code>pip2</code> Ainsi, il nous faut l'installer manuellement :</p><pre><code class="language-bash">sudo apt update; sudo apt install python2 curl -y
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
sudo python2 get-pip.py


# On peut vérifier que ça marche bien avec la commande
pip2 --version</code></pre><p>Une fois que c'est fait, on va pouvoir installer la seule dépendance du script <code>ubootwrite.py</code> à savoir 'serial' :</p><pre><code class="language-bash">pip2 install serial</code></pre><p>‼️ A noter que toute cette partie peut être réalisée avec Docker également (allez voir le README du repo <a href="https://github.com/julienbriault/mr33-openwrt">suivant</a>).</p><h3 id="activation-du-mode-console-sur-le-raspberrypi-">Activation du mode console sur le RaspberryPI 🧐</h3><p>Grosso merdo, sur votre Raspberry, nous allons utiliser 3 pins pour la console (dont un qui est pour la masse: GND).</p><p>Il faudra d'ailleurs faire très attention à ne pas se décaler en connectant les jumpers car sinon, ça ne risque pas de fonctionner. 😄</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.jbriault.fr/content/images/2022/02/image.png" class="kg-image" alt="Installer OpenWRT sur Cisco Meraki MR33 😆" srcset="https://blog.jbriault.fr/content/images/size/w600/2022/02/image.png 600w, https://blog.jbriault.fr/content/images/size/w1000/2022/02/image.png 1000w, https://blog.jbriault.fr/content/images/2022/02/image.png 1024w" sizes="(min-width: 720px) 720px"><figcaption>Source: https://www.ibeyonde.com/raspberry-pi-serial-ports.html</figcaption></figure><p>Ainsi pour activer ce fameux mode console (un peu comme si on voulait activer un port RS232 sur un pc classique), il faut utiliser l'utilitaire "raspi-config" en CLI et se rendre dans 'Interfacing options' &gt; 'serial'.</p><p>Sur le prompt 1, vous devez spécifier 'no', sur le prompt 2 vous devez spécifier 'yes' pour l'activer. 🥸</p><p>Il vous faudra redémarrer dans l'idéal. Ainsi, vous pouvez ensuite contrôler avec la commande :</p><pre><code class="language-bash">ls -l /dev | grep serial</code></pre><p>Vous devriez obtenir :</p><ul><li><code>serial0 -&gt; ttyS0</code></li><li><code>serial1 -&gt; ttyAMA0</code></li></ul><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/26ufdipQqU2lhNA4g" width="480" height="480" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/producthunt-mind-blown-blow-your-26ufdipQqU2lhNA4g"></a></p><!--kg-card-end: html--><h3 id="d-montage-et-connexion">Démontage et connexion</h3><p>Sous votre borne, il vous faudra retirer les patins pour y dévisser les vis présentent en dessous.</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2022/02/274226995_695509971826979_4769173164278890125_n.jpg" class="kg-image" alt="Installer OpenWRT sur Cisco Meraki MR33 😆" srcset="https://blog.jbriault.fr/content/images/size/w600/2022/02/274226995_695509971826979_4769173164278890125_n.jpg 600w, https://blog.jbriault.fr/content/images/size/w1000/2022/02/274226995_695509971826979_4769173164278890125_n.jpg 1000w, https://blog.jbriault.fr/content/images/2022/02/274226995_695509971826979_4769173164278890125_n.jpg 1536w" sizes="(min-width: 720px) 720px"></figure><p>Je vous conseil de vous aider d'un médiator en plastique pour déclipser la borne sans l'abîmer. </p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2022/02/272396433_532928958020771_5734458037309347687_n.jpg" class="kg-image" alt="Installer OpenWRT sur Cisco Meraki MR33 😆" srcset="https://blog.jbriault.fr/content/images/size/w600/2022/02/272396433_532928958020771_5734458037309347687_n.jpg 600w, https://blog.jbriault.fr/content/images/size/w1000/2022/02/272396433_532928958020771_5734458037309347687_n.jpg 1000w, https://blog.jbriault.fr/content/images/2022/02/272396433_532928958020771_5734458037309347687_n.jpg 1536w" sizes="(min-width: 720px) 720px"></figure><p>Maintenant que votre borne est éventrée. Nous allons devoir la connecter en console au RaspberryPI. 😇</p><p>Pour ce faire, munissez-vous de vos jumpers et connectez comme suit :</p><ul><li>GND &gt; blanc &gt; pin tout à droite de la borne ;</li><li>GPIO14 &gt; bleu &gt; pin au centre de la borne ;</li><li>GPIO15 &gt; rouge &gt; pin à gauche (à côté de celui qui possède la flèche blanche).</li></ul><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2022/02/273014146_324212042881188_6644294970792421028_n.jpg" class="kg-image" alt="Installer OpenWRT sur Cisco Meraki MR33 😆" srcset="https://blog.jbriault.fr/content/images/size/w600/2022/02/273014146_324212042881188_6644294970792421028_n.jpg 600w, https://blog.jbriault.fr/content/images/size/w1000/2022/02/273014146_324212042881188_6644294970792421028_n.jpg 1000w, https://blog.jbriault.fr/content/images/2022/02/273014146_324212042881188_6644294970792421028_n.jpg 1536w" sizes="(min-width: 720px) 720px"></figure><p>Il est important de noter qu'il ne faut surtout rien connecter sur le pin avec un flèche blanche sur la borne.</p><figure class="kg-card kg-image-card"><img src="https://blog.jbriault.fr/content/images/2022/02/273031012_3013614038913710_4542957744197988083_n-1.jpg" class="kg-image" alt="Installer OpenWRT sur Cisco Meraki MR33 😆" srcset="https://blog.jbriault.fr/content/images/size/w600/2022/02/273031012_3013614038913710_4542957744197988083_n-1.jpg 600w, https://blog.jbriault.fr/content/images/size/w1000/2022/02/273031012_3013614038913710_4542957744197988083_n-1.jpg 1000w, https://blog.jbriault.fr/content/images/2022/02/273031012_3013614038913710_4542957744197988083_n-1.jpg 1536w" sizes="(min-width: 720px) 720px"></figure><p>Une fois que c'est fait, nous allons pouvoir flasher la borne (envoyer <code>uboot</code>). 😊</p><h3 id="envoyer-uboot-">Envoyer uboot 🤗</h3><p>Pour ce faire rien de bien compliqué, vous devez utiliser les commandes suivantes :</p><pre><code class="language-bash">cd mr33-openwrt/ubootwrite
chmod a+x ubootwrite.py
./ubootwrite.py --write=mr33-uboot.bin --serial=/dev/ttyS0</code></pre><p>Lancez le script sans avoir allumé la borne, vous devriez, tant que la borne n'est pas allumée, avoir le prompt "Uploading Image".</p><p>Allumez-la, et l'upload de l'image devrait commencer.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/iemyQLx2kEJpeCbX9O" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/netflix-movie-leonardo-dicaprio-dontlookup-iemyQLx2kEJpeCbX9O"></a></p><!--kg-card-end: html--><p>Uboot va nous être très pratique car il va nous fournir un <em>serveur ftp</em> pour envoyer l'image d'OpenWRT par la suite.</p><p>Une fois que l'image est envoyée, vous devriez obtenir un "Hello from MR33 U-BOOT".</p><h3 id="envoyer-l-image-initramfs-">Envoyer l'image initramfs 😱</h3><p>Vous devez connecter votre raspberry avec une adresse IP dans le subnet 192.168.1.0/24 pour que vous puissiez accéder à la borne qui possède à présent l'IP (192.168.1.1).</p><p>Il nous faut à présent envoyer l'image avec la commande suivante :</p><pre><code class="language-bash">echo -e "openwrt-ipq40xx-meraki_mr33-initramfs-fit-uImage.itb" | tftp 192.168.1.1</code></pre><p>Une fois que c'est envoyé, laissez le temps au MR33 de démarrer. </p><p>Vous pouvez passer à l'étape suivante lorsque la LED d'état passe au vert et cesse de clignoter. 🤠</p><p>Il ne vous reste plus qu'à vous connecter en SSH pour valider qu'OpenWRT est bien présent. Attention à ne pas redémarrer la borne, sinon, il faudra tout recommencer, pour le moment, nous n'avons rien écrit dans la NVRAM.</p><pre><code class="language-bash">ssh root@192.168.1.1
root@OpenWrt:~#</code></pre><h3 id="pr-voir-un-retour-arri-re-">Prévoir un retour arrière 🤩</h3><p>Comme nous n'avons pas encore fait de sauvegarde de l'OS déjà présent, et que nous n'avons pas écrasé la NVRAM, il nous faut le faire pour pouvoir faire une marche arrière si tel est le cas.</p><p>Pour ce faire, il faut utiliser les commandes suivantes :</p><pre><code class="language-bash">file="openwrt-ipq40xx-meraki_mr33-initramfs-fit-uImage.itb"
size=$(cat "$file" | wc -c)
ubirename /dev/ubi0 part.old part.meraki.old
ubimkvol /dev/ubi0 --size=$size --type=static 
--name=part.old

Volume ID 99, size 49 LEBs (6221824 bytes, 5.9 MiB), LEB size 126976 bytes (124.0 KiB), static, name
"part.old", alignment 1
Ubimkvol generates a new Volume ID (marked in red). This ID is used for the next command so please
replace the 99 with the correct value.

ubiupdatevol /dev/ubi0_99 "$file"</code></pre><p>A noter que <code>/dev/ubi0_99</code> correspond au <code>Volume ID 99</code> présent un peu plus haut, ainsi ce numéro pourra changer en fonction du cas de figure. 😎</p><h4 id="installer-openwrt-pour-toujours-">Installer OpenWRT pour toujours !</h4><p>Maintenant que l'on a préparé un retour arrière, nous allons pouvoir installer OpenWRT, pour ça, il faut copier le fichier <code>openwrt-ipq40xx-meraki_mr33-squashfs-sysupgrade.bin</code> sur notre machine avec la commande :</p><pre><code class="language-bash">scp openwrt-ipq40xx-meraki_mr33-squashfs-sysupgrade.bin root@192.168.1.1:/root/</code></pre><p>Ainsi le fichier sera présent dans la <strong>home directory</strong> de <em>root</em>. 🤭</p><p>Il restera donc sur la machine à utiliser les commandes : </p><pre><code class="language-bash">ubirename /dev/ubi0 part.safe part.meraki
sysupgrade -v openwrt-ipq40xx-meraki_mr33-squashfs-sysupgrade.bin</code></pre><p>Une fois que c'est fait, la borne va à nouveau redémarrer, vous pourrez ensuite vous connecter à l'interface web d'OpenWRT (via http://192.168.1.1).</p><h3 id="restaurer-le-firmware-d-origine-">Restaurer le firmware d'origine 😜</h3><p>Pour restaurer le firmware d'origine, il suffit d'utiliser les commande suivantes :</p><pre><code class="language-bash">ubirename /dev/ubi0 part.safe part.openwrt part.old part.fallback
ubirename /dev/ubi0 part.meraki part.safe part.meraki.old part.old

# Supprimer les partitions OpenWRT
ubirmvol /dev/ubi0 --name=rootfs
ubirmvol /dev/ubi0 --name=rootfs_data</code></pre><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/kcaFvjKCjPHiQbCaTX" width="480" height="342" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/TAG24video-tom-tag24-totaletom-kcaFvjKCjPHiQbCaTX"></a></p><!--kg-card-end: html--><h3 id="sources">Sources</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://drive.google.com/drive/folders/1jJa8LzYnY830v3nBZdOgAk0YQK6OdbSS"><div class="kg-bookmark-content"><div class="kg-bookmark-title">MR33 – Google Drive</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://ssl.gstatic.com/images/branding/product/1x/drive_2020q4_32dp.png" alt="Installer OpenWRT sur Cisco Meraki MR33 😆"></div></div><div class="kg-bookmark-thumbnail"><img src="https://drive-thirdparty.googleusercontent.com/128/type/application/pdf" alt="Installer OpenWRT sur Cisco Meraki MR33 😆"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Anonymiser sa configuration réseau avec netconan 🧐]]></title><description><![CDATA[Cacher une partie de sa configuration des données sensibles pour l'envoyer à un collègue ou une société externe n'est pas si compliqué...]]></description><link>https://blog.jbriault.fr/anonymiser/</link><guid isPermaLink="false">617fb43112bcde0001eccc5c</guid><category><![CDATA[<--network-->]]></category><category><![CDATA[- NetDevOps -]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Mon, 17 Jan 2022 09:28:28 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1545569310-f6d4b4d7ede9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDI1fHxuZXR3b3JrfGVufDB8fHx8MTY0MjM1NzQwMA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1545569310-f6d4b4d7ede9?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDI1fHxuZXR3b3JrfGVufDB8fHx8MTY0MjM1NzQwMA&ixlib=rb-1.2.1&q=80&w=2000" alt="Anonymiser sa configuration réseau avec netconan 🧐"><p>Il n'y a pas très longtemps, j'ai découvert <a href="https://github.com/intentionet/netconan">cet outil</a> écrit en <em>Python</em> par <a href="https://www.intentionet.com/">Intentionet</a>, une boîte américaine qui développe également un superbe outil nommé <strong><a href="https://www.batfish.org/">Batfish</a> Enterprise</strong>.</p><p>Mais à quoi ça peut bien me servir me direz-vous ? Eh bien, ne vous est-il jamais arrivé d'avoir eu besoin d'envoyer votre configuration à un tiers mais que vous ne souhaitiez pas qu'il accède à certaines informations de celle-ci. Eh bien c'est faisable de cacher certaines informations, en les remplaçant par d'autres, avec l'outil nommé <a href="https://github.com/intentionet/netconan">netconan</a>. 🤯</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/nkbHJf196TV7y" width="480" height="266" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/conan-the-barbarian-nkbHJf196TV7y"></a></p><!--kg-card-end: html--><p>Avant toutes choses, vous devez bien évidemment avoir Python d'installé sur votre machine et son gestionnaire de dépendances (<em>pip </em>✔️).</p><p>Dès que vous avez tout ce qu'il faut pour commencer, vous pouvez utiliser la commande suivante pour installer l'outil :</p><pre><code class="language-bash">pip install netconan</code></pre><p>Maintenant que l'outil est installé, on va pouvoir commencer à jouer ! 😬 </p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/nbgMIadDPr2BozmwsY" width="480" height="270" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/HBOMax-halloween-hbo-max-it-chapter-2-nbgMIadDPr2BozmwsY"></a></p><!--kg-card-end: html--><p>⚠️ <em>A noter tout de même avant toutes choses que les tests ont été réalisés avec une configuration Cisco.</em></p><p>Pour l'exemple, j'ai utilisé un pack <a href="https://cvddocs.com/fw/cfg-17b-i1">CVD de configuration</a> (de Cisco obviously).</p><p>Dans ce pack on retrouve le fichier nommé "i4-201i-IWAN-CFG_Sep2017_rs32-4451x-2-confg_BGP". Pour les tests je l'ai renommé en "original-cfg". J'ai d'ailleurs supprimé les autres configs, elles ne me servent à rien pour l'exemple.</p><p>Voici un premier exemple tout simple permettant d'anonymiser les mots de passes et bien plus :</p><pre><code class="language-bash">netconan -i original-cfg -o anonymized-cfg --anonymize-passwords</code></pre><p>Vous avez plusieurs options très pratique avec cet outil qui sont : </p><ul><li><code>--anonymise-passwords</code> qui comme son nom l'indique permet de cacher les mots de passe de la configuration par d'autres hashs. D'ailleurs cette option permet également de cacher les communautés SNMP 😜</li><li><code>--anonymize-ips</code> permet de cacher les adresses IP (v4/v6).</li><li><code>--sensitive-words</code> permet de cacher des mots sensibles comme le nom de la société, d'un client.</li><li>On peut également cacher/remplacer les numéros d'AS dans le cas d'une configuration pour du BGP avec l'option `--as-numbers</li></ul><p>Voici un exemple un peu plus complexe :</p><pre><code class="language-bash">netconan -i original-cfg -o anonymized-cfg \
    --sensitive-words customer1,customer2,my-company \
    --anonymize-passwords \
    --anonymize-ips</code></pre><p>On peut aller encore plus loin ? Oui ! 🤯</p><p>La section <a href="https://github.com/intentionet/netconan#features">features</a> de la doc officielle de l'outil détail comment préserverune structure utilisable, eneffet, parfois, nous souhaitons juste diffuser une configuration à un collègue tout en empêchant que celle-ci soit compréhensible par une tierse personne qui l'aurait intercepté. 😅</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/JOeXqZebetYyY" width="480" height="416" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/get-out-siteasdasddd-JOeXqZebetYyY"></a></p><!--kg-card-end: html--><p>Vous n'aurez plus d'excuses pour échanger des configuration de manière un peu plus sécurisée à présent ! 😎</p>]]></content:encoded></item><item><title><![CDATA[Intégrer des fichiers statiques dans Go 🤩]]></title><description><![CDATA[<p>Depuis la version <a href="https://golang.org/doc/go1.16#library-embed">1.16</a> de Golang, il est possible d'intégrer des fichiers statiques dans nos binaires au build. C'est faisable grâce à l'ajout d'un nouveau package nommé <code>embed</code>. Ce package fournit un ensemble pratique d'interfaces, de méthodes pour embarquer des fichiers <em>statiques</em> dans les binaires <strong>Go</strong>. 🤯</p><h3 id="la-pr-histoire">La préhistoire</h3><p>Avant</p>]]></description><link>https://blog.jbriault.fr/integrer-des-fichiers-statiques-dans-go/</link><guid isPermaLink="false">611d106212bcde0001eccb2f</guid><category><![CDATA[<dev/>]]></category><category><![CDATA[>>devops<<]]></category><dc:creator><![CDATA[Julien Briault]]></dc:creator><pubDate>Thu, 19 Aug 2021 11:34:49 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1522071820081-009f0129c71c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE4fHx3ZWJ8ZW58MHx8fHwxNjI5Mjk0NzI4&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1522071820081-009f0129c71c?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE4fHx3ZWJ8ZW58MHx8fHwxNjI5Mjk0NzI4&ixlib=rb-1.2.1&q=80&w=2000" alt="Intégrer des fichiers statiques dans Go 🤩"><p>Depuis la version <a href="https://golang.org/doc/go1.16#library-embed">1.16</a> de Golang, il est possible d'intégrer des fichiers statiques dans nos binaires au build. C'est faisable grâce à l'ajout d'un nouveau package nommé <code>embed</code>. Ce package fournit un ensemble pratique d'interfaces, de méthodes pour embarquer des fichiers <em>statiques</em> dans les binaires <strong>Go</strong>. 🤯</p><h3 id="la-pr-histoire">La préhistoire</h3><p>Avant ça, pendant un long moment, j'utilisais un projet nommé "<a href="https://github.com/a-urth/go-bindata">go-bindata</a>" mais qui est déprécié depuis un long moment.</p><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/JdPDxUhQFFzCU" width="480" height="480" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/ms-plan-whitley-JdPDxUhQFFzCU"></a></p><!--kg-card-end: html--><p>Bon, c'était du passé, maintenant on peut intégrer facilement un fichier statique directement dans le binaire sans passer par des dépendances autres. 😅</p><h3 id="un-peu-de-doc-">Un peu de doc 🎓</h3><p>Vous pouvez retrouver toute la documentation du package <code>embed</code> en utilisant la commande :</p><pre><code class="language-bash">go doc embed</code></pre><p>Cette commande est vraiment à retenir quand on utilise Golang au quotidien, c'est super pratique, la doc n'est pas toujours très exhaustive mais le 3/4 du temps, vous avez de bons exemples.</p><p>D'ailleurs en bon complément de la documentation officielle, vous avez <a href="https://livre.fnac.com/a13957967/Frederic-G-Marand-Le-langage-Go-Les-fondamentaux-du-langage">cet excellent livre de référence</a> en français de Frédéric G. Marand (FGM pour les intimmes). 👏🏼</p><h3 id="un-p-tit-exemple-">Un p'tit exemple 😆</h3><p>On va se créer un petit projet Go tout simple avec un fichier <strong>.txt</strong> et <strong>.html</strong> pour l'exemple.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">mkdir embed &amp;&amp; cd $_

tree
.
├── static
│   └── index.html
├── example.txt
└── main.go</code></pre><figcaption>Exemple de projet Golang (contenu)</figcaption></figure><p>Notre code sera socké dans le fichier <code>main.go</code>. Go nous offre 3 façons d'intégrer du contenu dans un binaire : </p><ul><li>Sur type <code>string</code></li><li>Sur type <code>byte</code></li><li>Sur type <code>FS</code></li></ul><p>On va explorer chaque type, un par un, histoire de rendre plus visuel la chose! 😜</p><figure class="kg-card kg-code-card"><pre><code class="language-go">package main

import (
	_ "embed"
	"fmt"
)

func main() {
    //go:embed example.txt
    var s string
    fmt.Println(s)
}
</code></pre><figcaption>main.go</figcaption></figure><p>Pour spécifier quelle variable va contenir le contenu du fichier statique <strong>example.txt</strong>, on va utiliser un commentaire uniquement lu par le compilateur Go. Ce commentaire est <code>//go:embed</code> suivit du nom de votre fichier. A noter qu'il ne faut surtout pas qu'il y ait d'espace entre "//" et "go", l'espace transformerait la chose en commentaire standard du langage. 🤗</p><p>Ainsi dans notre fichier, on retrouve le contenu suivant :</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">Hello with embed package! 😜</code></pre><figcaption>example.txt</figcaption></figure><p>Et donc maintenant si on exectute notre programme :</p><pre><code class="language-bash">$ go run main.go
Hello with embed package! 😜</code></pre><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/yJFeycRK2DB4c" width="480" height="384" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/yJFeycRK2DB4c"></a></p><!--kg-card-end: html--><p>Ok, c'est cool me direz-vous, maintenant voyons plutôt comment embarquer tout un répertoire avec <code>embed.FS</code>. 😎</p><figure class="kg-card kg-code-card"><pre><code class="language-go">
package main

import (
	"embed"
	"fmt"
	"html/template"
	"os"
)

func main() {
	//go:embed static/*
	var assetData embed.FS
	t, err := template.ParseFS(assetData, "static/index.html")
	if err != nil {
		fmt.Println(err)
	}
	templateData := struct {
		Title string
	}{
		Title: "File inside Go binary",
	}
	t.Execute(os.Stdout, templateData)
}

</code></pre><figcaption>main.go</figcaption></figure><p><code>embed.FS</code> nous permet d'intégrer une arborescence de fichiers statiques, c'est-à-dire, dans notre cas, d'embarquer le répertoire <strong>static</strong> dicté par la directive <code>//go:embed static/*</code>.</p><p>Ce répertoire, comme vous avez pu le constater plus haut ne possède qu'un fichier : <code>index.html</code>, bien sûr, ça fonctionne avec tout un ensemble. 😜</p><p> D'ailleurs ce fichier possède le contenu suivant :</p><figure class="kg-card kg-code-card"><pre><code class="language-index.html">&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;{{$.Title}}&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Go is so cool!!!!&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><figcaption>index.html</figcaption></figure><p>Les patterns de la directive ne peuvent pas contenir de "." ou ".." ni commencer par un slash pour déclarer un chemin vers un répertoire.</p><p>Pour correspondre à tout ce qui se trouve dans le répertoire courant, il faut utiliser le "*" (comme ici : <code>//go:embed static/*</code> ). 😅</p><p>Et donc : </p><pre><code class="language-bash">$ go run main.go 
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;File inside Go binary&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Go is so cool!!!!&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><!--kg-card-begin: html--><iframe src="https://giphy.com/embed/1BFEEIo4h1BuTH8eqP" width="480" height="403" frameborder="0" class="giphy-embed" allowfullscreen></iframe><p><a href="https://giphy.com/gifs/theoffice-episode-3-the-office-tv-1BFEEIo4h1BuTH8eqP"></a></p><!--kg-card-end: html-->]]></content:encoded></item></channel></rss>