JESUISUNGEEK.COM - Bidouilles2022-10-15T08:24:27+02:00urn:md5:80fcbbbeeb78d335e0ba1eaeec99fb37DotclearConnexion en LDAPS avec Icingaurn:md5:09ce0dac9aabf317caf6b181d701f1342016-05-24T12:30:00+02:002016-05-24T12:56:26+02:00Jean-Baptiste LangloisBidouillesicingaldaplinux<p>Authentification sur Icinga via un serveur LDAP nécessitant un certificat</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/.icinga-ssl_s.png" alt="Icinga avec LDAPS" style="float:left; margin: 0 1em 1em 0;" title="Icinga avec LDAPS, mai 2016" /> Ce problème m'a été posé au bureau, et comme je n'ai pas trouvé de page traitant de ce problème, j'en détaille la configuration.<br />
Le serveur LDAPS utilisé dans ma société est permissif et autorise les connexions sans certificats. Il est être remplacer par un serveur forçant la connexion via un certificat en SHA-256. Quant à moi, je suis chargé de m'occuper de la migration correcte pour le serveur <a href="https://www.icinga.org/" hreflang="fr">Icinga</a>. La plupart des applicatifs dans ma société étant basé sur Java, plus qu'un certificat, il s'agit d'un TrustKeyStore (JKS) qui est fourni pour réaliser la migration.<br />
Dans Icinga, l'authentification LDAP s'effectue à travers Icinga-Web. A savoir dans les fichiers suivants (dans le cas d'une installation par défaut) :</p>
<ul>
<li><strong>/usr/share/icinga-web/app/modules/AppKit/config/auth.xml</strong></li>
<li><strong>/etc/icinga-web/conf.d/auth.xml</strong></li>
</ul>
<p>On y trouve la partie suivante :</p>
<pre class="brush: xml">
<setting name="provider">
<ae:parameter name="openldap-ldap1">
<ae:parameter name="auth_module">AppKit</ae:parameter>
<ae:parameter name="auth_provider">Auth.Provider.LDAP</ae:parameter>
<ae:parameter name="auth_enable">true</ae:parameter>
<ae:parameter name="auth_authoritative">true</ae:parameter>
<ae:parameter name="auth_create">true</ae:parameter>
<ae:parameter name="auth_update">true</ae:parameter>
<ae:parameter name="auth_map">
<ae:parameter name="user_firstname">givenName</ae:parameter>
<ae:parameter name="user_lastname">sn</ae:parameter>
<ae:parameter name="user_email">email</ae:parameter>
</ae:parameter>
<ae:parameter name="ldap_allow_anonymous">false</ae:parameter>
<ae:parameter name="ldap_dsn">ldaps://serveur1:636</ae:parameter>
<ae:parameter name="ldap_start_tls">false</ae:parameter>
<ae:parameter name="ldap_basedn">ou=people,dc=societe</ae:parameter>
<ae:parameter name="ldap_binddn">uid=userdn,ou=Applis,dc=societe</ae:parameter>
<ae:parameter name="ldap_bindpw"><![CDATA[mot_de_passe_userdn]]></ae:parameter>
<ae:parameter name="ldap_filter_user"><![CDATA[(&(uid=__USERNAME__))]]></ae:parameter>
</ae:parameter>
</setting>
</pre>
<p>Le paramètre <code>ldap_start_tls</code> semble attirant mais malheureusement ne correspond pas à mon cas où le serveur s'attend à trouver un certificat client sur la machine interrogeant l'annuaire.<br />
En fait, après plusieurs recherches, j'ai réalisé que Icinga-Web délègue l'intégralité du processus de connexion LDAP à PHP, en se basant sur les fonctions <a href="http://php.net/manual/fr/function.ldap-connect.php" hreflang="en">ldap_connect()</a> et <a href="http://php.net/manual/fr/function.ldap-search.php" hreflang="en">ldap_search()</a>, elles-mêmes s'appuyant sur la configuration locale.<br /></p>
<h3>Récupération du certificat</h3>
<p>Comme indiqué, je pars d'un <a href="https://en.wikipedia.org/wiki/Keystore" hreflang="en">Keystore</a> duquel je dois extraire le certificat nécessaire. Tout d'abord, je récupère l'alias du certificat que je compte extraire :</p>
<pre>
[root@icinga]# keytool -list -keystore mon_keystore.jks -storepass mot_de_passe_keystore
</pre>
<p>Ensuite, j'extrais le certificat (au format PEM) du Keystore (j'ai choisi le répertoire par défaut pour y stocker le certificat) :</p>
<pre>
[root@icinga]# keytool -exportcert -keystore mon_keystore.jks -storepass mot_de_passe_keystore -rfc -alias alias_du_certificat > /etc/openldap/cacerts/alias_du_certificat.pem
[root@icinga]# chmod 644 /etc/openldap/cacerts/alias_du_certificat.pem
</pre>
<p>Et je vérifie si l'algorithme de ce certificat est bien, comme demandé du SHA-256.</p>
<pre>
[root@icinga]# openssl x509 -text -noout -in /etc/openldap/cacerts/alias_du_certificat.pem | grep Algorithm
Signature Algorithm: sha256WithRSAEncryption
Public Key Algorithm: rsaEncryption
Signature Algorithm: sha256WithRSAEncryption
</pre>
<h3>Configuration du client LDAP</h3>
<p>Comme je l'ai dit plus haut, Icinga-Web se base, à travers PHP, sur la configuration locale, à savoir, <ins>l'environnement de l'utilisateur exécutant Apache</ins> (généralement <strong>www</strong>) :</p>
<pre>
[www@icinga]$ cat > ~/.ldaprc << EOF
TLS_REQCERT never
TLS_CACERT /etc/openldap/cacerts/alias_du_certificat.pem
EOF
</pre>
<p>On peut alors tester le bon fonctionnement de cette configuration :</p>
<pre>
[www@icinga]$ ldapsearch -H ldaps://serveur2:636 -d 1 2>&1 | grep TLS
TLS: loaded CA certificate file /etc/openldap/cacerts/alias_du_certificat.pem.
TLS: certificate [CN=server2,OU=0002,O=SOCIETE,C=TEST] is valid
...
</pre>
<p>Si le résultat est concluant, ne pas oublier de <ins>redémarrer Apache</ins>.</p>
<h3>Reconfiguration de Icinga-Web</h3>
<p>Finalement, je modifie le fichier auth.xml de Icinga-Web, et je vide le cache.</p>
<pre>
[icinga@icinga]$ sed -i.bak 's/serveur1/serveur2/1' /etc/icinga-web/conf.d/auth.xml
[icinga@icinga]$ /usr/share/icinga-web/bin/clearcache.sh
Cachedir: /usr/share/icinga-web/cache
Deleting cache from config (69 files) ... ok
Deleting cache from Squished (4 files) ... ok
</pre>
<p>Si aucune erreur n'a été faite, on devrait pouvoir se connecter avec ses <em>credentials</em> LDAP sur l'interface graphique de Icinga-Web <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /></p>http://www.jesuisungeek.com/index.php?post/2016/05/24/Connexion-en-LDAPS-avec-Icinga#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/250Remonter les checks Icinga grâce à Rubyurn:md5:4c15f6d766824a599be4ed6a9d0930442016-02-15T11:51:00+01:002016-02-15T14:21:17+01:00Jean-Baptiste LangloisBidouillesdashingicingaruby<p><img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-api-2.PNG" alt="icinga-api-2.PNG" style="display:block; margin:0 auto;" title="icinga-api-2.PNG, fév. 2016" />Classe Ruby permettant de remonter des informations grâce à l'interface REST de Icinga-Web</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-icon.png" alt="Logo Icinga" style="float:left; margin: 0 1em 1em 0;" title="Logo Icinga, fév. 2016" />Actuellement en plein développement de modules pour <a href="http://dashing.io/" hreflang="en" title="Dashing">Dashing</a>,on m'a demandé de créer un <em>widget</em> remontant le nombre de checks réalisés en recette et passant en orange ou rouge en fonction des erreurs pouvant être remontés par <a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a>. Plus que créer un <em>widget</em>, le problème qui se pose à moi est la remonté d'informations à partir d'<a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a>. Certes, il existe une API REST qui gère cela mais la versin d'<a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a> dont je dispose est trop ancienne pour en bénéficier. Plutôt que de partir sur une mise à jour du système (On est en RedHat 5 <img src="/dotclear/themes/chestnut/smilies/hmm.gif" alt=":-/" class="smiley" /> ), j'ai préféré tabler sur l'existant et utiliser l'API disponible avec <a href="https://www.icinga.org/icinga/screenshots/icinga-web/" hreflang="en" title="Icinga-Web">Icinga-Web</a>.<br />
Néanmoins, même si l'usage de cette API est (moins ou plus) documenté, rien n'existe pour la récupération des données à partir de <a href="http://dashing.io/" hreflang="en" title="Dashing">Dashing</a>, <a href="http://rubyonrails.org/" hreflang="en" title="Ruby on Rails">Rails</a> ou tout autre application issue de Ruby (à l'opposé une fois encore, de l'API de <a href="https://www.icinga.org/icinga/icinga-2/" hreflang="en" title="Icinga2">Icinga2</a> <img src="/dotclear/themes/chestnut/smilies/sad.gif" alt=":-(" class="smiley" /> ). Du coup, j'ai décidé de développer moi-même ce type d'interface via une classe Ruby : <strong>IcingaWebParser.rb</strong> <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" />
<div class="dcnote noteclassic">
<p>L'usage de cette classe ne se limite bien sûr pas à <a href="http://dashing.io/" hreflang="en" title="Dashing">Dashing</a> et peut être utilisé dans n'importe quel programme Ruby. On peut, par exemple, imaginer un script calculant un pourcentage de disponibilité hebdomadaire en fonction de l'état renvoyé par Icinga.</p>
</div>
</p>
<h3>INSTALLATION</h3>
<p>Tout d'abord, il faut créer une clé d'authentification permettant d'accéder à l'API REST dirrectement via une URL. Pour ce faire, se connecter à l'interface d'administration d'Icinga Web et créer un nouvel utilisateur.<br />
<img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-api-1.PNG" alt="icinga-api-1.PNG" style="display:block; margin:0 auto;" title="icinga-api-1.PNG, fév. 2016" /><br /></p>
<ul>
<li><ins>User name :</ins> Remplir avec un <em>username</em> sans espace ni caractères spéciaux</li>
<li><ins>Auth via :</ins> Choisir <strong>auth_key</strong></li>
<li><ins>Authkey for API :</ins> Cliquer sur l'icône de flèches bleues pour générer une clé. Cette clé (<em>Authkey</em>) sera nécessaire lors de la connexion avec la classe Ruby.</li>
</ul>
<p><img src="http://www.jesuisungeek.com/public/pictures/divers/icinga-api-2.PNG" alt="icinga-api-2.PNG" style="display:block; margin:0 auto;" title="icinga-api-2.PNG, fév. 2016" /><br /></p>
<ul>
<li><ins>Credentials :</ins> cocher l'identifiant <strong>appkit.api.access</strong></li>
<li>Cliquer sur <strong>Save</strong> pour créer l'utilisateur.<br /></li>
</ul>
<h3>UTILISATION</h3>
<p>Avant tout, ne pas oublier d'installer la Gem <q>rest-client</q>, utilisé par <strong>IcingaWebParser.rb</strong> pour se connecter à l'API d'<a href="https://www.icinga.org/icinga/screenshots/icinga-web/" hreflang="en" title="Icinga-Web">Icinga-Web</a>. L'exemple suivant récupérera le nom de services et d'hôtes dont l'état est <strong>CRITICAL</strong>.</p>
<pre>
irb(main):001:0> require './lib/icingawebparser.rb'
=> true
irb(main):002:0> i = IcingaWebParser.new "icinga_url", "auth_key"
=> #<IcingaWebParser:0x007fa3629ec548 @url="icinga_url", @authkey="auth_key">
irb(main):003:0> i.query("service", "AND(SERVICE_CURRENT_STATE|=|2;0)", ["SERVICE_NAME", "HOST_NAME"])
=> [{:SERVICE_NAME=>"Oracle Process", :HOST_NAME=>"server1"}, {:SERVICE_NAME=>"Logs JVM", :HOST_NAME=>"server2"}]
</pre>
<p><div class="dcnote noteclassic">
<p>Les arguments pour créer une nouvelle instance sont :</p>
<ul>
<li>L'URL du serveur Icinga Web</li>
<li>La <em>Auth key</em> précédemment créée</li>
</ul>
<p></p>
</div>
La classe est attachée à ce post. La documentation complète de la classe est ici : <a href="http://www.jesuisungeek.com/public/files/etc/icingawebparser/IcingaWebParser.html">IcingaWebParser.html</a><br /><br />
<ins>Icinga utilisé :</ins> <strong>2.3.4</strong><br />
<ins>Icinga-Web utilisé :</ins> <strong>1.13.0</strong><br />
<ins>Pour en savoir plus :</ins> <strong><a href="https://wiki.icinga.org/display/Dev/Icinga-Web+REST+API">Icinga Wiki</a></strong></p>http://www.jesuisungeek.com/index.php?post/2016/02/15/Remonter-les-checks-Icinga-gr%C3%A2ce-%C3%A0-Ruby#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/248Partage si tu aimes çaurn:md5:b6e83c83179b24f73cf778a87bd1df2e2016-02-14T07:56:00+01:002016-02-15T14:23:34+01:00Jean-Baptiste LangloisBidouillesblogdotclear<p>Le retour de la vengeance du geek en retard !</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/dotclear-2-b6c7a.png" alt="Logo dotClear" style="float:left; margin: 0 1em 1em 0;" title="Logo dotClear, fév. 2016" /> Salut à tous !<br /><br />
Ca fait un bail, pas vrai ? Ca fait genre une siècle que j'ai pas posté ici, mais ça ne m'a pas empêché de bien travailler <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> Du coup, j'ai genre une tonne de messages en attente à poster, ici... J'ai la motivation ; gageons qu'elle ne m'abandonne pas en chemin <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /><br />
A ce titre, je souhaitais depuis un certain temps rajouter des icônes de partage en bas des posts comme en possède la majorité des blogs ou sites de news et n'ayant pas trouvé de plugins équivalent sur dotClear, j'avais en projet de développer mon propre plugin. Or, dehors mon hibernation, je me suis aperçu q'un plugin qui faisait <strong>exactement</strong> ce que je cherchais, était sorti : <em><a href="http://open-time.net/post/2015/07/22/Plugin-socialShare-033-pour-Dotclear" hreflang="fr" title="socialShare">socialShare</a></em>. Très simple d'usage, peu gourmand, il était parfait... sauf que je voulais ajouter un lien de partage vers <a href="https://www.linkedin.com/in/jean-baptiste-langlois-9398b12" hreflang="fr" title="LinkedIn">LinkedIn</a>. Du coup, j'ai modifié ce plugin afin qu'il permette ce partage également.<br />
Vous trouverez, ainsi, le patch pour ajouter la possibilité de partage vers LinkedIn attaché à ce post (valable pour la version 0.3.3 de <a href="http://open-time.net/post/2015/07/22/Plugin-socialShare-033-pour-Dotclear" hreflang="fr" title="socialShare">socialShare</a>).<br />
Pour l'appliquer, c'est simple : Déposer le fichier <em>plugin-socialShare-0.3.3-linked.patch</em> au même niveau que le répertoire <em>socialShare/</em> (de l'archive ZIP du plugin socialShare) et tapez la commande :</p>
<pre>
patch -p0 < plugin-socialShare-0.3.3-linkedin.patch
</pre>http://www.jesuisungeek.com/index.php?post/2016/02/14/Partage-si-tu-aimes-%C3%A7a#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/247Temporisation des sous-titresurn:md5:47d328f93c7d05ac5820f8fce7aeca292014-05-09T13:56:00+02:002014-05-09T14:02:25+02:00Jean-Baptiste LangloisBidouillesbashlinuxmacsous-titre<p>Pour les amateurs non-anglophones de séries américaines...</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/Gnome_Subtitles_Icon.png" alt="Gnome_Subtitles_Icon.png" style="float:left; margin: 0 1em 1em 0;" title="Gnome_Subtitles_Icon.png, mai 2014" />Récemment, ma femme m'a demandé quels étaient les séries à la mode en Occident. Comme elle est fan de tout ce qui est fantastique, je lui ai proposé de regarder <em><a href="http://en.wikipedia.org/wiki/Game_of_Thrones" hreflang="fr" title="Game of Thrones">Game Of Thrones</a></em> (Bon, alors, j'avoue, elle n'a que moyennement apprécié les viols et autres décapitations <img src="/dotclear/themes/chestnut/smilies/tongue.gif" alt=":-P" class="smiley" /> ). Toutefois, afin que ce soit plus facile à comprendre pour elle, j'ai décidé de chercher des sous-titres en japonais (<strong>N.B.</strong>: Monsieur Hadopi, si tu me lis, je parle ici des épisodes de <em>Game Of Thrones</em> en DVD que j'ai acheté <img src="/dotclear/themes/chestnut/smilies/whistle.gif" alt=":siffle:" class="smiley" /> Tu peux toujours venir vérifier, mais n'oublie pas d'apporter le pop-corn <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ). J'ai finalement pu trouver mon bonheur sur <a href="http://www.podnapisi.net/fr/ppodnapisi/search?sJ=11" hreflang="en" title="Podnapisi">Podnapisi</a>. A propos, il y a assez peu de sites proposant des sous-titres en japonais donc je vais rajouter cette page en lien.<br />
Toutefois, tous les sous-titres télécharger sont décalés par rapport aux épisodes que je regarde (la faute au fait que je n'ai pas les <em>Previously on Game of Thrones</em> sur ma version DVD... Du coup, c'est bien gentil mais... Strictement inutilisable !<br />
Du coup, plus que de tous réencoder à la main, j'ai décidé de créer un script qui modifie la temporisation des sous-titres ; ce script est très simple dans son fonctionnement : il a pour but de modifier toutes les données de l'entrée standard (au format <a href="http://fr.wikipedia.org/wiki/SubRip" hreflang="fr" title="SRT">SRT</a>) en les augmentant ou les diminuant d'une certaine valeur. Ainsi l'invocation est très simple :</p>
<pre>
[mithweth@himiko ~]$ retime_sub.sh -1:20 < sous_titres.srt
</pre>
<p><em>Diminue le moment d'apparition des sous-titres de 1 minute et 20 secondes (ainsi, un sous-titre devant apparaître à 3 minutes 30 seondes, apparaîtra à 2 minutes 10)</em></p>
<pre>
[mithweth@himiko ~]$ retime_sub.sh +1:0:5 < sous_titres.srt
</pre>
<p><em>Augmente le moment d'apparition des sous-titres de 1 heure et 5 secondes</em></p>
<pre>
[mithweth@himiko ~]$ retime_sub.sh -12 < sous_titres.srt
</pre>
<p><em>Diminue le moment d'apparition des sous-titres de 12 secondes</em></p>http://www.jesuisungeek.com/index.php?post/2014/05/09/Temporisation-des-sous-titres#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/239Retrouver la version de son ESXurn:md5:a521c3480d6313f398cdba0179c9f38b2014-04-07T14:29:00+02:002014-04-07T14:29:00+02:00Jean-Baptiste LangloisBidouillesperlpuppetRed Hatrubyvmware<p>Comment connaitre la version de son ESX pour déterminer la version des vmware-ools SANS installer les vmware-tools ?</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/vmware-workstation.png" alt="WMWare Workstation - Logo" style="float:left; margin: 0 1em 1em 0;" title="WMWare Workstation - Logo, fév. 2013" />VMWare, c'est bien! Avec cela, on peut tester diverses situations ou projets (comme par exemple, <a href="https://www.reactos.org/fr" hreflang="fr" title="ReactOS">ReactOS</a> <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ) sans forcément flinguer son système. Par contre, la maintenace de ce type de système tend à devenir assez laborieux pour peu que l'on doive gérer les mises à jour système (ne serait-ce pour conserver le support constructeur). C'est pour cela qu'on utilise les <q>vmware-tools</q>, ces outils bien pratiques qui permettent la gestion de l'ESX à partir d'une machine cliente. Seulement voilà ; ces outils étant très spécifiques, il est <strong>nécessaire</strong> d'installer les <q>vmware-tools</q> qui correspondent bien à la version de son ESX installé (si vous avez du temps et du pop-corn à portée de main, installer donc les <q>vmware-tools</q> d'un ESX 4.0 sur une machine géré par un ESX 5.1, c'est fendard ! <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> ). Là où ça devient franchement folklo, c'est lors d'un déploiement automatisé. En effet : plus votre parc est grand, plus il est probable d'avoir des versions différentes d'ESX. Dans ce cas, on arrive au paradoxe de l'oeuf et de la poule : une fois la VM <em>guest</em> installée, pour connaitre la version des <q>vmware-tools</q> à installer, il faudrait connaître la version de l'ESX mais cette information n'est accessible qu'à traverser les <q>vmware-tools</q>... Du coup, comment faire ?<br />
Par chance, à travers, les dizaines d'informations que nous fournis <q>dmidecode</q>, il y en a une qui va nous sauver :<br />
En effet, si on regarde attentivement le champ <em>Address</em> de la commande <q>dmidecode -t 0</q> sur une VM, on s'aperçoit que l'adresse est toujours identique, <strong>en fonction de la version de l'ESX hôte !</strong> C'est donc par cette information qu'on va pouvoir passer. On obtient donc le script ci-dessous (j'ai testé différentes VM sur différents ESX pour obtenir les valeurs indiquées) :</p>
<pre class="brush: shell">
#!/bin/sh
case $( dmidecode | grep -A4 "BIOS Information" | grep Address | awk '{ print $2 }' ) in
"0xE8480" ) echo "ESX 2.5" ;;
"0xE7C70" ) echo "ESX 3.0" ;;
"0xE7910" ) echo "ESX 3.5" ;;
"0xEA550" ) echo "ESX 4U1" ;;
"0xEA2E0" ) echo "ESX 4.1" ;;
"0xE72C0" ) echo "ESX 5" ;;
"0xEA0C0" ) echo "ESX 5.1" ;;
*) echo "Unknown version: "; dmidecode | grep -A4 "BIOS Information";;
esac
</pre>
<p>Et voilà <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> Bon, bien sûr , même si c'est fonctionnel, ce n'est pas le top d'utiliser ce type de script durant la <em>post-install</em> (sans parler que c'est difficile de le réutiliser). C'est pour cela que je fournis également la version <strong>facter</strong> afin de pouvoir l'utiliser au sein d'une installation automatisé avec Puppet et son copain Foreman</p>
<pre class="brush: ruby">
# /usr/lib/ruby/site_ruby/1.8/facter/esxversion.rb
Facter.add("esxversion") do
confine :kernel => :Linux
setcode do
case Facter::Util::Resolution.exec('dmidecode | grep -A4 "BIOS Information" | grep Address | cut -d x -f 2')
when "E8480"
"ESX 2.5"
when "E7C70"
"ESX 3.0"
when "E7910"
"ESX 3.5"
when "EA550"
"ESX 4U1"
when "EA2E0"
"ESX 4.1"
when "E72C0"
"ESX 5"
when "EA0C0"
"ESX 5.1"
else
"Unknown"
end
end
end
</pre>
<p>Une fois copié dans le répertoire qui va bien (ou <a href="http://docs.puppetlabs.com/guides/custom_facts.html" hreflang="en">déployé par puppet</a>, en placant le <em>fact</em> ci-dessus dans le répertoire <q>facter</q> du projet), le script devrait renvoyer la version correcte de l'ESX hôte s'il est appelé par un : <strong>facter esxversion</strong></p>http://www.jesuisungeek.com/index.php?post/2014/04/07/Retrouver-la-version-de-son-ESX#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/234暗記は意味?urn:md5:8a9c1adfcea3bf84356f3c11ae8cae572013-07-22T11:50:00+02:002014-05-09T06:05:36+02:00Jean-Baptiste LangloisBidouillesankidictionnaireimiwajaponaistraduction<p>Le premier billet polyglotte dans l'Histoire de ce blog ! Santé !</p> <p>L'apprentissage des langues étrangères repose avant tout sur les bons outils. Dans le cas de l'apprentissage du Japonais à partir du Français (ou du Français à partir du Japonais), ces outils sont au nombre de deux :</p>
<ul>
<li><a href="http://imiwa.pierrephi.net/" hreflang="fr" title="IMIWA?">IMIWA?</a> qui est un dictionnaire franco-japonais pour iOS</li>
<li><a href="https://ankiweb.net" hreflang="en" title="Anki">Anki</a> qui permet l'édition et la création de <em>Flashcards</em> pour potasser son vocabulaire</li>
</ul>
<p>Sans plus détaillé les qualités intrinsèques de chaque de ces deux programmes (il y a les liens ci-dessus pour cela), notons que <strong>IMIWA?</strong> est un outil de référence complet, et que <strong>Anki</strong> permet d'apprendre vite un vocabulaire... une fois qu'il est bien configuré. Car voilà le problème : comme d'habitude, le plus grand point faible de ce type de logiciels se situe entre la chaise et le clavier. En effet, même si <strong>Anki</strong> permet d'étudier à peu près n'importe quoi, il faut tout d'abord saisir ses propres <em>Flashcards</em>. Certes, il y a des <em>decks</em> de <em>Flashcards</em> déjà prêt à l'emploi sur le site officiel mais, d'expérience, pour 1000 étudiants, il y aura 1000 decks différents.<br />
Là, où le lien peut se faire avec <strong>IMIWA?</strong>, c'est que celui-ci, via des favoris et un historique référence les dernières consultations ainsi que les mots les plus consultés... ceux précisément qu'on aimerait bien étudier !<br />
Or, et, c'est tout le point de ce post, j'ai créé un moyen d'exporter la liste des favoris et d'histoirique de <strong>IMIWA?</strong> pour créer un nouveau <em>deck</em> pour <strong>Anki</strong> et ainsi obtenir le <em>deck</em> le plus pertinent possible !!<br />
<br /></p>
<ul>
<li>Dans <strong>IMIWA?</strong>, choisir l'onglet <em>Historique</em> ou <em>Signets</em></li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa1.PNG" title="imiwa1.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa1_s.jpg" alt="imiwa1.PNG" title="imiwa1.PNG, juil. 2013" /></a></p>
<ul>
<li>Cliquer sur la flèche <em>Partager</em> et sélectionner <em>Exporter</em></li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa2.PNG" title="imiwa2.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa2_s.jpg" alt="imiwa2.PNG" title="imiwa2.PNG, juil. 2013" /></a>
<a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa3.PNG" title="imiwa3.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa3_s.jpg" alt="imiwa3.PNG" title="imiwa3.PNG, juil. 2013" /></a></p>
<ul>
<li>Sélectionner l'option <q>Champs séparés par tabulations</q>. Une fenêtre s'ouvre alors pour envoyer un mail avec un fichier attaché. S'envoyer ce mail à soi-même pour récupérer ce fichier attaché.</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa4.PNG" title="imiwa4.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa4_s.jpg" alt="imiwa4.PNG" title="imiwa4.PNG, juil. 2013" /></a></p>
<ul>
<li>A partir d'un navigateur Web, charger le fichier attaché au mail sur cette page, puis cliquer sur <em>Export</em>. Le navigateur propose de télécharger un fichier CSV.</li>
<li>Importer le fichier CSV dans l'application Anki sur votre ordinateur de bureau et synchroniser vers <strong>Ankiweb</strong>.</li>
</ul>
<p><br />C'est tout ! Vous pouvez dès à présent synchroniser <strong>Anki Mobile</strong> avec les nouvelles données présentes sur <strong>Ankiweb</strong>. Bien sûr, il aurait été plus simple de l'importer directement à partir du script ci-dessous mais, comme le dit le site officiel : <q>At this time, it is not possible to add shared decks directly to your AnkiWeb account.</q><br />
<br />
ちゃんと外国語を勉強するのに、正しい道具が必要なんですけど、日本語を勉強したいフランス人(または、フランス語を勉強したい日本人)には二つあります:</p>
<ul>
<li>iOSに<a href="http://imiwa.pierrephi.net/" hreflang="fr" title="IMIWA?">IMIWA?</a>と言う日仏辞典</li>
<li>語彙を習えるようにフラッシュカードが作れる<a href="https://ankiweb.net" hreflang="en" title="Anki">Anki</a>と言うソフト</li>
</ul>
<p>その二つのソフトの使い方を言わずに(そのためにリンクがあるんだ)、両方強いソフトだけど、設定しておきます。そうです。相変わらず、そういうソフトの不利はソフトじゃなくて、席からキーボードの間にいる。確か、Ankiで何を勉強してもいいけど、自分のフラッシュカードを入れておきなければいけません。もちろん、ホームページにフラッシュカード練習リストがあるけど、みんなの習い方が違います。<br />
IMIWA?に関係があるポイントはブックマークとヒストリーで、最後の調べた言葉と一番探してる言葉は知っています。ぴったり勉強したい言葉なんです!<br />
それで、Ankiにフラッシュカード練習リストを作れるように、IMIWA?のブックマークとヒストリーのリストを輸出仕方を発明した。<br />
<br /></p>
<ul>
<li>IMIWA?で、<em>Bookmarks</em>か<em>History</em>と言うタッブを選んで下さい</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa1.PNG" title="imiwa1.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa1_s.jpg" alt="imiwa1.PNG" title="imiwa1.PNG, juil. 2013" /></a></p>
<ul>
<li><em>Share</em>と言う矢印にクリックして、<em>Export</em>を選んで下さい。</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa2.PNG" title="imiwa2.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa2_s.jpg" alt="imiwa2.PNG" title="imiwa2.PNG, juil. 2013" /></a>
<a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa3.PNG" title="imiwa3.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa3_s.jpg" alt="imiwa3.PNG" title="imiwa3.PNG, juil. 2013" /></a></p>
<ul>
<li>「Tab separated values」と言うオプションを選んで。加え付けるファイルがあるメールを送るのに、新しいウインドーが開いています。自分に送って下さい。</li>
</ul>
<p><a href="http://www.jesuisungeek.com/public/pictures/divers/imiwa4.PNG" title="imiwa4.PNG"><img src="http://www.jesuisungeek.com/public/pictures/divers/.imiwa4_s.jpg" alt="imiwa4.PNG" title="imiwa4.PNG, juil. 2013" /></a></p>
<ul>
<li>ブローザーで、そのページに加え付けたファイルを載せて、<em>Export</em>と言うボタンにクリックして。ブローザーはCSVファイルをダウンロードするのを頼みます。</li>
<li>Ankiと言うデスクトップアプリでCSVファイルを輸入して、Ankiwebにシンクロして下さい。</li>
</ul>
<p><br />それだけです!今から、Ankiwebのある新しいデータでAnki Mobileにシンクロ出来ます。確かに、直接にしたのプログラムで輸入するのが一番簡単ですけど、ホームページは言うとおりに:<q>At this time, it is not possible to add shared decks directly to your AnkiWeb account.</q><br /></p>
<hr />
<form action="http://www.jesuisungeek.com/public/files/etc/imiwa_export.php" enctype="multipart/form-data" method="post">
<table style="width:490px;">
<tr><td>Fichier à import/File to import/乗せるファイル</td><td><input type="file" name="imiwa_import" /></td></tr>
<tr><td>Insérer les kana/Insert kana/仮名を加える</td><td><input type="checkbox" name="kana" /></td></tr>
</table>
<input type="submit" name="submit" value=" Export " />
</form>
http://www.jesuisungeek.com/index.php?post/2013/07/22/anki-wa-imi#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/233ASS2SRTurn:md5:ab57c2a0cc183bf12bb0919a7ddc875a2013-07-11T13:23:00+02:002013-07-12T14:28:43+02:00Jean-Baptiste LangloisBidouillesconversionperlscriptsous-titre<p>Conversions de sous-titres du format SubStation Alpha vers le format SRT</p> <p>Recement j'ai converti ma copine à <a href="http://fr.wikipedia.org/wiki/Doctor_Who" hreflang="fr" title="Doctor Who">Doctor Who</a> <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> <br />
Alors, certes, c'est une bonne série, mais c'est quand même plus simple de la regarder dans le texte. Je me suis donc mis à la recherche de sous-titres japonais à appliquer sur le rip de mon DVD VF. Et j'ai trouvé... au format <a href="http://fr.wikipedia.org/wiki/SubStation_Alpha" hreflang="fr" title="SubStation Alpha">ASS</a> <img src="/dotclear/themes/chestnut/smilies/ouch.gif" alt=":-s" class="smiley" /> Alors, certes, le <strong>ASS</strong> propose des options sympas, des couleurs, la possibilité d'avoir une position absolue des sous-titres... Sauf que... C'est très très mal supporté, notamment par ma <a href="http://adsl.sfr.fr/internet/" hreflang="fr">NeufBox Evolution</a>, qui ne gère que le <a href="http://fr.wikipedia.org/wiki/SubRip" hreflang="fr" title="SubRip">SRT</a>. Du coup, j'ai pas vraiment eu le choix et j'ai écrit un converteur de fichiers ASS vers SRT (ce qui est bien plus rapide que de réécrire tous les sous-titres à la main, n'est-ce pas ? <img src="/dotclear/themes/chestnut/smilies/whistle.gif" alt=":siffle:" class="smiley" /> ).<br />
Je partage donc mon script ici en espérant qu'il serve à d'autres personnes qui, comme moi, se trouvent bloqués avec un format ASS qu'ils ne peuvent pas lire (le fichier est joint à ce post).<br />
L'usage est relativement simple :</p>
<pre>
# ass2srt.pl <fichier_a_convertir.ass> <fichier_converti.srt>
</pre>
<p>Et comme le format ASS est une évolution du format SSA et bien, ça arche aussi !! Que demande le peuple <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /></p>http://www.jesuisungeek.com/index.php?post/2013/07/11/ASS2SRT#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/231Localisation de projets Ruby on Railsurn:md5:418f517cb44c83e9bdcbd3baa1c687172013-07-05T16:01:00+02:002013-07-12T14:29:59+02:00Jean-Baptiste LangloisBidouillesbashi18nrailsrubyscripttraduction<p>Petit script pour simplifier l'écriture de ses fichiers de localisation</p> <p>Toujours la tête plongée dans mon projet Ruby On Rails actuel (<em>stay tuned !</em> <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> ), j'imagine parfois l'avenir où mon application sera <strong>tellement</strong> connues qu'il faudra la localiser en <em>angliche</em> et en <em>日本語</em> (et puis pleins d'autres, au programme: Quenya, Vulcain, Klingon, ...) et pour gagner du temps, j'effectue la localisation en parallèle. Pour cela j'utilise Rails <a href="http://guides.rubyonrails.org/i18n.html" hreflang="en" title="i18n">i18n</a> qui est très simple à utiliser et à configurer. Rien que la fonction !! C'est tout simplement <strong>t</strong>. Donc à la taper, on ne perd pas de temps, c'est juste <ins>UNE</ins> lettre !!<br />
Pour l'aspect fonctionnel, c'est simple, s'il ne trouve pas la chaîne correspondante dans le fichier de localisation, il <q>railise</q> sa chaîne de caractères (comprendre : il remplace les <em>underscores</em> par des espaces et il met une majuscule à la première ligne.<br />
Prenons l'exemple de la fonction suivante : <strong>t(:je_fais_un_prout)</strong> dans un contexte de traduction anglaise.</p>
<ul>
<li>Rails va chercher dans le fichier en.yml, la chaîne correspndante ; s'il la trouve, il affichera <q>I make a prout</q></li>
<li>Sinon, il affichera <q>Je fais un prout</q></li>
</ul>
<p>C'est tellement simple que je place ces fonctions <strong>t</strong> un peu partout en me disant que je remplirais le fichier de localisation <code>fr.yml</code> plus tard... Sauf que voilà... <q>Plus tard</q>, en informatique signifie souvent, comme partout ailleurs, d'ailleurs,... <q>à la saint glin-glin</q>.<br />
Pourquoi ?<br />
Parce que, comme moi, tout bon développeur est une grosse feignasse qui a une flemme de maladie quand il s'agit de rechercher tous les chaines de localisation qu'il a éparpillé un peu partout dans tous ses fichiers (dans mon cas 110 fichiers et 6160 lignes de code <img src="/dotclear/themes/chestnut/smilies/sad.gif" alt=":-(" class="smiley" /> ) et que surtout : <q>traduire, c'est pas du dév!</q><br />
C'est là où le petit programme que je viens de développer vient à point nommé. En effet, ce script se charge de chercher dans une arborescence <em>Ruby On Rails</em>, les fichiers susceptibles d'accueillir des chaines de localisation de les extraire et de chercher un squelette de fichier de localisation avec. Dès lors que tous les chaînes ont été extraites, il ne reste plus qu'à traduire le fichier de la langue désirée. Pas mal, non ? <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /></p>
<pre class="brush: bash">
#!/bin/sh
# by Jean-Baptiste LANGLOIS
# Tested under RoR 3.2.3
DIRECTORY=`pwd`
APPEND=0
usage()
{
cat << _EOF_
Usage: `basename $0` [-a] [-d <directory>] <language>
where:
<language> localized language on two digits (en, fr, etc.)
Options:
-d <directory> RoR application directory (default: current directory)
-a appending localization file if exists
-h this help page
_EOF_
}
while getopts "d:ah" opt; do
case $opt in
d) DIRECTORY=$OPTARG;;
a) APPEND=1;;
h) usage && exit 1 ;;
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ]; then
usage
exit 1
fi
LANGUAGE=$1
FICHIER=$DIRECTORY/config/locales/$LANGUAGE.yml
[ $APPEND -eq 0 ] && echo "$LANGUAGE:" > $FICHIER
find $DIRECTORY -name "*.rb" -o -name "*.erb" | \
xargs grep -h "t(:" | \
sed 's/^.*t(:\([^), ]*\).*$/ \1:/g' | \
sort -u >> $FICHIER
</pre>
<p>Le programme prend en argument obligatoire la variable de langage (<strong>fr</strong> <em>pour Français</em>, par exemple ; cette variable créera aussi le fichier <strong>fr</strong>.yml) et en argument facultatif le répertoire où se trouve le projet Rails (par défaut, le répertoire en cours) et la possibilité d'écraser un fichier précédemment créé.
<div class="dcnote noteclassic">
<p><strong>TODO</strong><br />En plus d'extraire les chaînes de caractères, la prochaine évolution de ce script serait de <q>railiser</q> les chaines de localisation et d'initialiser les variables avec. Ainsi, si les chaines sont bien créés, il n'y aurait alors même pas besoin de modifier le fichier de localisation.
</p>
</div>
</p>http://www.jesuisungeek.com/index.php?post/2013/07/05/Localisation-de-projets-Ruby-on-Rails#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/230Installation et configuration d'un clusterurn:md5:c78d41a47ae2b126195d7564a42166872013-05-09T16:12:00+02:002016-07-07T12:57:30+02:00Jean-Baptiste LangloisBidouillesclustergpllinuxredhat<p>Depuis un certain temps, je m'intéresse à la Haute Disponibilité et jusqu'à présent, je n'ai jamais eu le loisir d'installer mon propre cluster. Je comble donc ici ma propre ignorance.</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/.lvs4p-200_t.jpg" alt="LVS Project Logo" style="float:left; margin: 0 1em 1em 0;" title="LVS Project Logo, mai 2013" /><strong>Cluster</strong> ! Le mot est lancé et il fait peur !! Mot compliqué et lié à des termes abscons comme <q>Node</q> ou <q>Concentrateur</q>. Et puis, sur le marché, ça fait sérieux et ça coute cher, donc c'est clairement pas le truc à refiler à des débutants !!<br />
... Enfin, c'est l'idée que j'en avais, car au final, c'est pas si compliqué que ça ; tout ce qu'il faut, ce sont des bonnes connaissances en réseau.<br />
<br />
<ins>Qu'est-ce que j'appelle ici <em>Cluster</em> ?</ins><br />
Il s'agit d'un mécanisme double, permettant l'accès à une information quel que soit l'état de mes ressources. Ainsi, je veux pouvoir être en état d'accéder à ce que je souhaite même si la moitié de mon infra est morte. Pour cela, trois notions sont habitellement associés :</p>
<ul>
<li>Le <ins>cluster failover</ins> qui permet de basculer sur une ressource secondaire si le serveur primaire en <em>down</em></li>
<li>Le <ins>load balancer</ins> qui permet de répartir équitablement l'usage des ressources pour ne pas laisser tout s'executer sur la même (ce qui permet d'une part, de ne pas la faire flancher trop rapidement et, d'autre part, d'avoir de meilleures perfs)</li>
<li>La <ins>redondance</ins> d'information entre les ressources constituant le cluster afin de ne pas perdre de données en cas de bascule (légérement hors-sujet, je dois l'avouer, mais fortement lié à l'architecture désirée)<br /></li>
</ul>
<p><br />
<ins>Un peu de vocabulaire</ins><br /></p>
<ul>
<li>On appelle <em>node</em>, le serveur effectuant la tâche demandé par le client. C'est sur ce serveur que l'applicatif désiré par le client se trouve.<ins>Un peu de vocabulaire</ins><br /></li>
<li>On appelle <em>node</em>, le serveur effectuant la tâche demandé par le client. C'est sur ce serveur que l'applicatif désiré par le client se trouve.</li>
<li>On appelle <em>concentrateur</em> (on voit aussi le terme de <em>directeur</em>, parfois), le serveur prenant en charge la requête du client et la répartie en fonction de la charge (<em>load balancer</em>) ou de l'état des <em>Nodes</em> (<em>failover</em>).</li>
</ul>
<p>On le voit ici (et également dans le schéma ci-dessous), le concentrateur ne fait juste office de <q>passerelle intelligente</q> se s'occupe que de router les paquets sur les nodes les plus adaptés. Pour l'utilisateur, c'est transparent (car il se connecte toujours via la même IP) mais il est fort probable que les divers traitements demandés soient gérés par des serveurs différents.<br /></p>
<ul>
<li>On appelle <em>concentrateur</em> (on voit aussi le terme de <em>directeur</em>, parfois), le serveur prenant en charge la requête du client et la répartie en fonction de la charge (<em>load balancer</em>) ou de l'état des <em>Nodes</em> (<em>failover</em>).</li>
</ul>
<p>On le voit ici (et également dans le schéma ci-dessous), le concentrateur ne fait juste office de <q>passerelle intelligente</q> se s'occupe que de router les paquets sur les nodes les plus adaptés.<br /></p>
<p><ins><strong>0. Présentation de l'infrastructure</strong></ins><br />
<a href="http://www.jesuisungeek.com/public/pictures/real/cluster-apache.png" title="Infrastructure Cluster"><img src="http://www.jesuisungeek.com/public/pictures/real/.cluster-apache_m.jpg" alt="Infrastructure Cluster" style="display:table; margin:0 auto;" title="Infrastructure Cluster, mai 2013" /></a>
Ce que je souhaite réaliser ici est l'un des usages les plus communs pour un cluster : un serveur Web doit être <em>up</em> 100% du temps. Pour ce faire, on monte un cluster avec 2 nodes strictement identiques dans leur configuration : même serveur Apache, même version, et même SGBDR (Car dès lors que l'on a un petit site Web, on a forcément besoin d'une base de données). La difficulté ici, est que si un node tombe,comment se passera le stockage dans le base de données ? Même question pour quand le node remontera ? Ici, on a beaucoup de chances, car MySQL gère un type de connexion Maître/Maître qui permet la mise-à-jour du cluster quel que soit le node sur lequel les données ont été écrites.<br />
Au regard du schéma, je sens poindre une question : <q>Oui, mais si le concentrateur tombe, comment qu'on fait ?</q> Question très judicieuse mais qui ne sera pas abordé ici (sachez toutefois que des solutions existent). Dans le cas présent, j'ai postulé que le Concentrateur, c'est le petit frère de Rambo, il a fait le Viet-Nam, la Thailande, la Corée du Nord, alors merde, c'est pas une petit coupure de courant qui va le faire chier !!<br />
<br />
N'ayant pas des masses de matos, j'ai cloné 2 fois la même VM sur <a href="https://www.virtualbox.org" hreflang="fr" title="Virtual Box">VirtualBox</a> de façon à avoir des machines strictement identiques. Tout juste ai-je rajouté MySQL et Apache sur les deux nodes.<br />
<br />
<strong><ins>1. Autoriser le transfert des paquets sur Concentrateur</ins></strong><br />
Pour ceux qui ont déjà monté des <em>gateway</em>, cette opération devrait déjà être réalisé <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> Il s'agit juste d'autoriser le transfert des paquets du sous-réseau des nodes, vers le réseau global. En effet, comme le montre le schéma au-dessus, le concentrateur a deux interfaces pour permettre le NAT entre les deux réseaux. Du coup, il suffit d'autoriser le transfert de paquet et de rajouter une règle de NAT à iptables :</p>
<pre>
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
</pre>
<p>A noter que, dans mon cas, l'interface vers le réseau public étant <q>eth0</q>, ma règle <em>iptables</em> route les paquets vers cette interface.<br />
<br />
<ins><strong>2. Préparation des nodes</strong></ins><br />
Dès lors que le <em>forwarding</em> des paquets a été autorisés, on peut tenter d'accéder au réseau global à partir des nodes (en reconfigurant <strong>/etc/resolv.conf</strong>, vous pouvez même faire vos mises à jour <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ).</p>
<pre>
ping 192.168.1.1
</pre>
<p>Si le ping répond comme il faut, il ne reste plus qu'à bloquer le transfert de paquets <ins><strong>SUR</strong></ins> cette machine, puis créer une page bidon pour tester Apache (j'ai utilisé <code>ip addr show</code> car l'IP apparaît bien, mais n'importe quoi fera l'affaire)</p>
<pre>
echo 0 > /proc/sys/net/ipv4/ip_forward
ip addr show > /var/www/html/index.html
service httpd restart
</pre>
<p><ins><strong>3. Installation load balancer</strong></ins><br />
Pour la mise en place de ma solution de <em>load balancing</em>, comme souvent, de nombreuses possibilités s'offraient à moi. Dans le cas présent, j'ai décidé d'utiliser <a href="http://www.linuxvirtualserver.org" hreflang="en" title="Linux Virtual Server">LVS</a> car c'est un projet récent, sympa et bien supporté. En plus, les RPMs existent et sont déjà diffusés par Red Hat <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /></p>
<pre>
[root@localhost ~]# yum install ipvsadm
</pre>
<p>Une fois LVS, installé, il faut charger ses modules dnas le noyau mais <ins>attention !</ins> Des modules supplémentaires doivent être défini. En effet, ce qui rend un Concentrateur spécial et qui fait de lui plus qu'une gateway est sa capacité à définir sur quel node doit être envoyé les informations transmises. Pour cela, plusieurs algorithmes de décisions existent tels que le <em>Round Robin</em> (RR, accès séquentiel) ou le <em>Weighted Round Robin</em> (WRR, accès séquentiel ou une node de poids double est deux fois plus sollicité que les autres). Dans mon cas, j'ai décidé de rester sur du <em>Round Robin</em> classique.</p>
<pre>
[root@localhost ~]# modprobe ip_vs
[root@localhost ~]# modprobe ip_vs_rr
[root@localhost ~]# ipvsadm -A -t 192.168.1.35:80 -s rr
[root@localhost ~]# ipvsadm -a -t 192.168.1.35:80 -r 192.168.0.2:80 -m -w 1
[root@localhost ~]# ipvsadm -a -t 192.168.1.35:80 -r 192.168.0.3:80 -m -w 1
</pre>
<p>Je charge donc les modules nécessaires et précise à <strong>ipvsadm</strong> que l'algorithme de décision sur le port 80 (puisqu'on tente de faire un cluster avec un serveur Web) se fera sur la base de <em>Round Robin</em>. Ensuite, j'ajoute des serveurs à cette règle de clusters en faisant du NAT vers les ports 80 de mes deux nodes avec un poids de 1.<br />
<div class="dcnote noteclassic">
<p>Comme on ne fait que du <em>Round Robin</em>, on n'a, <em>a priori</em>, pas besoin de spécifier un poids quelconque. Toutefois, par défault, LVS ne prendra pas en compte un node de poids 0 (ce qui, d'ailleurs, se tient)</p>
</div>
Voilà, la configuration du <em>load balancer</em> est terminée !! Facile, non ?<br />
<br />
<ins><strong>4. Test avec le poste client</strong></ins><br />
Il ne reste donc plus qu'à tester le fonctionnement. Pour cela, à partir du poste client (une machine hors du cluster), je lance plusieurs <strong>curl 192.168.1.35</strong> vers le concentrateur qui redirige tout ça vers les différents nodes. Un résultat équivalent à celui ci-dessous devraient confirmer le bon fonctionnement du cluster :</p>
<pre>
iMac-de-Jean-Baptiste-Langlois:~ mithweth$ curl 192.168.1.35
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 08:00:27:d3:5b:e9 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.2/24 brd 192.168.0.255 scope global eth0
inet6 fe80::a00:27ff:fed3:5be9/64 scope link
valid_lft forever preferred_lft forever
iMac-de-Jean-Baptiste-Langlois:~ mithweth$ curl 192.168.1.35
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 08:00:27:6c:73:0a brd ff:ff:ff:ff:ff:ff
inet 192.168.0.3/24 brd 192.168.0.255 scope global eth0
inet6 fe80::a00:27ff:fe6c:730a/64 scope link
valid_lft forever preferred_lft forever
</pre>
<p>On voit bien que, alors qu'on effectue le même appel, la valeur affichée est différente.<br />
<br />
<ins><strong>5. Haute disponibilité</strong></ins><br />
<div class="dcnote noteimportant">
<p>A faire APRES conf du load balancer : En effet, l'idée est d'ajouter ou supprimer des enresgistrements à ipvsadm en fonction de l'état des serveurs, donc il faut qu'auparavant <strong>ipvsadm</strong> soit correctement configuré.</p>
</div>
Dans le cas de mise en Haute Disponibilité d'un cluster, la plupart du temps, c'est <a href="http://www.linux-ha.org/wiki/Heartbeat" hreflang="en" title="Heartbeat">Heartbeat</a> qui est la solution recommandée. Toutefois, bien que connu et supporté, Heartbeat gère surtout l'état d'un node (<em>up</em> ou <em>down</em>) mais pas l'état d'un <em>daemon</em> installé sur ce node. Or, dans mon cas, je me moque de savoir si mon serveur tombe, dès lors que Apache fonctionne correctement. Pour superviser l'état de service et déclencher des scripts sous certaines conditons, j'ai pris le parti d'utiliser plutôt <a href="https://mon.wiki.kernel.org/index.php/Main_Page" hreflang="en" title="Mon">Mon</a>. Celui-ci peut vérifier l'état de plusieurs <em>daemons</em> ou l'état de certains flux réseaux, et le signaler ou bien exécuter un script pour, par exemple, le relancer. Dans notre cas présent, il faudrait que si Apache ne répond pas, le node inhérent soit retiré de la liste de <strong>ipvsadm</strong>.<br />
Pour installer MON, on peut très bien télécharger et recompiler les sources, mais j'ai trouvé des packages RPM de la dernière version (mon-1.2.0-8.el6.i686.rpm ou mon-1.2.0-8.el6.x86_64.rpm) que j'ai attaché à ce post. Toutefois, comme les RPMs semblent avoir été compilé avec les pieds, voici comment installer le RPM qui va bien sur votre RedHat de vos rêves ; Ne vous inquiétez pas, ça marche !! (Au moins avec ma CentOS 6.4 <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> ).</p>
<pre>
yum -y install perl-CPAN make gcc pam-devel # Installe pkg de dev
perl -MCPAN -e 'install "Time::HiRes"; install "Time::Period"; install "Convert::BER"; install "Authen::PAM"'
rpm -ivh --nodeps mon-1.2.0-8.el6.x86_64.rpm # ne pas oublier le --nodeps
yum -y remove make gcc pam-devel # desInstalle pkg de dev
</pre>
<p><strong>Mon</strong> est désormais bien installé. Il ne reste plus qu'à configurer le fichier de configuration de Mon <code>/etc/mon/mon.cf</code>. Copier ainsi le fichier ci-dessous, en changeant l'IP des ondes à la ligne <q>hostgroup</q></p>
<pre>
cfbasedir = /etc/mon
pidfile = /var/run/mon.pid
statedir = /var/lib/mon/state.d
logdir = /var/lib/mon/log.d
dtlogfile = /var/lib/mon/log.d/downtime.log
alertdir = /usr/lib64/mon/alert.d
mondir = /usr/lib64/mon/mon.d
maxprocs = 20
histlength = 100
randstart = 60s
authtype = pam
userfile = /etc/mon/userfile
hostgroup servers 192.168.0.2 192.168.0.3
watch servers
service http
interval 5s
monitor http.monitor
period wd {Sun-Sat}
upalert ha.alert
alert ha.alert
</pre>
<p>En fait, la partie importante est situé dans <code>watch <hostgroup_name></code>. Ici, la configuration précise de faire le test d'état du port 80 toutes les 5 secondes du Dimanche à Samedi sur les serveurs du <em>hostgroup</em> et qu'en cas d'erreur lancer le script <q>ha.alert</q>. En cas de rétablissement après une panne, il faudra relancer le script <q>ha.alert</q>.
<div class="dcnote noteclassic">
<p>En fait, en cas de rétablissement d'un service, le script indiqué est toujours exécuté avec le paramètre <code>-u</code>, ce qui permet de différencier les actions à effectuer dans un seul et même script.</p>
</div>
Ce script <q>ha.alert</q> n'apparait toutefois pas dans le répertoire <code>/usr/lib64/mon/alert.d</code> pour la simple et bonne réponse que c'est un script que j'ai fait moi-même : si un des <em>daemons</em> générant une réponse sur le port 80 (Apache) le script désactive l'enregistrement de <strong>ipvsadm</strong> permettant le routage vers le mode concerné. Cette désactivation consiste à changer le poids de ce routage de 1 à 0 et vice versa en cas de rétablissement du <em>daemon</em>.</p>
<pre class="brush: bash">
#!/bin/sh
read SERVER
WEIGHT=0
while getopts "s:g:h:t:l:u" opt; do
case $opt in
u) WEIGHT=1;;
s) SERVICE=$OPTARG;;
*) ;;
esac
done
GW=`grep GATEWAY /etc/sysconfig/network | cut -d = -f 2`
IFACE=`netstat -rn | grep $GW | awk '{print $NF;}'`
DFTIP=`grep IPADDR /etc/sysconfig/network-scripts/ifcfg-$IFACE | cut -d = -f 2`
logger -i -p local3.info -t mon "node $SERVER weight is now $WEIGHT"
ipvsadm -e -t $DFTIP:$SERVICE -r $SERVER:$SERVICE -m -w $WEIGHT
</pre>
<p>Il faut donc copier le script ci-dessus, le nommer <q>ha.alert</q>, lui donner les droits d'exécution et redémarrer <strong>mon</strong>.</p>
<pre>
chmod a+x /usr/lib64/mon/alert.d/ha.alert
service mon restart
</pre>
<p><br />
<strong><ins>6. Réplication de MySQL</ins></strong><br />
Comme indiqué plus haut, peu importe le serveur Apache avec lequel on communique, il faut que les données échangées avec la base de données soient les mêmes pour donner l'illusion qu'un unique serveur est à l'oeuvre. Pour cela, la réplication de Maitre à Maitre de MySQL va nous aider. Tout comme Apache, il faut que la configuration des nodes concernés soit strictement la même, ainsi la configuration suivante est à reporter sur chacun des nodes.<br />
<br /><ins>Node 1</ins><br />
<br />
Ajouter la ligne suivante dans <code>/etc/sysconfig/iptables</code></p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
</pre>
<p>Ajouter les lignes suivantes dans le fichier <code>/etc/my.cnf</code> (Configuration MySQL)</p>
<pre>
server-id=2
log-bin=mysql-bin
</pre>
<p>On redémarre alors <strong>iptables</strong>, <strong>mysqld</strong> et on se connecte au serveur MySQL où on va créer un utilisateur spécifiquement pour la réplication (changer le <code><mot de passe></code> par le mot de passe de votre choix)</p>
<pre>
mysql> grant replication slave on *.* to 'replication'@'%' identified by '<mot de passe>';
mysql> change master to master_host='192.168.0.2', master_port=3306, master_user='replication', master_password='<mot de passe>';
mysql> slave start;
</pre>
<p><br />
<br /><ins>Node 2</ins><br />
<br />
Ajouter la ligne suivante dans <code>/etc/sysconfig/iptables</code></p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
</pre>
<p>Ajouter les lignes suivantes dans le fichier <code>/etc/my.cnf</code> (Configuration MySQL)</p>
<pre>
server-id=3
log-bin=mysql-bin
</pre>
<p>On redémarre alors <strong>iptables</strong>, <strong>mysqld</strong> et on se connecte au serveur MySQL où on va créer un utilisateur spécifiquement pour la réplication (changer le <code><mot de passe></code> par le mot de passe de votre choix)</p>
<pre>
mysql> grant replication slave on *.* to 'replication'@'%' identified by '<mot de passe>';
mysql> change master to master_host='192.168.0.3', master_port=3306, master_user='replication', master_password='<mot de passe>';
mysql> slave start;
</pre>
<p><br />La réplication est enfin configurée ! Pour le vérifier il suffit de taper, dans la console MySQL, la commande suivante :</p>
<pre>
mysql> show slave status\G
</pre>
<p>Si, parmi les instructions retournés, les deux lignes suivantes apparaissent, c'est que la réplication est fonctionnelle.</p>
<pre>
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
</pre>http://www.jesuisungeek.com/index.php?post/2013/05/09/Installation-et-configuration-d-un-cluster#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/228Pixel-Arturn:md5:c6743b8e95e153ad95e46467d8f49ce82013-03-07T06:27:00+01:002013-03-15T19:22:38+01:00Jean-Baptiste LangloisBidouilleshtml5javascript<p>Petit moyen d'obtenir de jolis pixel-art avec la fonction getImageData de HTML5</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/.pixelme_s.jpg" alt="JB pixelisé" style="float:left; margin: 0 1em 1em 0;" title="JB pixelisé, mar. 2013" />Un style graphique que j'adore, c'est vraiment le Pixel-Art ! Avec la mode du <strong>8 bits</strong>, plus une image devient pixelisée et carrée, plus elle est <q>cool</q>. C'est pour cela que j'ai souhaité me faire un avatar en pixel-art sauf que j'avais oublié une chose : je suis une vraiment tanche en dessin ! Et bien entendu, n'ayant pas la patience de colorier pixel par pixel une image, j'étais un peu bloqué.<br />
Toutefois, ces temps-ci, développant un peu en <a href="http://fr.wikipedia.org/wiki/HTML5" hreflang="fr" title="HTML5">HTML5</a> (<code>canvas</code>, ça tue !!), j'ai découvert tout un ensemble de possibilités graphiques plutôt pratique.<br />
Plus que tout, l'élément que j'utilise actuellement massivement pour mon projet perso (<em>Stay tuned!</em> J'en dirai davantage plus tard) m'a permit à lui tout seul de développer la fonction que je présente aujourd'hui : <code>data</code><br />
<code>data</code> est en fait une propriété de l'objet <code>getImageData</code>. <code>getImageData</code> a pour particularité de récupérer les informations d'une portion rectangulaire du canvas. La propriété <code>data</code> retourne un tableau unidimensionnel de taille <code>largeur * longueur * 4</code>. Pour un multiplicateur 4 ? Parce que, et c'est là tout l'intérêt, chaque pixel est divisé en quatre éléments :</p>
<ul>
<li>Rouge</li>
<li>Vert</li>
<li>Bleu</li>
<li>Alpha</li>
</ul>
<p>Ainsi, pixeliser une image consiste à prendre la couleur du pixel à une position <em>(x,y)</em> et dessiner à part de cet axe un carré dont l'arête <em>a</em> correspond à la pixelisation attendue puis recommencer l'opération aux positions <em>(x+a,y)</em> et <em>(x,y+a)</em>. Simple, non ? <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> <br />
Pour ceux pour qui les cours de géometrie datent de Mathusalem, il suffit d'utiliser la fonction suivante :</p>
<pre class="brush: js">
function pixelate(canvas, square_size) {
var ctx = canvas.getContext("2d");
var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = img_data.data;
for (var y = 0; y < canvas.height; y += square_size) {
for (var x = 0; x < canvas.width; x += square_size) {
var pos = 4 * (y * canvas.width + x);
var i0 = data[pos];
var i1 = data[pos + 1];
var i2 = data[pos + 2];
ctx.fillStyle="rgb(" + i0 + "," + i1 + "," + i2 + ")";
ctx.fillRect(x, y, square_size, square_size);
}
}
}
</pre>
<p>La fonction prend deux arguments, le canvas où opérer la pixelisation, et la taille de la pixelisation attendue. Afin de montrer la fonction en action, je l'ai couplé à un <em>timer</em> <q>setInterval</q> qui double la taille de pixelisation toutes les 200 millisecondes. Pour voir le résultat, cliquez juste sur <q>Pixeliser</q>.</p>
<script language="javascript">
function init() {
var picture = document.getElementById("picture");
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var size = 1;
ctx.drawImage(picture, 0, 0, canvas.width, canvas.height);
var timer = window.setInterval(function() {
size *= 2;
if (size<canvas.width/4) {
pixelate(canvas,size);
} else {
window.clearInterval(timer);
}
},200);
}
function pixelate(canvas, square_size) {
var ctx = canvas.getContext("2d");
var img_data = ctx.getImageData(0,0,canvas.width, canvas.height);
var data = img_data.data;
for (var y = 0; y < canvas.height; y+=square_size) {
for (var x = 0; x < canvas.width; x+=square_size) {
var pos = 4*(y * canvas.width + x);
var i0 = data[pos];
var i1 = data[pos + 1];
var i2 = data[pos + 2];
ctx.fillStyle="rgb("+i0+","+i1+","+i2+")";
ctx.fillRect(x,y,square_size,square_size);
}
}
}
</script>
</head>
<body>
<img id="picture" src="http://www.jesuisungeek.com/index.php?post/2013/03/07/public/pictures/divers/dragonemeraude5.jpg" height="512" width="640" />
<br />
<button onclick="init()">Pixeliser</button>
<br />
<canvas id="canvas" height="512" width="640">
</canvas>
http://www.jesuisungeek.com/index.php?post/2013/03/07/Pixel-Art#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/225Indentationurn:md5:c550fecfe5679c8e6cd5ab699dced0c02013-02-23T10:30:00+01:002013-03-15T20:27:27+01:00Jean-Baptiste LangloisBidouilles<p>Enfin un moyen d'obtenir un code de beau gosse !</p> <p>Récemment, j'ai pas mal développé en <a href="http://www.w3schools.com/js/default.asp" hreflang="en" title="JavaScript Tutorial">JavaScript</a> (J'expliquerai la raison ultérieurement), mais à foce de rajouter des boucles là où c'était pas prévu, de faire des tests sur des divisions par zéro auxquels on avait pas pensé, et bien on obtient un code ultra moche, plus du tout indenté ce qui soulève une question existentielle de l'humanité : <q>Elle est où la fin de cette p***n de boucle ?</q>.<br />
La seule solution ? Ré-indenter ?? Sauf que dans mon cas (et encore, je ne pense pas être une exception... <code>catch(Exception JB) { }</code> ? Ah ah, pas drôle ! <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> ), je maltraite tellement mon code que je devrais ré-indenter tous les jours (C'est ça où voir l'association <em>SOS Codes Battus</em> appeler les services sociaux <img src="/dotclear/themes/chestnut/smilies/tongue.gif" alt=":-P" class="smiley" /> ). Alors, bien sûr la question se pose sur la façon de procéder à cette ré-indentation... La manière la plus simple est de le faire à la main, mais plus le code vit, plus il grandit et plus il est chronophage de ré-indenter. C'est pour cela que j'ai pondu un petit script tout simple qui se charge de réaliser une indentation de beau gosse que si tu la montres à tes conquêtes en discothèque, tu vas conclure à coup sûr !</p>
<pre class="brush: perl">
#!/usr/bin/perl
$i=0;
while (<>) {
chomp;
s/^\s+//;
s/\s+$//;
$i-- if /\}/;
for($j=0;$j<$i;$j++) {
print " ";
}
print $_."\n";
$i++ if /\{/;
}
</pre>
<p>Et puis, comme le méta, ça tape, j'ai ré-indenté ce script avec... ce script <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> <br />
Pour le fonctionnement, ce script, une fois sauvegardé en <q>.pl</q> et avoir reçu les permissions qui vont bien (<code>chmod u+x</code>), prend un script via l'entrée standard, le ré-indente et le redirige vers la sortie standard. Comme ça, les rois du <em><a href="http://fr.wikipedia.org/wiki/Tube_(shell)" hreflang="fr" title="Pipe">pipe</a></em> vont pouvoir se faire plaisir <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> <br />
La première chose que fait ce script est de détruire toute indentations existantes, plus il la reconstruit suivant deux règles simples :</p>
<ul>
<li><q>Si je rencontre un "{", j'augmente l'indentation d'un cran</q></li>
<li><q>Si je rencontre un "}", je réduis l'indentation d'un cran</q></li>
</ul>
<p>Comme ce script gère les accolades (il aime être pris dans les bras, le polisson <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /> ), il peut s'occuper de l'indentation de langages telles que C, C++, Perl, PHP mais par contre, si on lui donne du Basic ou du BASH et bien... Bonne chance <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" />
<div class="dcnote noteclassic">
<p>Les commentaires ne sont pas gérés : si le script trouve des accolades dans les commentaires, il procédera à leur indentation... Mais bon, quand tu as un code de beau gosse, t'as pas besoin de commentaires, n'est-ce pas ? <img src="/dotclear/themes/chestnut/smilies/whistle.gif" alt=":siffle:" class="smiley" /> </p>
</div>
</p>http://www.jesuisungeek.com/index.php?post/2013/02/23/Indentation#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/224Installer Kibana par Puppet (5/5)urn:md5:5de1c917075b3c23c70052da28ac48e52013-02-11T15:50:00+01:002013-02-13T15:04:38+01:00Jean-Baptiste LangloisBidouillesforemangplkibanalinuxmrepopuppetsvn<p>Déploiement et configuration automatique de Kibana par Puppet</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/kibana-logo.png" alt="kibana-logo" style="float:left; margin: 0 1em 1em 0;" title="kibana-logo, janv. 2013" />A présent, que tout est correctement installé, il ne reste plus qu'à configurer l'ensemble pour que Kibana se déploie sans soucis.<br /></p>
<ul>
<li><strong>Configuration du <em>Foreman-Proxy</em></strong><br /></li>
</ul>
<p>L'intérêt de Foreman est la forte intégration à Puppet. En effet, une fois les deux applications correctement configurés, Puppet peut très bien être configurés intégralement à travers l'interface Web de Foreman et sans plus mettre à jour les fichiers de configuration. Foreman s'occupe de tout, automatiquement ! <img src="/dotclear/themes/chestnut/smilies/whistle.gif" alt=":siffle:" class="smiley" /> Toutefois, Foreman n'étant lui-même qu'une interface Web passive, il n'a pas les compétences pour la collecte d'information de la part de Puppet. La solution consiste à utiliser un <em>Smart Proxy</em> réalisant cette tâche... Or, le hasard faisant bien les choses, Foreman fournit justement un <em>Smart Proxy</em> personnalisé, le bien nommé <strong>Foreman-Proxy</strong> <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> (Pour ceux qui n'ont pas compris, c'est ce <em>Smart Proxy</em> que j'ai décidé de configurer)<br />
A l'instar de Foreman, Foreman-Proxy tourne grâce à Ruby et nécessite de se connecter à la base de données pour la collecte et le dépot d'informations. Ainsi, il faut installer la bibliothèque permettant à Ruby de se connecter, dans notre cas, à MySQL.</p>
<pre>
[root@sophie conf.d]# yum -q -y install ruby-mysql
[root@sophie conf.d]# service foreman-proxy restart
</pre>
<p>Le proxy écoutant sur le port 8443, il ne faut pas oublier d'ajouter une nouvelle règle pour <em>iptables</em> dans <code>/etc/sysconfig/iptables</code>.</p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8443 -j ACCEPT
</pre>
<ul>
<li><strong>Configuration du <em>Foreman-Proxy</em> et de <em>Foreman</em></strong><br /></li>
</ul>
<p>Tout d'abord, <em>Foreman</em> dispose de deux modes d'utilisations (Désolé pour les anglicismes, j'ai pas trouvé de bonne traduction <img src="/dotclear/themes/chestnut/smilies/sad.gif" alt=":-(" class="smiley" /></p>
<ul>
<li>Le <strong>mode <em>attended</em></strong> permet la gestion de machines déjà installés et sur lesquels <em>Puppet</em> est déjà installé. La configuration est plus rapide mais nécessite une intervention initiale sur les serveurs à déployer.</li>
<li>Le <strong>mode <em>unattended</em></strong> permet la gestion de machines dès l'installation, moment où sont créés les modèles d'installation (<em>Preseed</em> ou <em>Kickstart</em>). La configuration est plus complète mais permet la totale automatisation du processus de déploiement.</li>
</ul>
<p>Par défaut, Foreman s'installation en mode <em>unattended</em>, mais nécessite donc énormement d'information sur le serveur à configurer (Adresse MAC, domaine, etc.). A moins d'avoir un réel besoin d'installer des serveurs via <em>Foreman</em>, mieux vaut désactiver l'option, c'est plus rapide. Dans mon cas, ma machine cliente <em>charlotte</em> étant déjà installé, je n'en ai pas besoin et l'ai donc désactivé :</p>
<pre>
[root@sophie conf.d]# sed -i "s/:unattended: true/:unattended: false/g" /etc/foreman/settings.yaml
[root@sophie conf.d]# service httpd restart
</pre>
<p>L'avantage d'utiliser un <em>Smart Proxy</em>, c'est que cela rend vraiment la gestion de Foreman plus simple <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> En deux trois coups de Puppet à pot, on peut obtenir un environnement fonctionnel.</p>
<ol>
<li>Se connecter à Foreman avec les droits d'administrateur</li>
<li>Créer un nouveau <em>Smart Proxy</em> dont l'URL est <q>https://sophie.localdomain:8443</q></li>
<li>Dans <em>Settings</em>, changer le <em>modulepath</em> en <q>/etc/puppet/svn/modules</q></li>
<li>Dans <em>Settings</em>, changer le <em>puppet_server</em> en <q>sophie.localdomain</q></li>
<li>Dans <em>Settings</em>, changer le <em>foreman_url</em> en <q>sophie.localdomain</q></li>
<li>Dans <em>Settings</em>, changer le <em>remote_addr</em> en <q>127.0.0.1</q></li>
<li>Dans <em>Environnment</em>, cliquer sur <q>Import from Proxy</q> et importer environnements et classes</li>
</ol>
<p>C'est tout <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> Le serveur est dorénavant bien configuré ! Il ne reste qu'à ajouter des serveurs à la liste des <q>Hosts</q>.</p>
<pre>
[root@sophie ~]# puppetd -t
</pre>
<p>En saisissant la commande ci-dessus sur <em>sophie</em>, ce serveur-ci est ajouté au <em>Foreman</em>.<br /></p>
<ul>
<li><strong>Intégration de <em>charlotte</em> dans <em>Foreman</em></strong><br /></li>
</ul>
<p>Tout d'abord, comme rien n'est encore installé sur <em>charlotte</em>, il faut commencer par installer le client <em>Puppet</em> afin que ce serveur puisse communiquer avec le PuppetMaster. Le <em>package</em> nécessaire se trouvant dans les sources <a href="http://fedoraproject.org/wiki/EPEL" hreflang="en" title="EPEL">EPEL</a>, on ajoute un lien pour <em>YUM</em> vers ce dépot :</p>
<pre>
[root@charlotte etc]# cat > /etc/yum.repos.d/epel.repo << EOF
[epel]
name=epel
baseurl=http://mirrors.ircam.fr/pub/fedora/epel/\$releasever/\$basearch/
gpgcheck=1
enabled=1
gpgkey=http://mirrors.ircam.fr/pub/fedora/epel/RPM-GPG-KEY-EPEL-6
EOF
</pre>
<p>On peut alors installer le client demandé :</p>
<pre>
[root@charlotte etc]# yum -q -y install puppet
</pre>
<p>A présent, le client est installé. Toutefois, la configuration du fichier <code>/etc/puppet/puppet.conf</code> est celle par défaut et ne correct pas à la configuration présente. Il faut donc modifier ce fichier.</p>
<pre>
[root@charlotte etc]# cat >> /etc/puppet/puppet.conf << EOF
report = true
pluginsync = true
masterport = 8140
environment = production
certname = charlotte.localdomain # le FQDN du serveur client
server = sophie.localdomain # le FQDN du puppetmaster
listen = false
EOF
</pre>
<p>Il ne reste pas qu'à lancer une requête auprès du serveur Puppet...</p>
<pre>
[root@charlotte etc]# puppetd -t
</pre>
<p>...requête qui plantera lamentablement... Car, <strong>oui!</strong> <em>charlotte</em> n'ayant pas été ajouté au PuppetMaster, celui-ci refuse la connexion, prétextant qu'il ne reconnait pas ce client (ce qui n'est pas entièrement faux, il faut le reconnaître...). Toutefois, le serveur <em>sophie</em> a noté le <em>fingerprint</em> de <em>charlotte</em> et l'a placé en <q>attente de validation</q>. Ainsi, si ce serveur est considéré comme <q>validé</q>, il obtiendra l'insigne honneur de communiquer avec cette bonne <em>sophie</em>. Sur le serveur, on peut faire la liste des serveurs en <q>attente de validation</q>.</p>
<pre>
[root@sophie puppet]# puppetca -l
"charlotte.localdomain" (75:65:48:27:49:F0:6F:2C:F4:D6:B5:8B:A7:7A:EA:0C)
</pre>
<p>Il suffit alors de <q>signer</q> ce serveur (c'est-à-dire reconnaître sa clé SSH) pour qu'il soit considéré comme <q>validé</q> par le serveur</p>
<pre>
[root@sophie puppet]# puppetca -s charlotte.localdomain
</pre>
<p>Ceci étant fait, il ne reste qu'à relancer une requête auprès du serveur Puppet, via le client.</p>
<pre>
[root@charlotte etc]# puppetd -t
</pre>
<p>Tout un ensemble d'informations appraissent (heureusement en vert <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> ), preuve que le client a bien été reconnu par le serveur. Toutefois rien d'autre ne se passe... Cela s'explique par le fait que, bien que le client est reconnu, aucun module n'a été chargé à partir du serveur. Une honte ! C'est donc le moment de procéder à l'installation de Kibana <img src="/dotclear/themes/chestnut/smilies/oops.gif" alt=":oops:" class="smiley" /> <br /></p>
<ul>
<li><strong>Installation du serveur <a href="http://kibana.org/" hreflang="en" title="Kibana">Kibana</a></strong><br /></li>
</ul>
<p>Comme j'ai indiqué sur la <a href="http://www.jesuisungeek.com/index.php?post/2013/01/31/Installer-Kibana-par-Puppet-partie-1">première page de ce tutoriel</a>, <em>Kibana</em> est très simple à installer, sauf quand il n'y a pas de réseau et là, ça devient un enfer (foutues <a href="https://rubygems.org/" hreflang="en" title="Rubygems">Gems</a> <img src="/dotclear/themes/chestnut/smilies/aww.gif" alt=":-C" class="smiley" /> ). Hormi, ce fait, il faut installer des serveurs <a href="http://www.elasticsearch.org/" hreflang="en" title="ElasticSearch">ElasticSearch</a> et <a href="http://redis.io/" hreflang="en" title="Redis">Redis</a>, sans oublier <a href="http://logstash.net/" hreflang="en" title="LogStash">LogStash</a> qui a pour tâche d'expédier les flux qui vont bien là où il faut ; bref, un beau foutoir à configurer. Pour simplifier l'installation de toutes les machines, j'ai donc créé un module <q>kibana</q> pour <em>Puppet</em> et c'est ce module qui se chargera de tout installer.<br />
On télécharge donc les fichiers du module de classe et on les charge sur <em>sophie</em> grâce à <em>Subversion</em> :</p>
<pre>
[jbl@bulow ~]$ wget http://www.jesuisungeek.com/public/files/rhel/kibana-puppet.tar.gz -O - | tar zxvf - -C /répertoire/dépot/svn/local
[jbl@bulow ~]$ cd /répertoire/dépot/svn/local
[jbl@bulow local]$ svn add kibana && svn commit
</pre>
<p><div class="dcnote noteimportant">
<p>Dans le cas où, comme indiqué plus haut, il est impossible de télécharger à partir d'Internet sur notre client SVN, les fichiers d'archives sont attachés à ce post. Dans ce cas, il suffit de transférer et tout décompresser dans le répertoire du dépot SVN local avant de l'ajouter à SVN</p>
</div>
Grâce à la magie des <em>hooks</em>, le serveur SVN a été mis automatiquement à jour et il ne reste plus qu'à mettre à jour les modules gérés par <em>Foreman</em>. Pour cela, sur le <em>Foreman</em> de <em>sophie</em></p>
<ol>
<li>Dans les options, choisir l'option <q>Puppet Classes</q>, puis cliquer sur <q>Import</q> pour ajouter la nouvelle classe <code>kibana</code>.</li>
<li>Ajouter la classe <q>kibana</q> à <code>sophie</code></li>
<li>Ajouter la classe <q>kibana::server</q> à <code>charlotte</code></li>
<li>Aller dans <em>Global Parameters</em> et ajouter une variable <q>kibana_server</q> (ici : 192.168.1.48)</li>
</ol>
<p><a href="http://www.jesuisungeek.com/public/pictures/real/kibana_-_puppetclass.png" title="Foreman - Puppet classes"><img src="http://www.jesuisungeek.com/public/pictures/real/.kibana_-_puppetclass_m.jpg" alt="Foreman - Puppet classes" style="display:block; margin:0 auto;" title="Foreman - Puppet classes, fév. 2013" /></a>
Il ne reste plus qu'à déployer les classes demandés sur <em>charlotte</em> et <em>sophie</em>. Toutefois, les deux serveurs échangeront les informations à logguer via <em>Redis</em>, ne pas oublier d'ouvrir le port nécessaire (ici <q>161</q>) en ajoutant une nouvelle règle pour <em>iptables</em> dans <code>/etc/sysconfig/iptables</code>.</p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 161 -j ACCEPT
</pre>
<p>Ensuite, il ne reste qu'à relancer l'agent <em>Puppet</em> sur les deux serveurs</p>
<pre>
[root@charlotte etc]# puppetd -t
[root@sophie etc]# puppetd -t
</pre>
<p>Après que <em>Puppet</em> ait déroulé les informations de modification de configuration, il suffit d'attendre quelqus minutes (le temps que l'ensemble des logs commence à être remonté) pour se connecter à <code>http://charlotte:8080</code> pour constater le bon fonctionnement de l'ensemble.<br />
<a href="http://www.jesuisungeek.com/public/pictures/real/kibana_-_logs.png" title="Kibana - Fonctionnement"><img src="http://www.jesuisungeek.com/public/pictures/real/.kibana_-_logs_m.jpg" alt="Kibana - Fonctionnement" style="display:block; margin:0 auto;" title="Kibana - Fonctionnement, fév. 2013" /></a></p>http://www.jesuisungeek.com/index.php?post/2013/02/11/Installer-Kibana-par-Puppet-%285/5%29#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/223Installer Kibana par Puppet (4/5)urn:md5:d679ca8b0018e44611531f2d56e4f85b2013-02-04T15:15:00+01:002013-02-11T15:50:50+01:00Jean-Baptiste LangloisBidouillesforemangpllinuxmrepopuppetRed Hatsvn<p>Dans cette partie, on s'occupe du <em>versioning</em> des modules Puppet via SVN</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/kibana-logo.png" alt="kibana-logo" style="float:left; margin: 0 1em 1em 0;" title="kibana-logo, janv. 2013" /></p>
<ul>
<li><strong>Installation et configuration de <a href="http://subversion.tigris.org/" hreflang="en" title="Subversion">Subversion</a></strong><br /></li>
</ul>
<p>Il ne reste plus qu'à configurer notre serveur Subversion. Celui-ci permettra de mettre à jour plus facilement les modules puppet à partir de machines clients et de garder une trace des modifications apportées aux fichiers. Afin de gagner du temps dans la configuration, tout comme <em>Puppermaster</em>, <em>Foreman</em> et <em>MRepo</em>, celui-ci fonctionne grâce à <em>Apache</em> via le module <strong>SVN/WebDAV</strong>. Pource faire, on commecne tout d'abord par installer les packages nécessaires :<br /></p>
<pre>
[root@sophie conf.d]# yum -y -q install subversion mod_dav_svn
</pre>
<p>L'installation du package <em>mod_dav_svn</em> va, au passage, créé un fichier de configuration pour <em>Apache</em>. Dès lors, il n'y a qu'à le modifier :</p>
<pre>
[root@sophie conf.d]# cat >> /etc/httpd/conf.d/subversion.conf << EOF
<Location /svn>
DAV svn
SVNPath /var/svn
AuthType None
</Location>
EOF
</pre>
<p>Il ne reste plus qu'à affecter les droits du dépot SVN à l'utilisateur <strong>apache</strong> puisqu'à travers WebDAV, c'est cet utilisateur qui gérera l'envoi et le téléchargement des données du dépot :</p>
<pre>
[root@sophie conf.d]# mkdir -p /var/svn
[root@sophie puppet]# chown -R apache:apache /var/svn/*
[root@sophie puppet]# chmod -R 775 /var/svn/*
[root@sophie conf.d]# service httpd restart
[root@sophie conf.d]# svnadmin create /var/svn
</pre>
<p>Maintenant que <em>Subversion</em> est installé, il faut créer le dépot local et y déposer les premiers modules développés. Ces modules sont ceux qui ont été créés par <em>Foreman</em> et se situe par défault dans le répertoire <code>/etc/puppet/modules</code>. On peut très bien imaginer prendre le répertoire <code>/etc/puppet</code> comme racine pour <em>Subversion</em>, mais on devra alors se farcir les fichiers de configuration de Puppet. Le plus propre est donc de mettre tous les modules dans un répertoire <code>/etc/puppet/svn</code> qui deviendra notre racine <em>Subversion</em>.</p>
<pre>
[root@sophie puppet]# mkdir /etc/puppet/svn/
[root@sophie puppet]# mv /etc/puppet/modules/ /etc/puppet/svn/
[root@sophie puppet]# chown -R apache:apache /etc/puppet/svn/
[root@sophie puppet]# chmod -R 775 /etc/puppet/svn/
</pre>
<p>Tout est prêt pour envoyer la liste des module vers le serveur <em>Subversion</em>. Toutefois, comme <em>Subversion</em> est généré à travers <em>Apache</em>, il faut que ce soit l'utilisateur Apache qui est tous les droits sur le serveur SVN. Pour ce faire, il faut que l'utilisateur <strong>apache</strong> ajoute les modules au dépot :</p>
<pre>
[root@sophie puppet]# su apache -s /bin/sh
sh-4.1$ svn co http://sophie/svn /etc/puppet/svn/
sh-4.1$ cd /etc/puppet/svn/ && svn add * && svn commit
sh-4.1$ exit
</pre>
<p>Les données étant dorénavant correctement envoyés au serveur, n'importe quel serveur peut télécharger et modifier ces modules, sous couvert que le dit serveur ait accès au port 80 du serveur Foreman/Puppet/MRepo/SVN (ca commence à faire long <img src="/dotclear/themes/chestnut/smilies/ouch.gif" alt=":-s" class="smiley" /> ). A-t'on fini ?? NON ! Ne surtout pas qu'on a modifié la configuration du serveur puppet ; les modules, auparavant dans <code>/etc/puppet/</code>, sont maintenant dans <code>/etc/puppet/svn/</code> et il faut donc l'indiquer dans le fichier de configuration de Puppet, puis le redémarrer :</p>
<pre>
[root@sophie puppet]# sed -i "s@/etc/puppet/modules@/etc/puppet/svn/modules@g" /etc/puppet/puppet.conf
[root@sophie puppet]# service puppet restart
</pre>
<p><br /></p>
<ul>
<li><strong>Mises à jour automatiques de <em>Subversion</em></strong><br /></li>
</ul>
<p>Waow, c'est cool, on a un serveur <em>Subversion</em> flambant et ça claque ! Mais dans les faits, si à chaque modification d'un utilisateur, l'administrateur est obligé de se connecter pour balancer un <code>svn update</code> dans <em>/etc/puppet/svn</em>, non seulement c'est pas pratique mais la mauvaise humeur de l'admin va aller croissante avec le nombre de développeurs... Le mieux, ça serait de pouvoir mettre à jour automatiquement le répertoire des modules Puppet dès qu'un <code>svn commit</code> est soumis par un des utilisateurs. Pour cela nous avons utilisé les <q>hooks</q> de <em>Subversion</em> qui (contrairement au capitaine éponyme qui sert à rien) permettent de déclencher des actions au moment de certains événements. Dans notre cas, <ins>après</ins> qu'un <code>svn commit</code> a eu, on souhaite qu'un <code>svn update</code> soit executé dans le répertoire <em>/etc/puppet/svn</em> du serveur. On va utiliser pour cela le <q>hook</q> (Rien à voir non plus à voir avec un quelconque bibliothèque d'une quelconque Université de l'Invisible) dit de <strong>post-commit</strong>.</p>
<pre>
[root@sophie hooks]# cat > /var/svn/hooks/post-commit << EOF
#!/bin/sh
cd /etc/puppet/svn
svn up
EOF
[root@sophie hooks]# chmod 775 /var/svn/hooks/post-commit
</pre>
<p><br /></p>
<ul>
<li><strong>Un <q>hook</q> pour les corriger tous (facultatif}</strong><br /></li>
</ul>
<p>Un <strong>post-commit</strong>, c'est bien, mais un <strong>pre-commit</strong>, c'est mieux ! OK, la mise à jour automatique du dépot est très pratique pour le serveur mais, comme à terme, le serveur est censé déployé un code sur tous ses clients, que se passera-t-il si le code est <ins>faux</ins> ?? La question se pose d'autant plus qu'à présent, le code est mis à jour sur le serveur <ins>sans aucune vérification</ins>. C'est pour cela que j'ai mis en place ce <q>hook</q> de <strong>pre-commit</strong> qui contrôle la syntaxe des fichiers soumis. Si celle-ci n'est pas conforme, le <em>commit</em> est interrompy jusqu'à correction du code erroné.</p>
<pre>
[root@sophie puppet]# yum -y -q install rubygem-puppet-lint
</pre>
<p>On installe donc tout d'abord <em><a href="https://github.com/rodjek/puppet-lint" hreflang="en" title="Puppet-Lint">puppet-lint</a></em> donc la seule tâche est de vérifier le code Ruby soumis pour Puppet. C'est grâce à lui que mon code Ruby sera toujours propre et joli à lire <img src="/dotclear/themes/chestnut/smilies/smile.gif" alt=":-)" class="smiley" /></p>
<pre>
[root@sophie hooks]# cat > /var/svn/hooks/pre-commit << EOF
#!/bin/sh
REPOS="\$1"
TRANS="\$2"
for FILE in \$(svnlook changed -t "\$TRANS" "\$REPOS" | cut -b 5-); do
if [ "\${FILE: -3}" == '.pp' ]; then
svnlook cat -t "\$TRANS" "\$REPOS" "\$FILE" > /tmp/puppet-lint.check
puppet-lint --no-autoloader_layout-check /tmp/puppet-lint.check >&2
RETVAL=\$?
rm -f /tmp/puppet-lint.check
if [ \$RETVAL -ne 0 ]; then
echo "Commit error: Syntax error in \$FILE" >&2
exit 1
fi
fi
done
exit 0
EOF
[root@sophie manifests]# chmod 775 /var/svn/hooks/pre-commit
</pre>http://www.jesuisungeek.com/index.php?post/2013/02/04/Installer-Kibana-par-Puppet-partie-4#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/221Installer Kibana par Puppet (3/5)urn:md5:6d5106ffe42df55defb5431f8f2afa1a2013-02-03T13:45:00+01:002013-02-11T16:07:01+01:00Jean-Baptiste LangloisBidouillesgpllinuxmrepopuppetRed Hat<p>Installation du serveur MRepo avec en prime la configuration pour Apache !</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/kibana-logo.png" alt="kibana-logo" style="float:left; margin: 0 1em 1em 0;" title="kibana-logo, janv. 2013" />Si on regarde un peu les commentaires qu'on peut trouver sur le site de <a href="http://kibana.org" hreflang="en" title="Kibana">Kibana</a>, on remarquera que tout le monde s'accorde à dire que c'est super simple à installer. Seulement, voilà : quand on a accès à Internet à partir de son serveur, oui, c'est simple. Mais quand on n'a pas de réseau (comme c'est souvent le cas dans un réseau d'entreprise), ça devient un enfer : les librairies ne correspondent pas, des dépendances manquants sont encore à télécharger, impossible de trouver une source correcte pour <q>bundler</q>, ... De surcroit, même avec le réseau, si l'objectif est de faire un module Puppet, les commandes de téléchargement et de compilation font qu'il est quasi-impossible d'écrire un module (ou tout du moins, d'écrire un module <ins>propre</ins>). C'est pour tout cela que j'ai créé des RPMs pour toutes les dépendances et fichiers nécessaires !<br /></p>
<ul>
<li><strong>Installation de <a href="http://dag.wieers.com/home-made/mrepo/" hreflang="en" title="MRepo">MRepo</a></strong><br /></li>
</ul>
<p>Bien entendu, même avec des RPMs, il faut pouvoir les diffuser jusqu'au serveur sur lequel kibana doit être installé. C'est à cet effet que j'installe MRepo qui permet de créer son propre dépôt de RPM local. C'est à travers ce dépot que seront installés les RPMs nécessaires au projet.<br />
Tout d'abord, on installe les packages nécessaires :</p>
<pre>
[root@sophie ~]# yum -y -q install createrepo mrepo
</pre>
<p>Par défaut, un répertoire <em>/etc/mrepo.conf.d</em> est créé pour y stocker la configuration de nos sources de dépôt. C'est donc là qu'on y copie notre fichier de configuration de notre dépôt <em>kibana</em> :</p>
<pre>
[root@sophie mrepo.conf.d]# cat > /etc/mrepo.conf.d/kibana.conf << EOF
[kibana]
name = Kibana for \$arch
arch = x86_64
metadata = repomd repoview
kibana = file:///var/data/mrepo/kibana
EOF
</pre>
<p>Il faut comprendre de ce fichier de configuration qu'un dépot nommé <em>kibana</em> sera créé à partir des RPMs trouvés dans <em>/var/data/mrepo/kibana</em>. On crée donc ce répertoire et on y télécharge les RPMs nécessaires :</p>
<pre>
[root@sophie mrepo.conf.d]# mkdir -p /var/data/mrepo
[root@sophie mrepo.conf.d]# wget http://www.jesuisungeek.com/public/files/rhel/kibana-repo.el`facter lsbmajdistrelease`.tar.gz -O - | tar zxvf - -C /var/data/mrepo
[root@sophie mrepo.conf.d]# chown -R apache:apache /var/mrepo/kibana-x86_64/kibana/
[root@sophie mrepo.conf.d]# chmod -R 755 /var/mrepo/kibana-x86_64/kibana/
</pre>
<p><div class="dcnote noteclassic">
<p>L'instruction utilisé dans le <em>wget</em> <code>facter lsbmajdistrelease</code> renvoie <strong>5</strong> pour une <em>CentOS 5</em> (ou <em>RHEL 5</em>) et <strong>6</strong> pour une <em>CentOS 6</em> (ou <em>RHEL 6</em>). Cela permet de télécharger uniquement le bon jeu de RPMs.</p>
</div>
<div class="dcnote noteimportant">
<p>Dans le cas où, comme indiqué plus haut, il est impossible de télécharger à partir d'Internet sur le serveur sur lequel on souhaite installer <em>Kibana</em>, les fichiers d'archives sont attachés à ce post. Dans ce cas, il suffit de transférer et tout décompresser dans le répertoire <em>/var/data/mrepo</em></p>
</div>
Il ne reste plus qu'à générer le dépôt désiré :</p>
<pre>
[root@sophie mrepo.conf.d]# mrepo -ugv
</pre>
<p>Normalement, si tout se passe bien, on obtient un affichage comme celui-ci :</p>
<pre>
kibana-x86_64: Updating Kibana for x86_64
kibana-x86_64: Mirror packages from file:///var/data/mrepo/kibana to /var/mrepo/kibana-x86_64/kibana
kibana-x86_64: Repository kibana changed (new: 24, removed: 0)
kibana-x86_64: Distribution updated (new: 24, removed: 0)
Sending mail to: root@localhost
kibana-x86_64: Generating Kibana for x86_64 meta-data
mrepo: kibana-x86_64: Version of createrepo could not be found. Assuming newer than 0.4.6.
kibana-x86_64: Create repomd repository for kibana
</pre>
<p>Où on voit bien apparaitre que 24 nouveaux packages ont été ajoutés au dépot (ce qui correspond au nombre des RPMs téléchargés). Le dépôt étant bien généré, il faut à présent, modifier la configuration de Apache pour que les machines clients puissent télécharger les RPMs désirés par HTTP. Par convention, j'ai décidé d'affecter le port 8080 au MRepo, mais n'importe quel autre port fera l'affaire. Dans tous les cas, il ne pas oublier d'autoriser les flux entrants vers ce port.<br />
Dans mon vas, j'ai ajouté la ligne suivante au fichier <em>/etc/sysconfig/iptables</em> :</p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
</pre>
<p>Pour en revenir à MRepo, la modification est assez simple : en effet, l'installation du RPM de MRepo a ajouté des fichiers de configuration dans le répertoire <em>/etc/httpd/conf.d</em> donc il n'y a plus qu'à les modifier :</p>
<pre>
[root@sophie conf.d]# cat >> /etc/httpd/conf.d/mrepo.conf << EOF
Listen 8080
<VirtualHost sophie:8080>
DocumentRoot /var/www
</VirtualHost>
EOF
</pre>
<p>Et bien, entendu, ne pas oublier de redémarrer Apache, de façon pour que la nouvelle configuration soit prise en compte :</p>
<pre>
[root@sophie conf.d]# service httpd restart
</pre>
<p>En se connectant à l'adresse <code>http://sophie:8080/mrepo</code>, on peut voir désormais naviguer parmi l'arborescence du dépôt.
<img src="http://www.jesuisungeek.com/public/pictures/real/.kibana-mrepo_m.jpg" alt="MRepo configuré" style="display:block; margin:0 auto;" title="MRepo configuré, fév. 2013" /><br /></p>http://www.jesuisungeek.com/index.php?post/2013/02/03/Installer-Kibana-par-Puppet-partie-3#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/220Installer Kibana par Puppet (2/5)urn:md5:a5ae3b2157af088114ee0ee01a24a7c92013-02-01T13:23:00+01:002013-02-11T16:04:21+01:00Jean-Baptiste LangloisBidouillesforemangpllinuxpuppetRed Hat<p>Suite de nos avantures sur l'installation d'un serveur centralisé de log</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/kibana-logo.png" alt="kibana-logo" style="float:left; margin: 0 1em 1em 0;" title="kibana-logo, janv. 2013" />Suite de nos aventures avec, aujourd'hui, la configuration de Foreman et Puppet sur <strong>sophie</strong>.<br />
<br /></p>
<h3><ins><strong>Un peu de sécurité</strong></ins><br /></h3>
<p><br /></p>
<ul>
<li><strong>Ajout de règles <a href="http://www.netfilter.org/projects/iptables/" hreflang="fr" title="iptables">iptables</a></strong><br /></li>
</ul>
<p>Au terme de l'installation de Foreman, il faudrait que le service Web soit accessible de <strong>bulow</strong> car c'est plus facile d'avoir de gérer une interface Web avec un navigateur moderne plutôt qu'un truc en ligne de commande comme <em><a href="http://lynx.browser.org/" hreflang="en" title="Lynx Browser">lynx</a></em> (En plus, je suis pas sûr que <em>lynx</em> et l'Ajax soient très copains...) donc il va falloir permettre les connexions extérieures à <strong>sophie</strong>.<br />
Pour ce faire, il faut ajouter les lignes suivantes dans le fichier <code>/etc/sysconfig/iptables</code> :</p>
<pre>
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT
</pre>
<p><div class="dcnote noteimportant">
<p>Attention à bien ajouter ces lignes <ins>avant</ins> l'instruction COMMIT car, dans le cas contraire, elles ne seront pas prises en compte</p>
</div>
Ne pas oublier de rédemarrer pour appliquer la nouvelle configuration :</p>
<pre>
[root@sophie foreman]# service iptables restart
</pre>
<ul>
<li><strong>Désactivation de <a href="http://doc.fedora-fr.org/wiki/SELinux" hreflang="fr" title="SELinux">SELinux</a></strong><br /></li>
</ul>
<p>Dans le même ordre d'idées, <a href="https://www.phusionpassenger.com/" hreflang="en" title="Phusion Passenger">Passenger</a> et SELinux n'étant pas très enclins à se faire des bisous, j'ai désactivé SELinux. Si quelqu'un trouve une meilleure péthode, je suis tout ouïe...<br /></p>
<pre>
[root@sophie httpd]# echo 0 >/selinux/enforce
[root@sophie httpd]# cat > /etc/selinux/config << EOF
SELINUX=disabled
SELINUXTYPE=targeted
EOF
</pre>
<p><br /></p>
<h3><ins><strong>Attaquons les choses sérieuses !</strong></ins><br /></h3>
<p><br />
Bon, voilà que les prérequis sont là, on va pouvoir attaquer les choses sérieuses et installer Puppet et Foreman. En fait, si on se réfère au site de Foreman, on comprend que ce qui est nommé <a href="http://theforeman.org/manuals/1.1/quickstart_guide.html" hreflang="en" title="Foremand installer">installeur</a> est en fait une ligne d'instruction permettant de télécharger et d'installer Foreman grâce à Puppet. Ainsi, la première chose à faire est de s'occuper de Puppet.<br />
<br /></p>
<ul>
<li><strong>Installation de <a href="http://www.mysql.fr/" hreflang="fr" title="MySQL">MySQL</a></strong><br /></li>
</ul>
<p>C'est pour cela qu'on installe... MySQL !! En effet, tant Puppet que Foreman ont besoin d'une base de données pour enregistrer leur configuration, donc on a, avant toute chose, besoin d'une base de données. A noter que <em>sqllite</em> fait aussi l'affaire mais je ne connais pas du tout ce SGBDR (D'ailleurs, c'est un SGBDR ?? <img src="/dotclear/themes/chestnut/smilies/ouch.gif" alt=":-s" class="smiley" /> )<br />
Du coup, on commence par un petit :</p>
<pre>
yum install mysql-server
</pre>
<p>Suivi d'un non moins utile :</p>
<pre>
mysqladmin -u root password 'MotDePasseTropBienDeLaMort'
</pre>
<p>car, à l'installation (et alors là, ça dépend de : la version, du packageur <ins>et</ins> de l'âge du capitaine !), il arrive que le mot de passe <code>root</code> ne soit pas (ou mal) défini, donc c'est mieux de le resaisir. A noter que j'ai pris <q>MotDePasseTropBienDeLaMort</q> comme mot de passe parce que j'aime trop les blagues trop LOL, mais on est libre de choisir n'importe quel autre mot de passe (tel que <q>Pastis51</q> ou encore <q>Biere1664</q>). Il ne reste plus qu'à créer la base de données pour <em>puppet</em> ainsi que l'utilisateur qui aura le droit de se connecter à cette base :</p>
<pre>
[root@puppet ~]# mysql -u root -p
mysql> CREATE DATABASE puppet;
mysql> GRANT ALL ON puppet.* TO puppet@localhost IDENTIFIED BY 'MotDePasseTropBienDifferentDeRoot';
</pre>
<p><br /></p>
<ul>
<li><strong>Installation de <a href="https://puppetlabs.com/" hreflang="en" title="PuppetLabs">Puppet</a></strong><br /></li>
</ul>
<p>Histoire de ne pas réinventer la roue, on peut gagner du temps en installant directement les RPMs existants de Puppet. Comme les RPMs sont packagés par EPEL, on ajoute ce dépot :</p>
<pre>
[root@sophie yum.repos.d]# cat /etc/yum.repos.d/epel.repo
[epel]
name=epel
baseurl=http://mirrors.ircam.fr/pub/fedora/epel/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=http://mirrors.ircam.fr/pub/fedora/epel/RPM-GPG-KEY-EPEL-6
</pre>
<p>Puis on installe les outils nécessaires :</p>
<pre>
[root@sophie yum.repos.d]# yum -y -q install puppet-server puppet
</pre>
<p>Bon, avec le jeu des dépendances, <em>puppet</em> <q>seul</q> n'est pas installé. <a href="http://augeas.net/" hreflang="en" title="Augeas">Augeas</a> et <a href="http://projects.puppetlabs.com/projects/facter" hreflang="en" title="Facter">Facter</a> font partie de la bande, aussi, hein (Facter est d'ailleurs fondamental pour l'installation de Foreman). Il ne reste plus qu'à configurer <em>puppet</em> de façon à ce qu'il puisse stocker la configuration de chaque client dans notre toute nouvelle et pimpante base de données MySQL. <br />
Pour ce faire, il éditer le fichier /etc/puppet/puppet.conf, puis repérer la partie débutant par <code><a href="http://www.jesuisungeek.com/index.php?post/2013/02/01/master" title="master">master</a></code> et y ajouter les lignes suivantes (En prenant soin, bien entendu de faire correspondre <q>MotDePasseTropBienDifferentDeRoot</q> avec le mot de passe défini pour l'utilisateur <em>puppet</em> dans la base de données éponyme).<br /></p>
<pre>
storeconfigs = true
dbadapter = mysql
dbuser = puppet
dbpassword = MotDePasseTropBienDifferentDeRoot
dbserver = localhost
dbsocket = /var/lib/mysql/mysql.sock
</pre>
<p><br /></p>
<ul>
<li><strong>Installation de <a href="http://theforeman.org/" hreflang="en" title="Foreman">Foreman</a></strong><br /></li>
</ul>
<p>MySQL est fonctionnel, Puppet se porte comme un charme, le grand moment est arrivé 8-) ! Installons Foreman!<br />
Comme indiqué précédemment, Foreman nécessite une installation correct de Puppet car c'est au travers de ce dernier qu'il s'installe. En effet, l'installeur (tel qu'il est appelé), télécharge dans un premier temps les packages nécessaire à partir de Git, puis applique la configuration grâce à Puppet.</p>
<pre>
export MODULE_PATH="/etc/puppet/modules/common"
mkdir -p $MODULE_PATH
for mod in apache foreman foreman_proxy git passenger puppet tftp xinetd; do
mkdir -p $MODULE_PATH/$mod
wget http://github.com/theforeman/puppet-$mod/tarball/master -O - | tar xzvf - -C $MODULE_PATH/$mod --strip-components=1
done;
</pre>
<p><div class="dcnote notetip">
<p>Dans le cas où l'on doit réaliser une installation de Foreman <ins>sans</ins> réseau, il faut télécharger les fichiers suivants :</p>
<pre>
http://github.com/theforeman/puppet-apache/tarball/master
http://github.com/theforeman/puppet-foreman/tarball/master
http://github.com/theforeman/puppet-foreman_proxy/tarball/master
http://github.com/theforeman/puppet-git/tarball/master
http://github.com/theforeman/puppet-passenger/tarball/master
http://github.com/theforeman/puppet-puppet/tarball/master
http://github.com/theforeman/puppet-tftp/tarball/master
http://github.com/theforeman/puppet-xinetd/tarball/master
</pre>
<p>et les décompresser dans le répertoire <code>/etc/puppet/modules/common</code> du serveur Puppet.
</p>
</div>
Il ne reste plus qu'à faire executer les fichiers de configuration par Puppet :</p>
<pre>
echo include puppet, puppet::server, foreman, foreman_proxy | puppet apply --modulepath /etc/puppet/modules/common
</pre>
<p>La bécane devrait turbiner pendant quelques minutes, affichant de temps en temps des jolis messages en couleurs (tant que c'est que du bleu, c'est bon <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ).
<div class="dcnote notewarning">
<p>
Si le programme sort avec une erreur indiquant qu'il n'arrive pas à trouver le Fact <code>fqdn</code>, éditer le fichier <code>/etc/syconfig/network</code>, puis rajouter un domaine au <em>hostname</em> (<q>.localdomain</q>, ça claque <img src="/dotclear/themes/chestnut/smilies/mdr.gif" alt=":mdr:" class="smiley" /> ), avant de redémarrer et de relancer la commande d'installation.
</p>
</div>
Durant l'installation, diverses tâches sont effectués : modification des scripts Puppet, configuration d'Apache (Foreman s'exécutant via Passenger, l'installeur configure Apache en ce sens) ou encore ajout d'un repository de RPMs pour la gestion de plugins pour Foreman. De ce fait, peu de tâches sont nécessaires en post-install. Toutefois, il faut faire s'interfacer Foreman avec l'environnement existant. Dans notre cas, il faut qu'il puisse s'enregistrer dans la base de données. <br />
On installe donc le plugin de gestion de MySQL :</p>
<pre>
[root@sophie foreman]# yum -y -q install foreman-mysql2
</pre>
<p>Puis, on lui précise les informations de connexion à la base de données précedemment créée (En prenant soin, bien entendu de faire correspondre <q>MotDePasseTropBienDifferentDeRoot</q> avec le mot de passe défini pour l'utilisateur <em>puppet</em> dans la base de données éponyme) :</p>
<pre>
[root@sophie foreman]# cat > /etc/foreman/database.yml << EOF
production:
adapter: mysql2
database: puppet
username: puppet
password: MotDePasseTropBienDifferentDeRoot
host: localhost
socket: "/var/lib/mysql/mysql.sock"
EOF
</pre>
<p><div class="dcnote noteclassic">
<p>Faire bien attention à l'identation, celle-ci est primordiale, ici !</p>
</div>
On peut alors lancer la création et le remplissage des tables, puis redémarrer Apache pour prendre en compte la nouvelle configuration de Passenger.</p>
<pre>
[root@sophie foreman]# cd /usr/share/foreman
[root@sophie foreman]# RAILS_ENV=production rake db:migrate
[root@sophie foreman]# service httpd restart
</pre>
<p>Voilà, c'est installé ! Un petit <code>http://sophie</code>, à partir de <strong>bulow</strong>, fait apparaitre la fenêtre de connexion classique de Foreman. Par défault le login est <q>admin</q> et le mot de passe est <q>changeme</q>.<br />
<br />
<img src="http://www.jesuisungeek.com/public/pictures/real/kibana-foreman.png" alt="Foreman - Login" style="display:block; margin:0 auto;" title="Foreman - Login, fév. 2013" /></p>http://www.jesuisungeek.com/index.php?post/2013/02/01/Installer-Kibana-par-Puppet-partie-2#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/219Installer Kibana par Puppet (1/5)urn:md5:d110ae4b93ba3c294f104bd4b1c3f3ca2013-01-31T10:52:00+01:002016-02-15T14:20:46+01:00Jean-Baptiste LangloisBidouillesforemangplkibanalinuxlogstashpuppet<p>Pour ceux qui souhaitent monter leur serveur de log à domicile...</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/kibana-logo.png" alt="kibana-logo" style="float:left; margin: 0 1em 1em 0;" title="kibana-logo, janv. 2013" />Je parle assez peu de mon travail... Quand on me demande "ça va le boulot ?", j'ai du mal à être précis sur mon activité réelle (ma hierarchie à deja du mal a comprendre, alors, pensez, des non-techos...)<br />
Ma tâche actuelle au travail consiste à monter un serveur centralisé de logs, projet qui me tient a cœur et ce pour plusieurs raisons :<br /></p>
<ul>
<li>Les responsables projet ayant reçu l'autorisation de se connecter directement en root, il est de bon ton de surveiller tout ce qu'ils s'amusent à faire avec le serveur<br /></li>
<li>C'est motivant !<br /></li>
</ul>
<p>En effet, au-delà de l'aspect simple de monter un serveur centralisé de logs, c'est toute l'architecture qui est à penser. Comme précédemment évoqué, mon environnement de travail se compose d'un serveur Puppet qui provisionne la configuration prévue au travers d'un serveur Foreman. Bien entendu, alors qu'il serait simple de décompresser l'archive Kibana et de la copier la ou ça va bien, c'est l'intégration à l'environnement existant qui nécessite le plus de temps.<br />
Cela faisant à présent presque 2 semaines que je travaille la-dessus, je me dis que ça serait dommage de perdre l'expérience que j'ai acquise. Alors, sous couvert de la mise en place de la même archi dans mon petit chez moi (ah là là, ces geeks ! Combien de célibataires à un serveur Foreman chez soi??), je compte partager mon expérience sous forme de HOWTO.<br />
<br /></p>
<h3><ins><strong>Infrastructure :</strong></ins><br /></h3>
<p><br />
C'est la ou le bat blesse (ça y est, on n'a pas encore commencé que je présente les faiblesses du produit... Par chance, je suis pas commercial, hein <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> ). Même si j'ai une pelletée d'ordi a domicile, la grande majorité sont des portables et donc sont très mal adaptés à la configuration en tant que serveurs. C'est pourquoi, j'ai pas mal lutter pour définir quels serveurs les serveurs utilisés. Au final, voici les machines que j'utiliserai :</p>
<ul>
<li>A ma gauche, mon tout nouveau nouvel ordi basé sur un Core i5 et tout son stockage en SATA3. Spécialement acheté pour joué à SWTOR, il a été récémment réinstallé avec une CentOS 6.3, depuis que je ne joue plus ; Vainqueur incontesté du benchmark de Panneau de conf Windows 7, veuillez accueillir : <strong>sophie</strong> !!</li>
<li>A ma droite, caché tout au fond de mon placard dans un vieux disque dur USB2, une image virtuelle CentOS 6.1 (mis à jour pour l'occasion) s'executant au travers de VirtualBox, merci d'applaudir : <strong>charlotte</strong> !</li>
<li>Sans oublier, ce bon vieux <strong>bulow</strong> dont le role sera de jeter un oeil sur le bon fonctionnement de Kibana et qui sera le point d'entrée des sources que j'ai déjà développé.<br /></li>
</ul>
<p><br /></p>
<h3><ins><strong>Architecture :</strong></ins><br /></h3>
<p><br />
Au vu du peu de serveurs dont je dispose, les machines seront serveurs les unes des autres. Ainsi, alors que <strong>sophie</strong> sera serveur Puppet/Foreman pour <strong>charlotte</strong>, celle-ci sera le serveur Kibana pour les logs provenant de <strong>sophie</strong>.<br />
<img src="http://www.jesuisungeek.com/public/pictures/real/kibana-archi1.png" alt="kibana-archi1.png" style="display:block; margin:0 auto;" title="Architecture Puppet" /><br />
La configuration (déjà créé, je la joindrais aux posts concernés, histoire de ne pas réinventer la roue <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /> ) sera envoyé sur <strong>sophie</strong> à partir de <strong>bulow</strong> Cette configuration sera appliqué au serveur Foremand qui "demandera" à Puppet de la déployer sur <strong>charlotte</strong>. Cette configuration créera un nouveau <em>repository</em> local (à partir du MRepo de <strong>sophie</strong>) à partir duquel sera téléchargé les packages de Kibana et ses petits copains.<br />
<img src="http://www.jesuisungeek.com/public/pictures/real/kibana-archi2.png" alt="kibana-archi2.png" style="display:block; margin:0 auto;" title="Architecture Kibana" /><br />
Une fois la configuration prévue sera déployé (client sur <strong>sophie</strong> et serveur sur <strong>charlotte</strong>), Logstash récupérera les logs de syslog de <strong>sophie</strong> et l'enverra à Redis sur <strong>charlotte</strong>. Ces logs seront envoyés par ce même Logstash vers Elasticsearch auquel se connecte Kibana pour afficher les logs récupérés sur son interface Web.</p>http://www.jesuisungeek.com/index.php?post/2013/01/31/Installer-Kibana-par-Puppet-partie-1#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/218Personnalisation d'Anacondaurn:md5:e25c6be428ebfc139320f39a2b40439d2012-10-01T14:52:00+02:002016-02-14T11:50:18+01:00Jean-Baptiste LangloisBidouillesAnacondaKickStartLinuxRed Hat<p>RedHat ne permettant pas la saisie des IP au format w.x.y.z/n à l'installation, voici un petit patch modifiant Anaconda</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/.red-hat-logo_s.jpg" alt="Logo Red Hat" style="float:left; margin: 0 1em 1em 0;" title="Logo Red Hat, oct. 2012" />Dans le cadre de mon travail, j'ai un besoin impérieux d'installer des machines <a href="http://www.jesuisungeek.com/index.php?tag/linux">Linux</a> rapidement. <br /><br />
Pour ce faire, quand je dois installer des serveurs Red Hat, j'utilise <a href="http://fedoraproject.org/wiki/Anaconda/Kickstart" hreflang="en">KickStart</a>. A l'instar de <a href="http://wiki.debian.org/DebianInstaller/Preseed" hreflang="en">Preseed</a>, il s'agit basiquement d'un fichier de réponse qui permet donc l'automatisation de l'installation. Actuellement très abouti, cette solution permet même l'execution de scripts de pre- et de post-install, en environnement chrooté ou non. Ainsi, une fois le fichier soumi à <a href="http://fedoraproject.org/wiki/Anaconda" hreflang="en">Anaconda</a>, l'installation se déroule sans aucun intervention humaine, ce qui est bien pratique. Le fichier <a href="http://www.jesuisungeek.com/index.php?tag/kickstart">KickStart</a> peut être soumis de plusieurs façons telles que sur une disquette ou un CD mais, dans un environnement connecté d'entreprise, la solution envisagé est souvent la soumission par réseau (FTP ou HTTP). C'est là où tout se complique car la ligne de commande à saisir au boot pour lancer une installation par KickStart via le réseau est la suivante.<br /><br />
<code>linux ip=192.168.0.1 netmask=255.255.255.0 gateway=192.168.0.254 ksdevice=eth0 ks=http://192.168.0.10/ks/fichier_ks.cfg</code><br />
<br />
Pas vraiment pratique, n'est-ce pas ? (Surtout si on le tape avec un Key-mapper en QWERTY sur un clavier AZERTY <img src="/dotclear/themes/chestnut/smilies/caca.gif" alt=":caca:" class="smiley" /> )<br />
<br />
La faute en revient à Anaconda qui ne gère que deux formats de saisie réseau :<br /></p>
<ul>
<li>Format <em>Anaconda</em> : <code>ip=192.168.0.1 netmask=255.255.255.0 gateway=192.168.0.254</code></li>
<li>Format <em>PXELinux</em> : <code>ip=192.168.0.1:192.168.0.10:192.168.0.254:255.255.255.0</code><br /></li>
</ul>
<p>Bref, dans les cas, c'est plutôt horrible à taper. D'autant que, saisir d'une part l'IP, le <em>Netmask</em> et la <em>Gateway</em>, c'est trois fois plus de chances de se tromper d'un chiffre et de planter son install. Alors que, pourtant, il existe un format plus court et moins source d'erreur !! Le format <em>Bitcount</em> !!<br />
<br />
<code>linux ip=192.168.0.1/24 ksdevice=eth0 ks=http://192.168.0.10/ks/fichier_ks.cfg</code><br />
<br />
La ligne précédente a quand même plus de gueule, non ? <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /><br />
A partir de la notation <strong>192.168.0.1/24</strong>, on détermine le <em>Network</em>, le <em>Netmask</em> et la Gateway ; que demande le peuple ??
Malheureusement, Anaconda ne le gère pas en natif... C'est pour cela que j'ai écrit un patch pour Anaconda pour que l'ISO de boot comprenne cette notation.<br />
<div class="dcnote notewarning">
<p>
La convention utilisé à mon travail consiste à prendre pour <em>Gateway</em>, la dernière IP du sous-réseau (avant le <em>Broadcast</em>). Le patch a été écrit en ce sens et il faut le modifier dans les autres cas. Pour les réseaux où la <em>Gateway</em> est toujours la première adresse du sous-réseau, il faut modifier la ligne<br />
<code>uint32_t gw = (netw | ( (~ mask) & mask32) ) - 1;</code><br />
En effet il faut la remplacer par :<br />
<code>uint32_t gw = netw + 1;</code>
</p>
</div>
</p>
<p><strong>Le HOWTO ci-dessus a été écrit et testé initialement sur Red Hat 5.x, puis complété pour Red Hat 6.x.</strong> Néanmoins, Anaconda ayant pas mal changé entre les deux, le patch a été réécrit pour Red Hat 6.x. Tous les fichiers évoqués (patch et <em>packages</em> RPM sont fournis, attachés à ce billet).<br />
<br />
Comme on parle ici de patcher Anaconda, il faut comprendre qu'on va devoir récupérer les sources de l'installeur Red Hat pour pouvoir les recompiler après modifier. Il faut donc, avant toutes choses, installer les packages de développement nécessaires à la compilation</p>
<pre># yum install anaconda yum-utils gcc make dbus-glib-devel syslinux
# yum info anaconda | grep Version</pre>
<p>La commande <code>yum info anaconda</code> renvoie un numéro de version. Celle-ci est importante car il s'agit de la version correspondant au système installé. Il faut alors télécharger les sources de <em>Anaconda</em> correspondant à la version installé.</p>
<ul>
<li>Pour RedHat 5 : <a href="http://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/SRPMS/" title="http://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/SRPMS/">http://ftp.redhat.com/pub/redhat/li...</a></li>
<li>Pour RedHat 6 : <a href="http://ftp.redhat.com/pub/redhat/linux/enterprise/6Server/en/os/SRPMS/" title="http://ftp.redhat.com/pub/redhat/linux/enterprise/6Server/en/os/SRPMS/">http://ftp.redhat.com/pub/redhat/li...</a></li>
</ul>
<p>Le nom du fichier recherché ressemble à <q>anaconda-xx.x.x.x-x.src.rpm</q>.<br /></p>
<p><div class="dcnote noteclassic">
<p>
Dans le cas d'une recompilation avec RedHat 6, des dépendances nécessitent l'installation de paquetages supplémentaires, à savoir :</p>
<ul>
<li>iscsi-initiator-utils-devel,</li>
<li>newt-devel, slang-devel,</li>
<li>NetworkManager-devel,</li>
<li>NetworkManager-glib-devel,</li>
<li>device-mapper-devel,</li>
<li>libudev-devel,</li>
<li>libarchive-devel,</li>
<li>isomd5sum-src</li>
</ul>
<p>Tous ces paquetages sont, pour plus de commodités, attachés à ce mail (de plus, il sera plus aisé de les obtenir d'ici quelques années).
Une fois tous les paquetages téléchargés, ne pas oublier de compiler isomd5sum.<br /></p>
<pre># cd /usr/src/redhat/SOURCES
#tar xfj isomd5sum-*.tar.bz2
# cd isomd5sum-*/
# make
# make install</pre>
<p></p>
</div>
</p>
<p>On comment par installer les pré-requis pour Anaconda puis les sources qu'on décompresse (sur RH6, les sources se trouve dans <em>/root/rpmbuild/SOURCES</em>)</p>
<pre># yum-builddep anaconda-*.src.rpm
# rpm -ivh anaconda-*.src.rpm
# cd /usr/src/redhat/SOURCES
# tar xjf anaconda-*.tar.bz2
# cd anaconda-*/ </pre>
<p>Il ne reste plus qu'à patcher le fichier loader (Pour cela, il faut au préalable avoir télécharger le patch <em>unified</em> pour Anaconda à partir de la liste des fichiers attachés à ce post.</p>
<pre># patch -p1 < /chemin/vers/patch
# ./configure
# make</pre>
<p>Pas la peine de faire <strong>make install</strong> ! On a juste besoin des binaires <code>loader</code> et <code>init</code>, pas d'un machine de développement pour Anaconda <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" />
Pour ceux qui ont la flemme ou ceux qui ignore ce qu'est une compilation, un fichier <em>tar.gz</em> contenant les fichiers <code>loader</code> et <code>init</code> correspondant chacune des versions d'Anaconda. Merci qui ??? <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /><br />
<br />
Après avoir récupéré l'initrd à partir du CD d'install de Red Hat, il faut ouvrir cette image ramdisk pour remplacer les fichiers <code>loader</code> et <code>init</code> par ceux nouvellement compilés.
<div class="dcnote noteimportant">
<p>L'initrd pour RH6 est compressé en LZMA (via <code>xz</code>) alors que celui pour RH5 est en BZip2</p>
</div>
</p>
<pre>
# mv initrd.img initrd.img.xz
# xz --format=lzma initrd.img.xz --decompress
# mkdir initrd && cd initrd
# cpio -ivdum < ../initrd.img
# cp /usr/src/redhat/SOURCES/anaconda-*/loader/loader bin/loader
# find . -print |cpio -o -H newc | xz --format=lzma > ../initrd.img
</pre>
<p>Voilà ! Dorénavant, Anaconda comprend les commandes de type <code>linux ip=x.y.z.w/n</code> au boot !! Y'a plus qu'à replacer ce nouveau initrd dans le répertoire <code>isolinux/</code> de la bonne distribution puis de créer l'ISO bootable qui va bien et hop, ça fait des Chocapic <img src="/dotclear/themes/chestnut/smilies/biggrin.gif" alt=":-D" class="smiley" /></p>http://www.jesuisungeek.com/index.php?post/2012/10/01/Anaconda#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/210JsonDocumenturn:md5:5f0d9349946a841c8b0b5e88c9d2d6332009-11-01T19:29:00+00:002013-01-07T14:22:05+00:00Jean-Baptiste LangloisBidouillesc-sharpgpljsonwindowsxml<p>Classe de sérialisation, de gestion et d'exportation du format JSON pour C#.</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/json160.gif" alt="Logo JSON" style="float:left; margin: 0 1em 1em 0;" title="Logo JSON, oct. 2012" />JsonDocument est une classe de gestion et d'utilisation du format <a href="http://www.json.org" hreflang="en">JSON</a> (<a href="http://fr.wikipedia.org/wiki/JavaScript_Object_Notation" hreflang="fr">JavaScript Object Notation</a>) dans Visual Studio C#. Initialement, le format JSON est une structure de données utilisés en JavaScript pour représenter des objets, des tableaux et toutes sortes d'autres données. En 2005, certains en ont eu l'idée d'en faire un format d'échange de données. L'idée était lancé.
Aujourd'hui, ce type de format est d'une importance capitale car il s'oppose directement au sacro-saint XML. Bien qu'il soit d'un abord moins lisible que ce dernier, le JSON a pour lui quelques avantages : il permet de gérer des sous-structures (comme des tableaux d'objets) ce dont est incapable XML, mais surtout, il est plus petit en taille, notamment à son encapsulation à base d'accolades et de crochets. Du coup, il commence à être massivement utilisé dans le domaine de la téléphonie mobile (Blackberry et iPhone en tête), car il permet de fournir des informations via un format de taille plus faible que XML ; ainsi, l'usage de la bande passante est réduite. C'est pour cela que j'ai décidé de créer une classe pour une structure dont l'avantage initial est d'être 100% compatible avec JavaScript, ce qui est bien inutile lors d'un développement pour Visual Studio.<br />
Actuellement, la dernière version est la <strong>1.0</strong>. La seule petite limitation actuelle est la gestion des structures hiérarchiques complexes qui est indisponible lors d'une exportation vers un fichier XML. Il n'y a pas, non plus, de moyen de convertir les fichiers XML en données JSON. L'exploitation en lecture du format JSON est, quant à elle, parfaitement fonctionnelle.<br />
<a href="http://www.jesuisungeek.com/public/pictures/real/json-demo.JPG" title="Demo JSONDocument"><img src="http://www.jesuisungeek.com/public/pictures/real/.json-demo_t.jpg" alt="Demo JSONDocument" style="display:block; margin:0 auto;" title="Demo JSONDocument, oct. 2012" /></a>
<br />
<ins>Les classes de l'application :</ins></p>
<ul>
<li><strong>JsonDocument</strong></li>
</ul>
<p>La classe d'ouverture et de gestion du fichier JSON. C'est par celle-ci que l'on accède aux autres. Les méthodes principales sont :<br />
<em>Load</em> : Charge le fichier, vérifie s'il est correct, et le <em>parse</em>.<br />
<em>ExportXml</em> : Renvoi une chaîne de caractère qui correspond aux données JSON rendues au format XML.<br />
<em>Attributes</em> : Propriété renvoyant les données, une fois désérialisées.<br />
<br /></p>
<ul>
<li><strong>JsonAttributes</strong></li>
</ul>
<p>Cette classe détaille le contenu du fichier JSON, le détaille et le désérialise. Cette classe est accessible au travers d'une propriété du <em>JsonDocument</em>. Les propriétés principales sont les suivantes :<br />
<em>GetType</em> : Précise le type de données contenues dans le noeud<br />
<em>ParseValue</em> : <em>Parse</em> le noeud et renvoie son contenu<br />
<br /></p>
<ul>
<li><strong>JsonData</strong></li>
</ul>
<p>Cette classe détaille le contenu d'un noeud. On n'y accède pas directement mais à travers les identificateurs du <em>JsonDocument</em>. Les propriétés de cette classe sont :<br />
<em>Name</em> : Nom du noeud<br />
<em>Type</em> : Type du noeud<br />
<em>Value</em> : Valeur du noeud<br />
<br />
Dans les sources (Liens <em>Fichiers attachés</em> en haut de la page) est fournie la documentation détaillant les classes au format CHM (HTML compilé)</p>http://www.jesuisungeek.com/index.php?post/2009/11/01/214-jsondocument#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/206Social Linksurn:md5:f83747cf1598a794a14324f29d98eebc2008-07-15T21:42:00+00:002012-10-07T14:57:13+00:00Jean-Baptiste LangloisBidouillesdcsoclinksdotclearfacebookphpsocial linkssoclinkstwitter<p>Plugin pour DotClear 1.2 pour envoyer le lien d'un post d'un blog sur un réseau social ou de l'ajouter directement à ses favoris.</p> <p><img src="http://www.jesuisungeek.com/public/pictures/divers/.social-network-icons_s.jpg" alt="social-network-icons.jpg" style="float:left; margin: 0 1em 1em 0;" title="social-network-icons.jpg, oct. 2012" />Depuis la fin de l'année 2006, les réseaux sociaux fleurissent sur le Web. Entre les réseaux où on partage ses humeurs (<a href="http://www.facebook.com" hreflang="en">Facebook</a>), ceux où on partage ses favoris (<a href="http://del.icio.us" hreflang="en">Del.icio.us</a>) ou encore les news pour nerds (<em>stuff that matters</em>, <a href="http://slashdot.org" hreflang="en">Slashdot</a>), les manières de partager ses découvertes ou ses coups de coeur se multiplie. A ce titre, de plus en plus d'<q>utilisateurs finaux</q> adhère à ce genre de vue, mais cela demeure toujours assez compliqué pour eux pour mettre à disposition le lien qui les intéresse (Paradigme habituel du <q>copier le lien, se connecter, coller le lien, envoyer, se déconnecter</q>). L'idée sera alors de proposer au lecteur du blog (ici <a href="http://www.dotclear.net/" hreflang="fr">Dotclear</a>) une barre de liens vers les principaux réseaux sociaux afin de pouvoir partager l'information voulue en un seul clic.<br />
<img src="http://www.jesuisungeek.com/public/pictures/real/soclinks-1.png" alt="soclinks-1.png" title="soclinks-1.png, oct. 2012" /><br />
Ce genre de choses existe déjà chez Wordpress, et j'ai voulu mettre en place ce principe sur ce site, mais étrangement il n'existe pas sur Dotclear. Une solution alternative est pourtant disponible (<a href="http://www.addthis.com/" hreflang="en">AddThis</a>) mais l'ensemble n'est pas très personnalisable et, pour ainsi dire, assez moche.<br />
J'ai donc commencé à bidouiller les sources de mon <em>template</em> Dotclear et, de fil en aiguille, c'est devenu un plugin <img src="/dotclear/themes/chestnut/smilies/cool.gif" alt="8-)" class="smiley" /> <br />
<a href="http://www.jesuisungeek.com/public/pictures/real/soclinks-2.png" title="soclinks-2.png"><img src="http://www.jesuisungeek.com/public/pictures/real/.soclinks-2_s.jpg" alt="soclinks-2.png" title="L'interface principale de configuration" /></a>
<a href="http://www.jesuisungeek.com/public/pictures/real/soclinks-3.png" title="soclinks-3.png"><img src="http://www.jesuisungeek.com/public/pictures/real/.soclinks-3_s.jpg" alt="soclinks-3.png" title="Ajouter un élément" /></a>
<a href="http://www.jesuisungeek.com/public/pictures/real/soclinks-4.png" title="soclinks-4.png"><img src="http://www.jesuisungeek.com/public/pictures/real/.soclinks-4_s.jpg" alt="soclinks-4.png" title="L'aide en ligne" /></a><br />
Comme on peut le voir sur les <em>screenshots</em> ci-dessus, j'ai décidé de ne pas réinventer la roue ; j'ai donc développé mon interface de configuration en me basant sur <ins>Veni Vidi Vici</ins>, un plugin de gestion de médias. Comme la plupart des plugins Dotclear, il est relativement intuitif et ne nécessite quasiment aucun code à insérer (la création de la base de données est, par exemple, entièrement automatique). Tout ce qui vous est demandé est d'avoir un blog utilisant Dotclear <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> <br />
<br />
<strong>Présentation</strong><br />
Le plugin SocialLinks permet d'intégrer à ses billets DotClear une barre permettant d'envoyer le lien du billet lu à n'importe quel réseau social configuré au préalable. Si vous voulez, par exemple, faire connaître le <em>post</em> que vous lisez à vos contacts sur Facebook, il suffit de cliquer sur l'icône <q>Envoyer via Facebook</q> pour le faire partager. Vous pouvez, bien entendu, également utilisé SocialLinks pour enrichir vos favoris sur des sites comme Del.icio.us.<br />
<br />
<strong>Utilisation</strong><br />
Pour afficher la barre SocialLinks dans votre blog, insérez le code suivant dans vos fichiers post.php et list.php à l'emplacement où vous souhaitez le voir figurer :<br />
<code><?php dcSocialLinks::show($GLOBALS['news']); ?></code><br />
<br />
<strong>Description des options</strong><br /></p>
<ul>
<li><ins>Intitulé :</ins> Indiquez ici l'info-bulle de l'iône dans la barre de SocialLinks.<br /></li>
<li><ins>URL :</ins> Indiquez ici l'adresse internet correspondant au lien de partage du réseau social voulu. Il faut, de plus, indiquer, sur ce lien, les références aux URLs et les références aux titres. Ainsi si on veut ajouter Facebook dont le lien de partage est http://www.facebook.com/share.php?u=<url_du_site_à_partager>, on pourra taper <q>http://www.facebook.com/share.php?u=%URL%</q></li>
<li><ins>Image :</ins> Indiquez ici le chemin d'accès à l'image associée au réseau social. Ce chemin doit être relatif à votre dossier images ou bien une URL complète commençant par http:// ou par ftp://. SocialLinks est fourni avec les icônes de Del.icio.us, Digg, Facebook, Slashdot et Google.<br /></li>
</ul>
<p><br />
<strong>Options de configuration</strong><br /></p>
<ul>
<li><ins>Titre à afficher :</ins> Titre à afficher à la gauche de la barre SocialLinks. Facultatif. Par défaut, aucun titre n'est précisé.</li>
<li><ins>Label des URLs :</ins> Mot clé permettant d'indiquer à quel endroit l'URL du billet sera insérée (par défaut %URL%).</li>
<li><ins>Label des titres :</ins> Mot clé permettant d'indiquer à quel endroit le titre du billet sera insérée (par défaut %TITLE%).</li>
<li><ins>URL du site :</ins> URL du site sur lequel DotClear est installé. SocialLinks tente de le déterminé par lui-même à l'installation<br /></li>
</ul>
<p><br />
<strong>TODO</strong><br /></p>
<ul>
<li>Régler ce problème qui fait que l'on a le même rendu, que l'on soit en ISO8859-1 où en UTF-8.<br /></li>
</ul>http://www.jesuisungeek.com/index.php?post/2008/07/15/147-social-links#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/143Back to the passwordurn:md5:88e4a157001a9bf7de14a1f399ea28a82008-06-08T17:47:00+00:002012-10-07T15:47:06+00:00Jean-Baptiste LangloisBidouillesc-sharpcrackmot de passewindowszip<p>Programme pour <q>craker</q> les fichiers ZIP et retrouver le mot de passe du fichier demandé.</p> <p><img src="http://www.jesuisungeek.com/public/pictures/real/bttp.gif" alt="bttp.gif" style="float:left; margin: 0 1em 1em 0;" title="Back to the password - logo" />Récemment, j'ai retrouvé un vieux fichier ZIP sur mon ordinateur. Ignorant ce qu'il y avait dedans, j'ai décidé de l'ouvrir... Je me suis aperçu qu'un mot de passe en empêchait la lecture. Après plusieurs tentatives infructueuses, je me suis tourné vers des logiciels de <q>crack</q> de fichiers ZIP. Néanmoins, j'ai vite déchanté : les prix auxquels sont proposés ce genre de solution sont bien trop cher pour moi. L'absurdité de ce prix est d'autant plus flagrante qu'il n'est pas, à mon sens, justifié. En effet, cela ne me semble pas d'une difficulté extrême de réaliser ce type de programmes. L'idée serait donc de proposer une solution gratuite (et si possible libre) pour retrouver le mot de passe d'un fichier ZIP. C'est en ce sens qu'est né <em>Back to the password</em>.<br />
<a href="http://www.jesuisungeek.com/public/pictures/real/bttp1.png" title="bttp1.png"><img src="http://www.jesuisungeek.com/public/pictures/real/.bttp1_s.jpg" alt="bttp1.png" title="bttp1.png, oct. 2012" /></a>
<a href="http://www.jesuisungeek.com/public/pictures/real/bttp2.png" title="bttp2.png"><img src="http://www.jesuisungeek.com/public/pictures/real/.bttp2_s.jpg" alt="bttp1.png" title="bttp2.png, oct. 2012" /></a><br />
<br />
Les avantages de <em>Back to the password</em> sont multiples :</p>
<ul>
<li>Une interface sympa (Et oui, ça joue <img src="/dotclear/themes/chestnut/smilies/wink.gif" alt=";-)" class="smiley" /> )</li>
<li>Support de différents types de caractères (lettres, chiffres ou tous caractères)</li>
<li>Choix de la longueur d'un mot de passe</li>
<li>Enregistrement des mots de passe probables</li>
<li>Statistiques montrant l'avancement en temps réel</li>
<li>Licence GPL</li>
<li>Application Multi-threads</li>
</ul>
<p>J'ai conçu un algorithme de génération de mot de passe qui en crée plus de 2 millions par seconde. Toutefois, mon programme est freiné par la bibliothèque que j'utilise pour ouvrir les fichiers ZIP, <a href="http://www.icsharpcode.net/OpenSource/SharpZipLib/" hreflang="fr">SharpZipLib</a> (Plutôt que de réinventer la roue, j'ai préféré utiliser ce qui existait déjà). Mais cette librairie a des soucis dès qu'il s'agit d'ouvrir de multiples fichiers ZIP ; en effet, le fait de changer de mot de passe fait qu'il faut ouvrir à nouveau le fichier ZIP. Ainsi, pour tester 10 mots de passe, il faut pouvoir ouvrir 10 fois le même fichier. Cela augmente donc de manière drastique les accès au disque et diminue d'autant la vitesse de recherche du mot de passe.<br />
Je pourrais (enfin je devrais) utiliser une autre classe, voire même en développer une autre, si j'avais le temps, mais je doute que ce soit pour tout de suite...<br />
D'où l'idée d'utiliser plusieurs threads, ce qui permet de chercher plusieurs mot de passe en même temps. En fait, un thread est créé pour chaque longueur de mot de passe. Ainsi, si on cherche un mot de passe compris entre 3 et 4 caractères, on créera deux threads. Tous les threads ainsi générés créent à leur tour deux threads pour parcourir la liste des mots de passe possible en partant de chaque extrémité. Ainsi, malgré les limitations de la classe utilisée, on peut facilement monter à un parcours de 200 mots de passe par seconde.</p>http://www.jesuisungeek.com/index.php?post/2008/06/08/132-back-to-the-password#comment-formhttp://www.jesuisungeek.com/index.php?feed/atom/comments/128