<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Serveurs</title>
  <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/taxonomy/term/1178"/>
  <link rel="self" type="application/atom+xml" href="http://artisan.karma-lab.net/taxonomy/term/1178/atom/feed"/>
  <id>http://artisan.karma-lab.net/taxonomy/term/1178/atom/feed</id>
  <updated>2008-07-30T14:49:02+02:00</updated>
  <entry>
    <title>Non mais des fois, je vous jure...</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1693" />
    <id>http://artisan.karma-lab.net/node/1693</id>
    <published>2008-11-09T21:20:07+01:00</published>
    <updated>2008-11-10T01:19:15+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p>
  Cela fait environ un mois, très exactement depuis que j'ai basculé sur la <kbd>cooker</kbd> pour tester en avance de phase Mandriva 2009.0, que je me retrouve sous Eclipse avec un bug des plus étonnant. Le symptôme est aussi simple qu'agaçant, chaque ouverture de fichier prend en gros 2 secondes... J'ai attendu patiemment la 2009.0 pour voir si le problème serait corrigé, mais rien à faire. Je me suis alors enfin décidé à chercher comme un grand et j'ai enfin mis la doigt sur le problème. Tout est la faute... de l'imprimante...
</p>

    ]]></summary>
    <content type="html"><![CDATA[<p>
  Cela fait environ un mois, très exactement depuis que j'ai basculé sur la <kbd>cooker</kbd> pour tester en avance de phase Mandriva 2009.0, que je me retrouve sous Eclipse avec un bug des plus étonnant. Le symptôme est aussi simple qu'agaçant, chaque ouverture de fichier prend en gros 2 secondes... J'ai attendu patiemment la 2009.0 pour voir si le problème serait corrigé, mais rien à faire. Je me suis alors enfin décidé à chercher comme un grand et j'ai enfin mis la doigt sur le problème. Tout est la faute... de l'imprimante...
</p>

<!--break-->

	<a name='chapter_1'></a>
  <h2>Premier round, le CPU...</h2>
	
<p>
  J'ai d'abord cru à un CPU emballé mais <a class='external' target='_blank' href='http://artisan.karma-lab.net/node/1209' >oprofiler</a> ne m'a pas donné raison. Aucun processus ne semble particulièrement occuper le CPU, ce qui est confirmé par un bête <kbd>ntop</kbd>.
</p>
<p>
  Noter au passage que pour utiliser <kbd>oprofiler</kbd> de manière optimum, ce dernier a besoin de votre noyau sous sa forme non-compressée (vmlinux et non pas vmlinuz). Ne cherchez pas un moyen de décompresser votre <kbd>/boot/vmlinuz</kbd> en l'autre, cela n'existe pas. En fait <kbd>vmlinuz</kbd> est un peu comme ces exécutables compressés, une première partie contient le code du décompresseur et la seconde les données. la seul solution est d'aller dans les sources du kernel et de lancer un simple <kbd>make vmlinux</kbd>. Le fichier est alors compilé dans le dossier <kbd>arch/x86</kbd>.
</p>


	<a name='chapter_2'></a>
  <h2>Second round, latence...</h2>
	
<p>
  La seconde possibilité est une latence, ou un timeout. Du coup je me lance sur un <kbd>strace eclipse 2> logs</kbd> pour afficher en temps réels les appels systèmes effectués par Eclipse. Dans une autre console je lance un <kbd>tail -f log</kbd>. Vu le volume d'informations, je suis rapidement passé à quelque chose de la forme <kbd>tail -f /home/yoran/t | grep -v timeofday | grep -v poll | grep -v "read(3"  | grep -v select | grep -v writev | grep -v futex</kbd>. Du coup, beaucoup moins d'informations. J'ouvre alors un fichier et je regarde ce qui se passe. 
</p>
<p>
   Dans les traces, je vois clairement que le coco cherche à se connecter au réseau, bizarre pour une simple ouverture de fichier. Il établit une connexion avec mon serveur et échange des informations.
</p>
<p>
 Du coup, j'arrêtes <kbd>strace</kbd> et je lance <a class='external' target='_blank' href='http://www.wireshark.org/' >wireshark</a>.
</p>


	<a name='chapter_3'></a>
  <h2>Troisième round, le réseau...</h2>
	
<p>
 <kbd>WireShark</kbd> est un indispensable outil de monitoring réseau, il permet ainsi de capturer toutes les informations qui circulent. Il vaut mieux du coup fermer les applications "communicantes", histoire de ne pas être paumé dans un flot de données. Ceci fait, lancement d'Eclipse et observant lors de l'ouverture de ce maudit fichier...
</p> 
<p>
  Là c'est confirmé, une connexion est bien ouverte sur le serveur, suivi d'une série de transaction, sur le port 631, c'est à dire celui de... <a class='external' target='_blank' href='http://www.cups.org/' >cups</a>... 
</p>


	<a name='chapter_4'></a>
  <h2>Quatrième round, pourquoi CUPS ?!?</h2>
	
<p>
   Un peu surpris tout de même... Pour information, notre imprimante est déportée prés du serveur dans une autre pièce et nous imprimons donc via le réseau. Il y a un donc bien un service <a class='external' target='_blank' href='http://artisan.karma-lab.net/node/1336' >CUPS sur le serveur et juste les librairies en local</a>. 
</p>
<p>
  Nouvelle observation des traces un peu avant la fameuse connexion au serveur, et là je me rend compte que lors de cette fameuse ouverture de fichier, Eclipse (ou une librairie partagée) va lire le fichier de configuration cups (/etc/cups/client.conf). Il y trouve mon serveur distante et va lui causer... Incompréhensible... Notez que j'ai refais le même test avec un utilisateur bidon, sur un compte totalement vierge, avec un eclipse tout frais sur une JVM SUN, rien n'y a fait, même résultat...
</p>


	<a name='chapter_5'></a>
  <h2>La solution la plus bidon au monde...</h2>
	
<p>
  J'ai tout essayé et le seule moyen que j'ai trouvé est de déplacer <kbd>/etc/cups</kbd>, lancer eclipse, et remettre le dossier <kbd>cups</kbd> à sa place. De toute beauté...
<p>


	<a name='chapter_6'></a>
  <h2>Conclusion</h2>
	
<p>
  Ce problème et sa solution ne va sûrement pas toucher grand monde, mais peut-être que la "démarche" peut intéresser ceux qui se trouvent face à cette famille de bug systémiques et vicieux. Le genre de bugs qui laisse google sans voix, jusqu'au moment où l'on a la solution et qu'on lui demande <a class='external' target='_blank' href='http://www.google.fr/search?q=eclipse+cups' >eclipse cups</a>... No comments, ça me rappelle le codage de la bible cette histoire...
</p>

    ]]></content>
  </entry>
  <entry>
    <title>CRON et la planification de tâches</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1692" />
    <id>http://artisan.karma-lab.net/node/1692</id>
    <published>2008-11-08T20:06:39+01:00</published>
    <updated>2008-11-13T19:02:54+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
  Difficile de se passer d'un planificateur de tâche, que ce soit pour faire des sauvegardes, vérifier l'intégrité des systèmes, faire le ménage ou bêtement se réveiller le matin. Sous UNIX, le temps c'est le domaine du vénérable CRON. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
  Difficile de se passer d'un planificateur de tâche, que ce soit pour faire des sauvegardes, vérifier l'intégrité des systèmes, faire le ménage ou bêtement se réveiller le matin. Sous UNIX, le temps c'est le domaine du vénérable CRON. 
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Principe</h2>
	
<p>
  <kbd>CRON</kbd> est un démon de l'ancien monde, à peu prés aussi vieux qu'
  <a target='_blank' href='http://fr.wikipedia.org/wiki/UNIX'>
  UNIX
  </a> lui-même. Et pour les connaisseurs, sachez qu'il n'a rien à voir avec la divinité cimmérienne, en toute banalité son nom vient du grec "chronos" (<b>χρόνος</b>), le temps.
</p>
<p>
  CRON est un planificateur de tâches dont le rôle est simplement d'exécuter des commandes récurrentes, chacune sur une base de temps donnée (toutes les heures, à une heure particulière chaque jour, au début de chaque mois, etc...).
</p>


	<a name='chapter_2'></a>
  <h2>La version simplifiée</h2>
	
<p>
  Comme nous allons le voir plus loin, ajouter une tâche dans CRON nécessite de connaître sa syntaxe et de modifier le bon fichier de planning. Cependant sur certaines distribution comme la Mandriva, <kbd>CRON</kbd> est pré-configuré de telle sorte que <kbd>les commandes</kbd> (ou plus généralement des liens symboliques vers des commandes) contenues dans les dossiers <kbd>/etc/cron.hourly</kbd>, <kbd>/etc/cron.daily</kbd>, <kbd>/etc/cron.weekly</kbd> et <kbd>/etc/cron.monthly</kbd>, soient exécutées respectivement tous les jours, toutes les heures, toutes les semaines et tous les mois. 
</p>  
<p>
  Du coup si vous avez seulement besoin de récurrence de ce type (heure, jour, semaine et mois), pas la peine de sortir la grosse artillerie, un simple lien symbolique suffit à planifier la tâche :
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># lancer la tâche backup tous les jours</div><div class='command'><span class='prompt'>root#</span>ln -s /usr/bin/backup /etc/cron.daily</div><div class='result'>&nbsp;</div><div class='co0'># vérifier le système toutes les heures</div><div class='command'><span class='prompt'>root#</span>ln -s /usr/bin/check_system /etc/cron.hourly</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>


	<a name='chapter_3'></a>
  <h2>Syntaxe des plannings</h2>
	
<p>
  Bien que pratique, le système par liens symbolique ne répond pas à tous les besoins. Et pour programmer une tâche aussi spécifique que "tous dimanches à l'heure de la messe", il faut mettre un peu plus les mains dans le cambouis.
</p>  

<p>
  Les plannings de tâches sont constitués par de simple fichier texte utilisant une syntaxe particulière. Le planning principal est <kbd>/etc/crontab</kbd> que très logiquement seul l'utilisateur <kbd>root</kbd> peut modifier. Mais pour éviter que ce fichier ne deviennent trop gros et aussi gagner en modularité, il est préférable de créer des micros-plannings dans le dossier <kbd>/etc/cron.d</kbd>. La syntaxe sera rigoureusement la même. 
</p>

<p>
 Un fichier planning peut commencer par une section de définition de variable. Nous allons grâce à ces variables pouvoir définir dans le contexte d'un même planning : le chemin des exécutable (<kbd>PATH</kbd>), le shell à utiliser par défaut (<kbd>SHELL</kbd>), le dossier de démarrage (<kbd>HOME</kbd>) et l'adresse courriel à utiliser pour envoyer à un tiers le résultat de la commande (<kbd>MAILTO</kbd>). 
</p>
<p>
  Ces variables sont importante car vous ne savez par exemple jamais quelle est la valeur de la variable PATH au sein d'un CRON, ni quel sera le dossier de démarrage. Elles permettent donc de fixer le contexte de manière fiable. 
</P>
<p>
  Dans une autre idée <kbd>MAILTO</kbd> définit quant à elle à qui sera expédié le mail qui contient tout ce qui a été "écrit" par une commande (messages, erreurs, etc). Notre premier planning va donc pouvoir ressembler à cela :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co0">#! /bin/sh</span><br />
<br />
<span class="co0"># définition des variables spécifiques au planning</span><br />
<span class="co0"># ###################################################</span><br />
<span class="re2">SHELL=</span><span class="sy0">/</span>bin<span class="sy0">/</span>bash<br />
<span class="re2">PATH=</span><span class="sy0">/</span>sbin:<span class="sy0">/</span>bin:<span class="sy0">/</span>usr<span class="sy0">/</span>sbin:<span class="sy0">/</span>usr<span class="sy0">/</span>bin<br />
<span class="re2">MAILTO=</span>mon_mail &nbsp;<span class="sy0">@</span>mon_domain.com<br />
<span class="re2">HOME=</span><span class="sy0">/</span>root<br />
<br />
<span class="co0"># Une tâche du planning</span><br />
<span class="sy0">*/</span><span class="nu0">1</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> root <a target="blank" href="http://pwet.fr/man/linux/commandes/ls"><span class="kw2">ls</span></a> -la &nbsp; &nbsp;
  </div>
  <div class='caption'>/etc/cron.d/mon_planing</div>
  </div>
</p>
<p>
  Si votre système est correctement configuré, vous devriez dans la minute qui suit (les plannings sont automatiquement pris en compte) recevoir par mail à l'adresse <kbd><script>document.write(String.fromCharCode(60,97,32,104,114,101,102,61,39,109,97,105,108,116,111,58,109,111,110,95,109,97,105,108,64,109,111,110,95,100,111,109,97,105,110,101,46,99,111,109,39,62,109,111,110,95,109,97,105,108,64,109,111,110,95,100,111,109,97,105,110,101,46,99,111,109,60,47,97,62));</script></kbd> le contenu du dossier <kbd>/root</kbd> (cf la variable <kbd>HOME</kbd>). Et ce, toutes les minutes... Lorsque vous aurez constaté que cela fonctionne, vous pouvez éditer à nouveau ce planning pour mettre la ligne qui lance la commande <kbd>ls</kbd> en commentaire en ajoutant un <kbd>#</kbd> en tête. 
</p>
<p>
  Comme vous le voyez le fichier planning contient une ligne par tâche planifiée. Chaque ligne est d'abord composée de 5 champs permettant de déterminer le moment du lancement. Suit ensuite l'identifiant l'utilisateur qui sera utilisé pour lancer cette commande, puis la commande elle-même comprenant tout ce qui se trouve après l'identifiant de l'utilisateur. Chaque champs est séparé par des espaces ou des tabulations. 
</p>
<p>
  Les 5 champs qui définissent le moment du lancement sont :
  <dl>
  <dt><kbd>minutes</kbd></dt><dd>Une valeur numérique allant de 0 à 59.</dd>
  <dt><kbd>heure</kbd></dt><dd>Une valeur numérique allant de 0 à 23.</dd>
  <dt><kbd>jour du mois</kbd></dt><dd>Une valeur numérique allant de 1 à 31.</dd>
  <dt><kbd>mois</kbd></dt><dd>Une valeur numérique allant de 1 à 12. </dd>
  <dt><kbd>jour de la semaine</kbd></dt><dd>Une valeur numérique de 1 à 7. </dd>
  </dl>
</p>
<div class='inline-box attention'>
  Pour les deux derniers champs, la dernière valeur (12 et 7) et 0 sont généralement synonymes mais il est plus simple de ne pas trop y compter. Enfin ces valeurs peuvent aussi être les 3 premières lettres du mois ou du jour de la semaine. Mais là aussi, d'un UNIX à l'autre, c'est de l'anglais ou du français. De plus certains ne prennent pas en charge cette notation pour les listes et les intervalles (voir plus loin).
</div>
<p>
  Chaque champ peut prendre une valeur précise, ou un intervalle de valeur. L'intervalle le plus simple est <kbd>*</kbd> signifiant "tout". Ainsi pour lancer une tâche tous les mois, toutes les semaines, tous les jours et à la 2ième minute de chaque heure, cela donne :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="nu0">02</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> gaston <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>ma_command
  </div>
  <div class='caption'>/etc/cron.d/exemples</div>
  </div>
</p>
<p>
  Il est aussi possible de spécifier une liste de valeur en séparant chacune par une virgule. Par exemple pour lancer la même commande que plus haut mais à la 2ième et 42ième minute :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="nu0">02</span>,<span class="nu0">42</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> &nbsp;gaston <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>ma_command
  </div>
  <div class='caption'>/etc/cron.d/exemples</div>
  </div>
<p>

<p>
  L'étoile spécifie un intervalle complet, mais nous pouvons aussi utiliser un intervalle restreint. Par exemple une commande lancée la 2ième minute de chaque heure mais de cette fois de 10h du matin à 6h du soir, cela donnerait :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="nu0">02</span> <span class="nu0">10</span><span class="nu0">-18</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> &nbsp;gaston <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>ma_command
  </div>
  <div class='caption'>/etc/cron.d/exemples</div>
  </div>
<p>
<p>
  Et comme pour les valeurs simples, vous pouvez définir des listes d'intervalles. Par exemple si l'on veut exclure l'heure du déjeuné, cela nous fait deux intervalles :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="nu0">02</span> <span class="nu0">10</span><span class="nu0">-12</span>,<span class="nu0">14</span><span class="nu0">-18</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> gaston <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>ma_command
  </div>
  <div class='caption'>/etc/cron.d/exemples</div>
  </div>
</p>
<p>
  Dernier point, il est possible de dire des choses du genre "toutes les deux heures" en ajoutant un pas à l'intervalle sous la forme <kbd>intervalle/pas</kbd>. Pour par exemple effectuer une tâche toutes les 15 minutes, nous affecterons le pas "15" à l'intervalle complet <kbd>*</kbd>, soit :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="sy0">*/</span><span class="nu0">15</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> gaston <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>ma_command
  </div>
  <div class='caption'>/etc/cron.d/exemples</div>
  </div>
</p>
<p>
  Cette notation de "pas" ne change en rien les propriétés de l'intervalle. Il est donc possible, de faire des listes d'intervalles avec pas. Par exemple toutes des 2 h, de 8h à 12h et de 14h à 18h, à la 2ième minute se note :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="nu0">2</span> <span class="nu0">8</span><span class="nu0">-12</span><span class="sy0">/</span><span class="nu0">2</span>,<span class="nu0">14</span><span class="nu0">-18</span><span class="sy0">/</span><span class="nu0">2</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> gaston <span class="sy0">/</span>usr<span class="sy0">/</span>bin<span class="sy0">/</span>ma_command
  </div>
  <div class='caption'>/etc/cron.d/exemples</div>
  </div>
  
</p>

<p>
  Une fois que l'on a mémorisé les différents motifs (valeur, intervalle, liste et pas), l'ajout de nouvelles tâche est très simple. Par exemple pour envoyer un mail tous les jours ouvré à 1h du matin cela nous donne :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="nu0">0</span> <span class="nu0">1</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="nu0">1</span><span class="nu0">-5</span> trichelieu <span class="kw3">echo</span> <span class="st0">&quot;Il est une heure,% tout va bien !!&quot;</span> <span class="sy0">|</span> mail -s <span class="st0">&quot;Rapport&quot;</span> compagnie<span class="sy0">@</span>son_domaine.net
  </div>
  <div class='caption'>/etc/cron.d/tour_de_garde</div>
  </div>
</p>
<p>
  A noter que le caractère <kbd>%</kbd> dans la commande est automatiquement changé en "retour chariot". Pour un vrai %, il faut taper <kbd>\%</kbd>.
</p>



	<a name='chapter_4'></a>
  <h2>CRON utilisateur</h2>
	
<p>
   <kbd>/etc/crontab</kbd> ou <kbd>/etc/cron.d</kbd> ne sont accessible qu'à <kbd>root</kbd>. Il est cependant offert à chaque utilisateur la possibilité de disposer de sa propre planification de tâche qui sera alors stockée en <kbd>/var/spool/cron/nom_utilisateur</kbd>.
</p>
<p>
 Ne pouvant pas éditer cela directement, il doit utiliser la commande <kbd>crontab</kbd>
 <dl>
  <dt>crontab -l</dt><dd>Vérifier si une table existe déjà et la lister si c'est le cas.</dd>
  <dt>crontab -e</dt><dd>Éditer la table avec <kbd>vi</kbd>. Si cet éditeur ne vous plaît pas, ce qui serait surprenant, faite un <kbd>export EDITOR=gedit</kbd> avant.</dd>
  <dt>crontab nom_fichier</dt><dd>Pour importer une table existante.</dd>
  <dt>crontab -r</dt><dd>Suppression de la table utilisateur.</dd>
  </dl>
</p>
<p>
  A noter que certains utilisateurs peuvent être interdits, ou explicitement autorisés à utiliser leur <kbd>crontab</kbd> en modifiant les fichier <kbd>/etc/cron.allow</kbd> et <kbd>/etc/cron.deny</kbd>.
</p>

	<a name='chapter_5'></a>
  <h2>Conclusion</h2>
	
<p>
  CRON fait parti de ces concepts UNIX indispensables à maîtriser et que pourtant beaucoup considèrent, à tord, comme complexe. J'espère que ce n'est maintenant plus le cas. 
</p>
    ]]></content>
  </entry>
  <entry>
    <title>Mettre en oeuvre des scripts Sieve dans Cyrus-Imap</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1083" />
    <id>http://artisan.karma-lab.net/node/1083</id>
    <published>2008-11-04T01:40:43+01:00</published>
    <updated>2008-11-04T11:34:48+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
  Peu de monde connaît <kbd>Sieve</kbd> présent sur la majorité des serveurs <kbd>IMAP</kbd>, dont <a class='external' target='_blank' href='http://fr.wikipedia.org/wiki/Dovecot' >Dovecot</a> et <a class='external' target='_blank' href='http://fr.wikipedia.org/wiki/Cyrus_(logiciel)' >Cyrus</a>. Pourtant il peut rendre d'immenses services comme trier automatiquement le spam, les publicités, ou même renvoyer un message d'absence lorsque vous êtes en vacance, le tout sans avoir à paramétrer le moindre client.
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
  Peu de monde connaît <kbd>Sieve</kbd> présent sur la majorité des serveurs <kbd>IMAP</kbd>, dont <a class='external' target='_blank' href='http://fr.wikipedia.org/wiki/Dovecot' >Dovecot</a> et <a class='external' target='_blank' href='http://fr.wikipedia.org/wiki/Cyrus_(logiciel)' >Cyrus</a>. Pourtant il peut rendre d'immenses services comme trier automatiquement le spam, les publicités, ou même renvoyer un message d'absence lorsque vous êtes en vacance, le tout sans avoir à paramétrer le moindre client.
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Qu'est-ce que sieve ?</h2>
	
<p>
  Sieve est un langage de filtrage des courriels <a class='external' target='_blank' href='http://rfc-ref.org/RFC-TEXTS/3028/index.html' >normalisé</a> qui permet d'automatiser à peu prés tous les tris imaginables. Pour mieux comprendre ce qu'il peut vous apporter, prenons un petit exemple "parlant" :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co2"># Est-ce que spamassassin a mis le flag &quot;SPAM&quot; ?</span><br />
<span class="kw1">if</span> header <span class="sy0">:</span>contains <span class="st0">&quot;X-Spam-Flag&quot;</span> <span class="st0">&quot;YES&quot;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="co2"># on déplace le mail dans la benne à pourriels...</span><br />
&nbsp; &nbsp; fileinto <span class="st0">&quot;spams&quot;</span>;<br />
&nbsp; &nbsp; stop;<br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Ici nous demandons à analyser l'en-tête de chaque message à la recherche de l'étiquette posée par un outil comme spamassassin. S'il s'agit bien d'un spam, le courriel est directement déplacé dans le dossier <kbd>spams</kbd>. 
</p>
<p>
  Sieve se place donc comme un excellent remplacement des classiques fonctions de filtrage présentes sur les clients de messagerie. Le gros avantage de son utilisation est que les règles de tris sont écrites une fois pour toutes et chaque client en bénéficie sans paramétrage. 
</p>



	<a name='chapter_2'></a>
  <h2>Sieve dans cyrus</h2>
	
<p>
  Dans l'outil Cyrus, sieve est intégré sous la forme d'un serveur qui écoute le port 2000. Il doit être activé en modifiant le fichier <kbd>/etc/cyrus.conf</kbd> de sorte à obtenir la ligne suivante :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  sieve &nbsp; &nbsp; &nbsp; &nbsp; cmd=&quot;timsieved&quot; listen=&quot;localhost:sieve&quot; prefork=1
  </div>
  
  </div>
</p>
<p>
  Ici l'écoute est forcée sur localhost seulement (127.0.0.1). Pour rendre sieve accessible du monde extérieur il suffit d'enlever <kbd>localhost:</kbd> (et de mettre en place un cryptage !!). 
</p>
<p>
  Ensuite il faut simplement relancer cyrus pour constater que le serveur sieve est bien actif
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>root#</span>/etc/init.d/cyrus-imapd restart</div><div class='result'>Arrêt de cyrus-imapd :                                          [  OK  ]</div><div class='result'>Lancement de cyrus-imapd :                                      [  OK  ]</div><div class='command'><span class='prompt'>root#</span>netstat -anlp | grep 2000</div><div class='result'>tcp        0      0 127.0.0.1:2000              0.0.0.0:*                   LISTEN      25047/timsieved</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>

	<a name='chapter_3'></a>
  <h2>Premier script Sieve</h2>
	
<p>
  Pour commencer, il va falloir créer notre premier script. Reprenons pour cela notre exemple en ajoutant la clause require (les librairies) qui lui manquait :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  require <span class="br0">&#91;</span><span class="st0">&quot;fileinto&quot;</span>,<span class="st0">&quot;envelope&quot;</span>,<span class="st0">&quot;reject&quot;</span>,<span class="st0">&quot;vacation&quot;</span>,<span class="st0">&quot;imapflags&quot;</span>,<span class="st0">&quot;relational&quot;</span>,<span class="st0">&quot;comparator-i;ascii-numeric&quot;</span>,<span class="st0">&quot;regex&quot;</span>,<span class="st0">&quot;notify&quot;</span><span class="br0">&#93;</span>;<br />
<span class="kw1">if</span> header <span class="sy0">:</span>contains <span class="st0">&quot;X-Spam-Flag&quot;</span> <span class="st0">&quot;YES&quot;</span> <span class="br0">&#123;</span><br />
&nbsp; fileinto <span class="st0">&quot;spams&quot;</span>;<br />
&nbsp; stop;<br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>mon_script.sieve</div>
  </div>
</p>
<p>
  Pour ajouter un script il faut utiliser la commande <kbd>sieveshell</kbd>. Cet outil se connecte sur le serveur, s'authentifie et permet d'uploader un script, de downloader un script existant et de rendre un des scripts actif. Une sorte de FTP ultra basique :

  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>root#</span>sieveshell -u gaston -a gaston localhost</div><div class='command'><span class='prompt'>></span>put mon_script.sieve default</div><div class='command'><span class='prompt'>></span>list</div><div class='result'>default</div><div class='command'><span class='prompt'>></span>activate default</div><div class='command'><span class='prompt'>></span>list</div><div class='result'>default*</div><div class='command'><span class='prompt'>></span>quit</div><div class='command'><span class='prompt'>root#</span></div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  A l'inverse, la commande <kbd>get default mon_vieux_script.sieve</kbd> va vider le script serveur <kbd>default</kbd>
dans le fichier local <kbd>mon_vieux_script.sieve</kbd>.
</p>
<p>
  Maintenant pour une édition régulière ce n'est pas très pratique. Le mieux serait un script bash qui permettrait d'éditer directement le script par défaut et de le sauver à la sortie. Pour y arriver, j'utilise une version améliorée par la communauté Debian de <kbd>sieveshell</kbd>. Pour l'utiliser il faut d'abord récupérer <a class='external' target='_blank' href='http://artisan.karma-lab.net/files/artisan/Shell.pm' >Shell.pm</a>  et <a class='external' target='_blank' href='http://artisan.karma-lab.net/files/artisan/sieveshell.pl.txt' >sieveshell.pl</a>. Ensuite vous devez remplacer les fichiers d'origines qui proviennent du paquet <kbd>cyrus-imapd-utils</kbd> pour <kbd>sieveshell</kbd>et <kbd>perl-cyrus</kbd> pour <kbd>Shell.pm</kbd>. Pour localiser ces fichiers, aidez-vous de la commande <kbd>rpm -ql cyrus-imapd-utils</kbd> et <kbd>rpm -ql perl-cyrus</kbd>. 
</p>
<p>
  Une fois le remplacement effectué, vous disposez d'un shell capable entre autre de prendre un mot de passe en paramètre. Le script est alors trivial :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co0">#! /bin/sh</span><br />
<span class="re2">server=</span>$<span class="nu0">1</span><br />
<span class="re2">user=</span>$<span class="nu0">2</span><br />
<span class="re2">password=</span>$<span class="nu0">3</span><br />
sieveshell -a <span class="re1">$user</span> -u <span class="re1">$user</span> -p <span class="re1">$password</span> --exec <span class="st0">&quot;get default /tmp/default&quot;</span> <span class="re1">$server</span><br />
vi <span class="sy0">/</span>tmp<span class="sy0">/</span>default<br />
sieveshell -a <span class="re1">$user</span> -u <span class="re1">$user</span> -p <span class="re1">$password</span> --exec <span class="st0">&quot;put /tmp/default default&quot;</span> <span class="re1">$server</span>
  </div>
  <div class='caption'>sievedit</div>
  </div>
</p>
<p>
  Il s'utilise simplement en passant le nom de serveur en premier paramètre (ex. localhost), le nom de l'utilisateur en second (ex. gaston) et enfin son mot de passe. Évidement vous n'êtes pas obligé d'utiliser <kbd>vi</kbd> <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>
</p>


	<a name='chapter_4'></a>
  <h2>Brève introduction à la syntaxe Sieve</h2>
	
<p>
   Un script sieve commence par la déclaration des librairies pré-requises :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co2"># importation des bibliothèques utiles</span><br />
require <span class="br0">&#91;</span><span class="st0">&quot;reject&quot;</span>, <span class="st0">&quot;fileinto&quot;</span>, <span class="st0">&quot;comparator-i;ascii-numeric&quot;</span>, <span class="st0">&quot;relational&quot;</span>, <span class="st0">&quot;imapflags&quot;</span><span class="br0">&#93;</span>;
  </div>
  
  </div>
</p>
<p>
 Là c'est un peu "ceinture-bretelles", on inclut tout ou presque histoire d'être paré <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>. Ensuite, vous pouvez insérez vos règles sous la forme de tests :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> BLOC_CONDITION &nbsp;<span class="br0">&#123;</span><br />
&nbsp; &nbsp;ACTION_1<span class="sy0">;</span><br />
&nbsp; &nbsp;...<br />
&nbsp; &nbsp;ACTION_N<span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Les actions les plus "utiles" sont :
  <dl>
    <dt>discard</dt>
    <dd>qui entraîne la destruction du courriel.</dd>
    <dt>stop</dt>
    <dd>qui arrête ici le traitement.</dd>
    <dt>fileinto "NOM_BOITE"</dt>
    <dd>qui déplace le courriel dans une autre boîte IMAP.</dd>
  </dl>
</p>
<p>
  <kbd>BLOC_CONDITION</kbd> quant à lui peut être une condition simple ou une composition de conditions simples liées entre elle par des ET (mot clef <kbd>allof</kbd>) ou des OU (mot clef <kbd>anyof</kbd>) :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1"># condition simple</span><br />
<span class="kw1">if</span> CONDITION_SIMPLE <span class="br0">&#123;</span><br />
&nbsp; <span class="co1"># liste des actions</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="co1"># conditions liées par OU</span><br />
<span class="kw1">if</span> anyof <span class="br0">&#40;</span>CONDITION_SIMPLE_1<span class="sy0">,</span> CONDITION_SIMPLE_2<span class="sy0">,</span> ...<span class="sy0">,</span> CONDITION_SIMPLE_N<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="co1"># liste des actions</span><br />
<span class="br0">&#125;</span><br />
<br />
<span class="co1"># conditions liées par ET</span><br />
<span class="kw1">if</span> allof <span class="br0">&#40;</span>CONDITION_SIMPLE_1<span class="sy0">,</span> CONDITION_SIMPLE_2<span class="sy0">,</span> ...<span class="sy0">,</span> CONDITION_SIMPLE_N<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="co1"># liste des actions</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Une condition simple se compose d'un <b>objet</b> sur lequel porte la condition, d'un <b>type</b> de condition et de <b>paramètres</b>. La syntaxe globale d'une condition simple est donc (notez bien le <kbd>:</kbd> et le <kbd>not</kbd> optionnel) :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  [not] OBJET_CONDITION :TYPE_CONDITION PARAMÈTRE_CONDITION_1 ... PARAMÈTRE_CONDITION_N &nbsp;
  </div>
  
  </div>  
</p>
<p>
  Les objets souvent utilisés sont :
  <dl>
    <dt>header</dt><dd>Il s'agit des champs de l'en-tête du message (Received, Subject, etc...)</dd>
    <dt>size</dt><dd>La taille du message</dd>
  </dl> 
</p>
<p>
  Les paramètres des conditions dépendent quant à eux beaucoup du type de condition. Cela peut être une chaîne (ex. <kbd>"CHAINE"</kbd>), une taille (ex. <kbd>1M</kbd> pour 1mo), un tableau de chaînes (ex. <kbd>["CHAINE_1","CHAINE_2",...,"CHAINE_N"]</kbd>), etc...
</p>
<p>
  Enfin les grand types de condition sont :
  <dl>
    <dt>objet <kbd>contains</kbd> P V</dt><dd>qui vérifie que l'objet à au moins une valeur V dans sa partie P. P et V pouvant être des chaînes ou des tableaux.</dd>
    <dt>objet <kbd>matches</kbd> P V</dt><dd>Comme <kbd>contains</kbd> mis à part que V peut contenir des chaînes avec des "jockers" (ex. "*@karma-lab.net")</dd>
    <dt>objet <kbd>over</kbd> V</dt><dd>Qui vérifie que la valeur de l'objet est "supérieur à" V</dd>
  </dl> 
</p>


	<a name='chapter_5'></a>
  <h2>Quelques exemples</h2>
	
<p>
  Pour que tout cela passe mieux, voyons quelques exemple classiques :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> header <span class="sy0">:</span>contains <span class="br0">&#91;</span><span class="st0">&quot;List-Id&quot;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="st0">&quot;xorg.lists.freedesktop.org&quot;</span><span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; fileinto <span class="st0">&quot;Mailling-Listes.xorg&quot;</span><span class="sy0">;</span><br />
&nbsp; stop<span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  On vérifie ici que la courriel est membre d'une mailling-liste donnée (champ <kbd>List-Id</kbd> du header) et on le déplace dans un dossier spécifique si tel est le cas.<br>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> header <span class="sy0">:</span>contains <span class="br0">&#91;</span><span class="st0">&quot;From&quot;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="st0">&quot;mon_client.com&quot;</span><span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; fileinto <span class="st0">&quot;mon client&quot;</span><span class="sy0">;</span><br />
&nbsp; stop<span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Si le courriel vient d'une adresse donnée, on le place dans un dossier spécial.<br>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> header <span class="sy0">:</span>contains <span class="br0">&#91;</span><span class="st0">&quot;To&quot;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="st0">&quot;<script>document.write(String.fromCharCode(60,97,32,104,114,101,102,61,39,109,97,105,108,116,111,58,99,100,105,115,99,111,117,110,116,64,103,97,115,116,111,110,46,110,101,116,39,62,99,100,105,115,99,111,117,110,116,64,103,97,115,116,111,110,46,110,101,116,60,47,97,62));</script>&quot;</span><span class="br0">&#93;</span> <span class="br0">&#123;</span><br />
&nbsp; fileinto <span class="st0">&quot;Publicites&quot;</span><span class="sy0">;</span> <br />
&nbsp; stop<span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Si le courriel est destiné à quelqu'un en particulier.<br>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> header <span class="sy0">:</span>contains <span class="br0">&#91;</span><span class="st0">&quot;Received&quot;</span><span class="br0">&#93;</span> <span class="br0">&#91;</span><span class="st0">&quot;12.34.56.78&quot;</span><span class="br0">&#93;</span> &nbsp;<span class="br0">&#123;</span><br />
&nbsp; fileinto <span class="st0">&quot;Societe Betadure&quot;</span><span class="sy0">;</span><br />
&nbsp; stop<span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Si le courriel a été reçu via un serveur SMTP (relais) particulier.<br>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> size <span class="sy0">:</span>over 1M <span class="br0">&#123;</span><br />
&nbsp; fileinto <span class="st0">&quot;gros courriels&quot;</span><span class="sy0">;</span><br />
&nbsp; stop<span class="sy0">;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Si le message est très gros, on le place dans un dossier particulier...
</p>

	<a name='chapter_6'></a>
  <h2>Les dossiers</h2>
	
<p>
  Si vos messages ne sont pas filtrer et donc qu'une des règles semble échouer, il faut aller voir du côté des logs de votre serveur IMAP. Il se peut que vous ayez simplement un problème dans le nommage du dossier pour la commande <kbd>fileinto</kbd> du genre <kbd>Invalid mailbox name</kbd> ou <kbd>mailbox doesn't exists</kbd>. Les différentes pistes sont les suivantes :
<ul>
  <li>L'encodage des accents. Certains serveur demande à ce que <kbd>répondeur</kbd> soit écrit <kbd>deux.r&AOk-pondeur</kbd> (ce n'est pas le cas de cyrus).</li>
  <li>Le séparateur de dossiers. Selon les versions de cyrus, le séparateur doit être un <kbd>.</kbd> ou un <kbd>/</kbd>.</li>
  <li>Racine de la boîte. Dans certaines version de cyrus les dossiers doivent commencer par la racine <kbD>INBOX</kbd>.</li>
  <lI>Racine des dossiers partagés. Selon le paramétrage de cyrus, la racine des dossiers partagée est la même que les dossiers standards ou doit être <kbd>Shared Folders</kbd>.</li>
</ul>
</p>


	<a name='chapter_7'></a>
  <h2>Conclusion</h2>
	
<p>
  Voilà, fin du petit tour du petit langage sieve qui rend finalement de bien grands services. 
</p>
    ]]></content>
  </entry>
  <entry>
    <title>Supervision domestique avec Nagios</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1157" />
    <id>http://artisan.karma-lab.net/node/1157</id>
    <published>2008-10-30T00:42:31+01:00</published>
    <updated>2008-10-30T00:44:18+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
  Lorsque l'on gère un petit réseau domestique avec une ou deux machines, on se retrouve malgré tout avec des problèmes de "grands" comme la nécessité d'être prévenu le plus vite lorsqu'un service tombe, et ce de la manière la plus automatisée possible. C'est à cette problématique que répond <kbd>Nagios</kbd>. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
  Lorsque l'on gère un petit réseau domestique avec une ou deux machines, on se retrouve malgré tout avec des problèmes de "grands" comme la nécessité d'être prévenu le plus vite lorsqu'un service tombe, et ce de la manière la plus automatisée possible. C'est à cette problématique que répond <kbd>Nagios</kbd>. 
</p>
<!--break-->

	<a name='chapter_6'></a>
  <h2>Présentation</h2>
	

<p>
<image file="nagios.png" width="300px"/>
  <a class='external' target='_blank' href='http://www.nagios.org' >Nagios</a>, qui s'appelait précédemment NetSaint, est un outil de supervision pour parc de serveurs. Il permet d'auditer en permanence des machines, des services sur ces machines, de recevoir des alertes en cas de problème et de disposer d'un tableau de bord de l'état du système à un moment donnée.
</p>

<p>
  Nagios s'architecture autour d'un moteur écrit en C chargé de la planification des différents audits à lancer à travers de le réseau et de l'agrégation des résultats dans une base de donnée. L'acquisition en elle-même est déléguée à une impressionnante librairie de greffons qui répondent à tous les besoins ou presque. Des modules qui sont souvent écrits en perl ou en bash, très simple à modifier et tout autant à imiter.  
</p>
<p>
  Le tout est contrôlable à travers une frontal Web basée sur le protocole CGI et accessible via n'importe quel serveur HTTP comme Apache.
</p>


	<a name='chapter_7'></a>
  <h2>Installation</h2>
	
<p>
  Sous Mandriva il suffit d'installer le paquet <kbd>nagios-www</kbd> pour que le reste vienne avec par jeu de dépendance. Si vous avez gardé la configuration standard de Mandriva côté apache, l'installation a ajouté un fichier de configuration spécifique en /etc/httpd/conf/webapp.d. Pour les autres ce qui est à rajouter dans votre apache doit ressembler à cela :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  ScriptAlias /nagios/cgi-bin /usr/lib/nagios/cgi<br />
<br />
<span class="sc3"><span class="re1">&lt;Directory</span> /usr/lib/nagios/cgi<span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; Options ExecCGI<br />
&nbsp; &nbsp; order deny,allow<br />
&nbsp; &nbsp; deny from all<br />
&nbsp; &nbsp; allow from 127.0.0.1<br />
<span class="sc3"><span class="re1">&lt;/Directory<span class="re2">&gt;</span></span></span><br />
<br />
Alias /nagios /usr/share/nagios<br />
<br />
<span class="sc3"><span class="re1">&lt;Directory</span> /usr/share/nagios<span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; Options None<br />
&nbsp; &nbsp; order deny,allow<br />
&nbsp; &nbsp; deny from all<br />
&nbsp; &nbsp; allow from 127.0.0.1<br />
<span class="sc3"><span class="re1">&lt;/Directory<span class="re2">&gt;</span></span></span>
  </div>
  
  </div>
</p>
<p>
  Le <kbd>ScriptAlias</kbd> permet d'accéder au CGI de Nagios, et l'<kbd>Alias</kbd> au dossier des éléments WEB. Tel quel l'Alias ne laisse passer que les utilisateurs locaux. A vous de modifier cela pour ajouter de l'<a class='external' target='_blank' href='/node/22' >authentification</a>, du SSL, etc. 
</p>
<p>
  Ensuite pour que cela fonctionne, nous allons faire une très vilaine chose, à savoir virer l'authentification du côté CGI de nagios. Pourquoi ? Disons qu'il n'y a pas grand intérêt à authentifier un service qui n'est accessible que localement ou alors est encrypté et authentifié. Du moins pour un usage domestique aucun. Pour faire cela, il faut simplement modifier la configuration <kbd>/etc/nagios/cgi.cfg</kbd> et mettre à <kbd>0</kbd> la valeur de <kbd>use_authentication</kbd>.
</p>
<p>
<image file="horrible.png" width="200px"/>
  Ceci fait, nous pouvons redémarrer apache, puis démarrer le service <kbd>nagios</kbd> et enfin aller faire un tour sur le serveur à l'url <kbd>/nagios</kbd> pour voir la plus horrible interface que le monde ait connu depuis le WEB 0.1. Heureusement il est possible d'arranger cela en installant un look un peu plus moins-pire avec le paquet <kbd>nagios-theme-nuvola</kbd>.
</p>
<p>
  Comme vous le voyez, nagios fonctionne "out of the box" avec une série de service (cpu, disques) en écoute de la machine locale. Voyons maintenant comment aller plus loin. 
</p>


	<a name='chapter_8'></a>
  <h2>Configuration</h2>
	
<p>
  Alors je vous préviens, le paramétrage de cet outil peut se révéler être une véritable expérience Kafkaïenne mais une fois réalisé, on dispose de quelque chose de fonctionnel, et pour longtemps.  
</p>
<p>
 Pour débuter, prenons un exemple simple. Imaginons que nous ayons un serveur nommé <kbd>gaston</kbd> et que nous voulions auditer la bonne marche de son service HTTP. 
</p>
 
<p>
 Nous allons commencer par créer un fichier <kbd>/etc/nagios/servers/gaston.cfg</kbd> chargé de décrire le serveur 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  define host{<br />
&nbsp; use &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; linux-server<br />
&nbsp; host_name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gaston<br />
&nbsp; alias &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Le serveur Gaston<br />
&nbsp; address &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 192.168.0.155<br />
}
  </div>
  <div class='caption'>/etc/nagios/servers/gaston.cfg</div>
  </div>
</p>
<p>
  Notre <kbd>host</kbd> est de type <kbd>linux-server</kbd> qui un template nagios qui porte bien son nom. <kbd>Alias</kbd> est le nom "humain" du serveur, il peut contenir des espaces mais c'est à peu près tout. Pas d'accents, pas de parenthèses, bref un véritable ascétisme syntaxique tendance ethno-centré US.
</p>
<p>
  Autre détail, ne pensez même pas à formater le code à votre convenance. Par exemple, mettre la première accolade à la ligne entraînera un refus brutal de démarrage...
</p>
<p>
  Pour tester notre configuration, plutôt que de relancer tout de suite le service <kbd>nagios</kbd>, nous pouvons d'abord la tester à la main :

  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>root#</span>nagios -v /etc/nagios/nagios.cfg</div><div class='result'>Nagios 3.0.3</div><div class='result'>Copyright (c) 1999-2008 Ethan Galstad (http://www.nagios.org)</div><div class='result'>Last Modified: 06-25-2008</div><div class='result'>License: GPL</div><div class='result'>&nbsp;</div><div class='result'>Reading configuration data...</div><div class='result'>&nbsp;</div><div class='result'>Running pre-flight check on configuration data...</div><div class='result'>&nbsp;</div><div class='result'>Checking services...</div><div class='result'>Checked 8 services.</div><div class='result'>Checking hosts...</div><div class='result'>Checked 1 hosts.</div><div class='result'>Checking host groups...</div><div class='result'>Checked 1 host groups.</div><div class='result'>...</div><div class='result'>Total Warnings: 0</div><div class='result'>Total Errors:   0</div><div class='result'>&nbsp;</div><div class='result'>Things look okay - No serious problems were detected during the pre-flight check</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  Là ça passe où ça casse mais au moins cela donne la ligne où ça plante. Une fois que tout est correcte, on peut redémarrer proprement le service <kbd>nagios</kbd>. 
</p>
<p>
  Il suffit ensuite d'aller sur l'URL de nagios, de faire un refresh pour voir un nouveau host apparaître. Dans un premier temps il apparaît en gris car la mise à jour des status est encore en file d'attente. Mais au bout de quelque temps cela devrait passer au vert. 
</p>

<p>
  Deuxième étape, ajouter un service à <kbd>gaston</kbd> en éditant à nouveau notre fichier <kbd>gaston.cfg</kbd>  :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  define service{<br />
&nbsp; use &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local-service<br />
&nbsp; host_name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gaston<br />
&nbsp; service_description &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Audit du site web de Gaston<br />
&nbsp; check_command &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; check_http_text!Ceci est le site Web de Gaston<br />
}
  </div>
  <div class='caption'>/etc/nagios/servers/gaston.cfg</div>
  </div>
</p>
<p>
  L'idée de ce service est de vérifier si le serveur HTTP fonctionne sur gaston et que la page renvoyé contient la chaîne de caractère <kbd>Ceci est le site Web de Gaston</kbd>. En l'état cela ne marchera pas car il va encore falloir créer la commande Nagios <kbd>check_http_text</kbd>. 
</p>
<p>
  En effet Nagios est fournit avec une foultitude de plugins permettant de tester un grand nombre de services. Ces plugins, qui sont de simple exécutables stockés dans <kbd>/usr/lib/nagios/plugins</kbd>, ne sont pas reconnus directement. Il faut préalablement les déclarer dans le fichier <kbd>/etc/nagios/objects/commands.cfg</kbd>. 
</p>
<p>
  Ceci dit, là, nous cherchons la difficulté car une grande partie des plugins de base sont déjà configurés en commandes directement utilisable et nous aurions pu par exemple utiliser commande <kbd>check_http</kbd>, qui ne teste que la présence d'un serveur web, à la place <kbd>check_http_text</kbd>.
</p>
<p>
  Mais pour nous faire la main, disons que nous avons absolument besoin de quelque chose de plus spécifique. Pour ajouter cette nouvelle commande, nous allons donc étendre le fichier <kbd>commands.cfg</kbd> :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  define command{<br />
&nbsp; &nbsp; &nbsp; &nbsp; command_name &nbsp; &nbsp;check_http_text<br />
&nbsp; &nbsp; &nbsp; &nbsp; command_line &nbsp; &nbsp;$USER1$/check_http -H $HOSTADDRESS$ &nbsp;-R &quot;$ARG1$&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; }
  </div>
  <div class='caption'>à la fin de /etc/nagios/objects/commands.cfg</div>
  </div>
</p>
<p>
  La commande <kbd>check_http_text</kbd> va invoquer le plugin <kbd>check_http</kbd> avec comme premier paramètre l'adresse IP du serveur, et en second paramètre une expression régulière à vérifier dans la page de garde. Ce paramètre correspond à ce qui se trouve après le point d'exclamation dans le service que l'on a écrit un peu plus haut (<kbd>check_http_text!Ceci est le site Web de Gaston</kbd>). A noter que si nous avions créé une commande avec plusieurs paramètres, nous aurions rajouté des $ARG2$ ou $ARG3$ et aussi rajouté dans le service des paramètre précédé de leur point d'exclamation. Oui je sais, c'est totalement idiot comme formalisme...
</p>
<p>
  Maintenant, on redémarre le service <kbd>nagios</kbd> et là sur la page WEB devrait apparaître notre nouveau service. 
</p>
<p>
  A ce stade, vous avez presque toute les billes pour configurer Nagios. C'est long, c'est fastidieux, on se trompe souvent mais on y arrive, du moins pour les service locaux et les services distants mais publiques (ex. http, ssh, etc.). Reste le cas des services locaux, d'un serveur distant. 
</p>


	<a name='chapter_9'></a>
  <h2>Audit de services internes à distance</h2>
	
<p>
  Imaginons que cette fois nous voulions connaître l'espace disque sur le serveur <kbd>gaston</kbd>. Pour réaliser une telle chose nous allons devoir passer par une couche de transport prise en charge par le paquet <kbd>nrpe</kbd>.
</p>
<p>
 NRPE est un petit serveur qui va se mettre en écoute sur un port sur la machine distante et répondre aux requêtes de votre serveur Nagios. Lorsqu'il reçoit une demande, il va exécuter un plugin local et transmettre sa réponse à Nagios. Conséquence directe, <kbd>nrpe</kbd> a son propre fichier de configuration qui n'a rien à voir avec celui de nagios. Donc si vous pensiez pouvoir paramétrer cela à distance c'est raté. 
</p>
<p>
  Pour auditer à distance l'état des disques du serveur <kbd>gaston</kbd>, nous allons devoir commencer par y installer le service <kbd>nrpe</kbd> avec le paquet <kbd>nrpe-plugin</kbd>. Et sur la machine qui exécute Nagios, nous allons installer le plugin ET la commande <kbd>nrpe</kbd> provenant du paquet <kbd>nagios-check_nrpe</kbd>.
</p>
<p>
  Sur la machine <kbd>gaston</kbd>,  nous allons éditer le fichier <kbd>/etc/nagios/nrpe.cfg</kbd> et localiser la ligne contenant <kbd>command[check_disk1]</kbd>. Vous commencez à comprendre, cette ligne publie via <kbd>nrpe</kbd> un paramétrage spécifique du plugin <kbd>check_disk</kbd> qui pour l'instant utilise la partition <kbd>/dev/hda1</kbd>. Changer la référence de la partition pour, par exemple, auditer le répertoire <kbd>/var</kbd> en <kbd>/dev/sda3</kbd>. On remplace donc <kbd>hda1</kbd> par <kbd>sda3</kbd>. Le reste ne change pas. Ensuite il faut sauver et redémarrer <kbd>nrpe</kbd>.
</p>

<p>
Maintenant nous allons ajouter un nouveau service à <kbd>/etc/nagios/servers/gaston.cfg</kbd>  :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  define service<span class="br0">&#123;</span><br />
&nbsp; use &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; local-service<br />
&nbsp; host_name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gaston<br />
&nbsp; service_description &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Etat de la partition <span class="sy0">/</span>var<br />
&nbsp; check_command &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; check_nrpe<span class="sy0">!</span>check_disk1<br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>/etc/nagios/servers/gaston.cfg</div>
  </div>
</p>
<p>
  Notez le paramètre <kbd>!check_disk1</kbd>, il va être transmis à la commande et remplacer l'argument <kbd>$ARG1$</kbd> avant que le plugin nrpe soit exécuté. Le serveur <kbd>gaston</kbd> va recevoir la demande de plugin <kbd>check_disk1</kbd> et va donc exécuter en local le plugin <kbd>check_disk</kbd> sur la partition <kbd>/dev/sda3</kbd>. Le résultat est renvoyé à nrpe, qui le revois au plugin nrpe sur la machine nagios qui va le rendre à nagios lui-même. ouf ! Dans la série pourquoi faire simple lorsque l'on peut faire compliqué...
</p>


	<a name='chapter_10'></a>
  <h2>Passage par SSH</h2>
	
<p>  
  Une manière de se passer de NRPE est d'utiliser <a class='external' target='_blank' href='/node/82' >SSH et une authentification par clef pour les deux deux utilisateurs nagios des deux machines</a>. L'idée est assez simple, il s'agit de lancer, via ssh le plugin nagios distant par le biais d'une commande nagios conçue pour cela. Il faut toujours configuré de nouvelles commandes mais au moins cette configuration reste centralisée sur le serveur nagios et ne demande pas l'ouverture de ports supplémentaires. 
</p>
<p>
  Pour commencer, nous devons créer un plugin capable de relayer une commande sur une machine distante 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co0">#! /bin/sh</span><br />
<br />
<span class="re2">host=</span>$<span class="nu0">1</span><br />
<span class="kw3">shift</span><br />
<span class="re2">command=</span><span class="re4">$*</span>;<br />
<span class="re2">command=</span><span class="sy0">/</span>usr<span class="sy0">/</span>lib<span class="sy0">/</span>nagios<span class="sy0">/</span>plugins<span class="sy0">/</span><span class="re1">$plugins</span><span class="re1">$command</span><br />
<a target="blank" href="http://pwet.fr/man/linux/commandes/ssh"><span class="kw2">ssh</span></a> <span class="re1">$host</span> <span class="st0">&quot;$command&quot;</span>
  </div>
  <div class='caption'>/usr/lib/nagios/plugins/ssh_check</div>
  </div>
</p>
<p>
  Pas très sorcier. Ensuite disons que nous voulions auditer l'espace disque, nous allons ajouter une nouvelle commande :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; define <span class="kw3">command</span><span class="br0">&#123;</span><br />
&nbsp; command_name &nbsp; &nbsp;check_disk<br />
&nbsp; command_line &nbsp; &nbsp;<span class="re1">$USER1</span>$<span class="sy0">/</span>ssh_check <span class="re1">$HOSTADDRESS</span>$ &nbsp;<span class="sy0">/</span>check_disk -w <span class="nu0">10</span><span class="sy0">%</span> -c <span class="nu0">5</span><span class="sy0">%</span> -p <span class="sy0">/</span>var -p <span class="sy0">/</span>tmp -p <span class="sy0">/</span>storage -p <span class="sy0">/</span> &nbsp;home -p <span class="sy0">/</span><br />
<span class="br0">&#125;</span>
  </div>
  <div class='caption'>objects/commands.cfg</div>
  </div>
</p>
<p>
  Ceci fait, la commande s'utilise comme les autres et renvoie à Nagios les résultats distants sans broncher. 
</p>


	<a name='chapter_11'></a>
  <h2>conclusion</h2>
	
<p>
  Nagios n'est clairement pas un outil pour newbies. Mais une fois le paramétrage en main il se révèle être d'une grande souplesse. De plus son système de greffons permet de l'étendre très simplement. Si vous comptez aller plus loin avec Nagios, je vous conseille d'aller regarder par <a class='external' target='_blank' href='http://blog.nicolargo.com/' >ici</a>.
</p>
    ]]></content>
  </entry>
  <entry>
    <title>Mise en place d&#039;un service NIS</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1682" />
    <id>http://artisan.karma-lab.net/node/1682</id>
    <published>2008-10-22T11:10:54+02:00</published>
    <updated>2008-10-22T12:59:44+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
  Après avoir utilisé pendant un temps LDAP, j'en arrive à la conclusion que ce type de serveur est parfait pour une grande structure mais totalement ridicule pour un réseau domestique. D'un autre côté, on a aussi autre à faire de son temps que de s'amuser à répliquer les comptes, les droits, les groupes sur 5 machines. La solution intermédiaire est un bon vieux retour au source avec NIS. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
  Après avoir utilisé pendant un temps LDAP, j'en arrive à la conclusion que ce type de serveur est parfait pour une grande structure mais totalement ridicule pour un réseau domestique. D'un autre côté, on a aussi autre à faire de son temps que de s'amuser à répliquer les comptes, les droits, les groupes sur 5 machines. La solution intermédiaire est un bon vieux retour au source avec NIS. 
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Principe</h2>
	
<p>
   NIS est un protocole d'origine SUN dont le but est de publier sur un réseau UNIX à peu prés toutes les bases de données traditionnelles au format ndbm et ainsi les rendre disponibles pour des clients, UNIX eux aussi. 
</p>
<p>
   Ces bases de données sont tout simplement <kbd>/etc/passwd</kbd>, <kbd>/etc/shadow</kbd>, <kbd>/etc/group</kbd>, <kbd>/etc/hosts</kbd>, <kbd>/etc/services</kbd>, <kbd>/etc/protocols</kbd>, etc. En utilisant les 3 premières citées, de la même manière qu'avec un serveur LDAP, ce protocole permet de s'authentifier partout sur le réseau. Et en utilisant <kbd>/etc/hosts</kbd> il serait aussi possible de se passer, plus ou moins de Bind mais il est souvent délicat de se passer de DNS, même pour une petite infrastructure. 
</p>
<p>
   Techniquement NIS, aussi appelé Yellow Pages, utiliser le même canal RPC que les transactions NFS. NFS, pour ceux qui ne le savent pas, est aussi un système d'origine SUN, permettant le partage de dossier dans le monde UNIX à l'instar de SMB/CIFS dans le monde Windows. 
</p>
<p>
  Lorsque l'on ne compte QUE des machines UNIX dans son réseau, et que ce réseau n'est pas composé de what-milles bécanes, NIS est une très bonne alternative à LDAP/Bind. Non pas qu'il soit plus performant, loin de là, mais surtout parce qu'il est simple, stable, vieux, solide, il ne bouge plus ou presque. Et surtout il ne menace pas de vous planter à chaque mise à jour parce qu'un ingénieur de chez Mandriva (ou autre) a décidé qu'il était absolument intolérable que le serveur bidulo ne soit chrooté dans /var avec des ACLs sécurisés par des jetons Kerberos 5 et encapsulé dans des transactions chiffrées vous obligeant à passer la nuit à tenter de comprendre pourquoi vous êtes devenu un inconnu sur votre propre système... 
</p>
<p>
  NIS se contente très simplement d'utiliser ces bons vieux fichiers pour en faire des bases de données toute bêtes et de les publier à la demande aux clients qui en ont besoin. 
</p>


	<a name='chapter_2'></a>
  <h2>Installation du serveur</h2>
	
<p>
   Pour commencer, une brassée de paquets à installer : <kbd>portmap</kbd> (si vous n'avez pas déjà un serveur NFS), <kbd>ypserv</kbd>, <kbd>yp-tools</kbd> et <kbd>nscd</kbd>. Ce dernier permet d'ajouter un cache configuré par défaut pour retenir les login/mot de passe un certain temps. Cela permet de limite les requêtes faites sur le serveur pour connaître le group ou l'uid de tel ou tel utilisateur. 
</p>
<p>
  Première étape, déclarer un nom de réseau NIS. Pour cela il faut modifier votre fichier <kbd>/etc/sysconfig/netword</kbd> :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="re2">HOSTNAME=</span>mon_serveur.mon_domaine.net<br />
<span class="re2">NETWORKING=</span>yes<br />
<span class="re2">NETWORKING_IPV6=</span>NO<br />
<br />
<span class="co0"># mon nom de domaine</span><br />
<span class="re2">NISDOMAIN=</span>mon_domaine.net
  </div>
  <div class='caption'>/etc/sysconfig/network</div>
  </div>
</p>
<p>
  Le serveur qui va distribuer les informations est <kbd>ypserv</kbd>. Son fichier de paramétrage est <kbd>/etc/ypserv.conf</kbd> et généralement il contient déjà tout ce qu'il faut, vérifiez seulement que vous avez au moins cela :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  dns: no<br />
files: <span class="nu0">30</span><br />
slp: no<br />
slp_timeout: <span class="nu0">3600</span><br />
xfr_check_port: <a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
<span class="sy0">*</span> : <span class="sy0">*</span> : shadow.byname : port<br />
<span class="sy0">*</span> : <span class="sy0">*</span> : <a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a>.adjunct.byname : port
  </div>
  <div class='caption'>/etc/ypserv.conf</div>
  </div>
</p>

<p>
  Faites un <kbd>man ypserv.conf</kbd> pour les deux dernières lignes si vous voulez blinder un peu la sécurité. Personnellement, dans un LAN domestique totalement étanche, je m'en moque un peu. 
</p>

<p>
  Maintenant il nous faut initialiser notre serveur principal 
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>root#</span>/usr/lib/yp/ypinit -m</div><div class='result'>At this point, we have to construct a list of the hosts which will run NIS</div><div class='result'>servers.  nephilia.karma-lab.net is in the list of NIS server hosts.  Please continue to add</div><div class='result'>the names for the other hosts, one per line.  When you are done with the</div><div class='result'>list, type a <control D>.</div><div class='result'>next host to add:  mon_serveur.mon_domaine.net</div><div class='command'><span class='prompt'>next host to add:</span>CTRL-D</div><div class='result'>The current list of NIS servers looks like this:</div><div class='result'>&nbsp;</div><div class='result'>mon_serveur.mon_domaine.net</div><div class='result'>&nbsp;</div><div class='command'><span class='prompt'>Is this correct?  [y/n: y]</span>y</div><div class='result'>We need a few minutes to build the databases...</div><div class='result'>Building /var/yp/karma-lab.net/ypservers...</div><div class='result'>Running /var/yp/Makefile...</div><div class='result'>gmake[1]: entrant dans le répertoire « /var/yp/karma-lab.net »</div><div class='result'>Updating passwd.byname...</div><div class='result'>...</div><div class='result'>Updating shadow.byname...</div><div class='result'>gmake[1]: quittant le répertoire « /var/yp/karma-lab.net »</div><div class='result'>&nbsp;</div><div class='result'>mon_serveur.mon_domaine.net has been set up as a NIS master server.</div><div class='command'><span class='prompt'>root#</span></div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  Là je n'ai donc que faire répondre oui à la question, rien de bien sorcier. Et... c'est tout... Le serveur est techniquement configuré <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/> Maintenant un bon ami administrateur m'a un jour expliqué que ce n'était pas parce que Linux n'avait à peu prés jamais besoin de redémarrer qu'il ne fallait pas le faire pour vérifier que tout se lançait correctement, surtout sur un serveur. Et il a grandement raison, donc maintenant, redémarrage. Tant pis pour le record d'uptime <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>.  
</p>
<p>
  Une fois le serveur redémarré, vous pouvez regarder si tout semble en place
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='command'><span class='prompt'>root#</span>avons nous le bon domaines ?</div><div class='result'>mon_domaine</div><div class='result'>&nbsp;</div><div class='co0'># le service Yellow Pages est-il public sur le service RPC ?</div><div class='command'><span class='prompt'>root#</span>rpcinfo -p localhost</div><div class='result'>program no_version protocole  no_port</div><div class='result'>100000    2   tcp    111  portmapper</div><div class='result'>100000    2   udp    111  portmapper</div><div class='result'>100024    1   udp  55448  status</div><div class='result'>100024    1   tcp  34159  status</div><div class='result'>100004    2   udp    646  ypserv</div><div class='result'>100004    1   udp    646  ypserv</div><div class='result'>100004    2   tcp    649  ypserv</div><div class='result'>100004    1   tcp    649  ypserv</div><div class='result'>600100069    1   udp    677  fypxfrd</div><div class='result'>600100069    1   tcp    679  fypxfrd</div><div class='result'>100009    1   udp    679  yppasswdd</div><div class='result'>...</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  Tout semble bon, passons au paramétrage des clients. Si vous utilisez un serveur <kbd>dhcpd</kbd>, vous pouvez aussi ajouter la ligne <kbd>option nis-domain "karma-lab.net";</kbd> dans votre subnet de sorte à réduire ne pas avoir à régler ce domaine sur les clients. 
</p>


	<a name='chapter_3'></a>
  <h2>Paramétrage des clients UNIX</h2>
	
<p>
  Cette fois nous devons installer <kbd>ypbind</kbd>, <kbd>yp-tools</kbd> et toujours <kbd>portmap</kbd>. Vous l'aurez compris, <kbd>ypbind</kbd> est le client de <kbd>ypserv</kbd> et son paramétrage se fait par le fichier <kbd>/etc/yp.conf</kbd> dans lequel nous allons indique notre domaine et l'adresse IP de notre serveur NIS. 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  domain mon_domaine.net &nbsp;server <span class="nu0">10.0</span><span class="nu0">.0</span><span class="nu0">.100</span>
  </div>
  <div class='caption'>/etc/yp.conf</div>
  </div>
</p>

<p>
  NIS se contente de distribuer l'information. Le choix de la source d'authentification en elle-même passe par <kbd>glibc</kbd> et est paramétrée par le fichier <kbd>/etc/nsswitch.conf</kbd>. C'est dans ce fichier que nous allons indiquer les sources à utiliser par ordre de priorité et par type d'action voulue :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a>: &nbsp; &nbsp; files nis<br />
shadow: &nbsp; &nbsp; files nis<br />
group: &nbsp; &nbsp; &nbsp;files nis &nbsp;<br />
hosts: &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/file"><span class="kw2">file</span></a> &nbsp;dns
  </div>
  <div class='caption'>/etc/nsswitch.conf</div>
  </div>
</p>

<p>
  Ainsi configuré, pour chacune des 3 clefs de recherche nous cherchons en priorité dans le fichier local puis si rien n'y est trouvé, la source NIS. 
</p>

<div class='inline-box note'>
  Dans mon cas, vu que je conserver le serveur DNS/Bind, le service <kbd>hosts</kbd> n'utilise pas <kbd>nis</kbd>. Pour faire autrement, intercalez seulement <kbd>nis</kbd> entre <kbd>file</kbd> et <kbd>dns</kbd>. N'oubliez pas non plus de modifier <kbd>/etc/hosts.conf</kbd> pour ajouter <kbd>nis</kbd> à la liste <kbd>order</kbd>.
</div>

<p>
  Le paramétrage est terminé dans le cas où vous utilisez un serveur <kbd>dhcp</kbd> (voir plus haut) et presque terminé dans le cas contraire où il nous faut encore modifier <kbd>/etc/sysconfig/network</kbd> pour ajouter la même entrée <kbd>NISDOMAIN=mon_domaine</kbd> que pour le serveur.
</p>
<p>
  Là il s'agit de la version longue. Dans la version courte, utilisez simplement l'outil mandriva <kbd>drakauth</kbd>, sélectionnez <kbd>NIS</kbd>, donnez le nom du domaine et l'adresse IP du serveur et validez. L'outil se charge de récupérer les paquets manquants et de tout configurer. Coût de l'opération, 5 secondes...
</p>
<p>
 Ceci fait, il ne nous reste plus qu'à tester :
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># nous n'avons pas encore redémarré le client donc le domaine NIS</div><div class='co0'># n'est pas encore initialisé, on le fait à la main</div><div class='command'><span class='prompt'>root#</span>nisdomainname mon_domaine.net</div><div class='result'>&nbsp;</div><div class='co0'># démarrage du service ypbind</div><div class='command'><span class='prompt'>root#</span>service ypbind start</div><div class='result'>Recherche du nom de domaine NIS...                              [  OK  ]</div><div class='result'>Recherche d'un serveur de domaine NIS : mon_serveur.mon_domaine.net</div><div class='result'>&nbsp;</div><div class='co0'># vérifions que nous avons bien accès aux données, par exemple passwd</div><div class='command'><span class='prompt'>root#</span>ypcat passwd</div><div class='result'>gaston:x:1010:1010::/home/gaston:/bin/bash</div><div class='result'>...</div><div class='result'>&nbsp;</div><div class='co0'># et Si vous utilisez en plus les hosts...</div><div class='command'><span class='prompt'>root#</span>ybcat hosts</div><div class='result'>10.0.0.11		tagazok.mon_domaine.net</div><div class='result'>...</div><div class='result'>&nbsp;</div><div class='co0'># on ping pour voir si la résolution se fait correctement</div><div class='result'>ping tagazok.mon_domaine.net</div><div class='result'>64 bytes from tagazok.mon_domaine (10.0.0.11): icmp_seq=1 ttl=64 time=0.015 ms</div><div class='result'>...</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  Après il faut bien sur tester une authentification mais tout devrait marcher sans problèmes. 
</p>


	<a name='chapter_4'></a>
  <h2>Mise à jour des bases de données</h2>
	
<p>
  Un point appréciable avec NIS est que c'est aussi simple à maintenir qu'à configurer. Voyons sur le serveur en combien de temps nous pouvons ajouter un utilisateur, son groupe, et sa machine (si vous utilisez la publication de <kbd>/etc/hosts</kbd>) :
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># ajout d'un groupe et d'un utilisateur</div><div class='command'><span class='prompt'>root#</span>groupadd totoches</div><div class='command'><span class='prompt'>root#</span>useradd josette -g totoches</div><div class='result'>&nbsp;</div><div class='co0'># ajout d'un nouveau host (si vous avez publié /etc/hosts)</div><div class='command'><span class='prompt'>root#</span>echo "10.0.0.12 machine_josette.mon_domaine.net" >> /etc/hosts</div><div class='result'>&nbsp;</div><div class='co0'># Maintenant la formule magique pour propager les nouveautés :</div><div class='command'><span class='prompt'>root#</span>make -C /var/yp</div><div class='result'>gmake[1]: entrant dans le répertoire « /var/yp/mon_domaine.net »</div><div class='result'>Updating passwd.byname...</div><div class='result'>Updating passwd.byuid...</div><div class='result'>Updating group.byname...</div><div class='result'>Updating group.bygid...</div><div class='result'>Updating hosts.byname...</div><div class='result'>Updating hosts.byaddr...</div><div class='result'>Updating netid.byname...</div><div class='result'>Updating shadow.byname...</div><div class='result'>gmake[1]: quittant le répertoire « /var/yp/mon_domaine.net »</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  En gros cela a du prendre 10 à 30 secondes selon votre rapidité à taper les commandes. Pour vérifier que ce n'est pas du bleuf, un petit tour sur une machine cliente s'impose :
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># vérification de l'utilisateur josette</div><div class='command'><span class='prompt'>root#</span>id josette</div><div class='result'>uid=1011(josette) gid=1011(totoches) groupes=1011(totoches)</div><div class='result'>&nbsp;</div><div class='co0'># vérification du nouveau host (si vous avez publié /etc/hosts)</div><div class='command'><span class='prompt'>root#</span>ping machine_josette.mon_domain.net</div><div class='result'>64 bytes from machine_josette.mon_domaine (10.0.0.12): icmp_seq=1 ttl=64 time=0.015 ms</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  Voilà, terminé. Maintenant il faut comparer cela au temps que cela aurait pris avec un serveur LDAP avec myLdapAdmin ou mieux... à la main en ligne de commande...
</p>  

	<a name='chapter_5'></a>
  <h2>Pour les portables</h2>
	
<p>
  Le soucis avec les authentification centralisée et les portables c'est que ce dernier ne sont pas toujours connecté au réseau. Du coup, impossible de contacter le serveur NIS et par voir de conséquence impossible de s'authentifier. 
</p>
<p>
  Pour régler ce problème de manière élégante nous allons utiliser <kbd>nscd</kbd> de manière plus avancée en modifiant un peu sa configuration. L'idée est d'obtenir quelque chose comme cela pour son fichier de configuration <kbd>/etc/nscd.conf</kbd>
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  reload-count &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;unlimited<br />
paranoia &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;no<br />
enable-cache &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
positive-time-to-live &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">604800</span><br />
negative-time-to-live &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">20</span><br />
suggested-size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">211</span><br />
check-files &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
persistent &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
shared &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/passwd"><span class="kw2">passwd</span></a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
<br />
enable-cache &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;group &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
positive-time-to-live &nbsp; group &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">604800</span><br />
negative-time-to-live &nbsp; group &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">60</span><br />
suggested-size &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;group &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">211</span><br />
check-files &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; group &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
persistent &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;group &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
shared &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;group &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/yes"><span class="kw2">yes</span></a><br />
<br />
enable-cache &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hosts &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; no &nbsp;
  </div>
  <div class='caption'>/etc/nscd.conf</div>
  </div>
</p>
<p>
  Ainsi configuré, le cache va être persistant, maintenu autant que fois que nécessaire (<kbd>reload-count</kbd>), d'une durée de vie de 7 jours (604800 secondes) et ce pour les tables <kbd>passwd</kbd> et <kbd>group</kbd>. A noter que <kbd>passwd</kbd> indique ce que c'est la table <kbd>/etc/passwd</kbd> distante qui est mise en cache, celle qui ne contient pas les mots de passe. 
</p>
<p>
  L'effet de cette configuration est qu'une fois <kbd>nscd</kbd> relancé, un utilisateur connecté au réseau qui s'authentifie peut continue à travailler sur sa machine même s'il est déconnecté du réseau. En revanche, s'il met fin à sa session, comme <kbd>shadow</kbd> n'est pas en cache, il ne pourra plus s'authentifier. 
</p>
<p>
  Pour pouvoir ouvrir une session hors du réseau la seule solution est... de ne pas utiliser de mot de passe et préférer une authentification par <a class='external' target='_blank' href='/node/1677' >empreinte digitale</a>, par <a class='external' target='_blank' href='/node/1164' >clef usb</a>, etc.
</p>


	<a name='chapter_6'></a>
  <h2>Conclusion</h2>
	
<p>
  J'étais passé de NIS à LDAP il y a un peu plus d'un an, pensant que ça allait me simplifier la vie. J'avoue que cela a été instructif car LDAP est un monde à part entière qu'il est pertinent d'au moins connaître un peu. Mais ce retour à NIS a été un vrai soulagement car même si c'est un petit réseau local, une partie de la complexité (le groupe d'accès à telle ou telle ressource via le net, le pote bidulo de passage sur le réseau, le bon ami à qui l'on crée un compte pour qu'il mate la machine pendant qu'on se dore la pilule, l'ajout de droits temporaire à la copine bidulette pour télécharger une vidéo, etc.) reste la même que pour un réseau plus grand à la différence que l'on a autre chose à faire de son temps que de jouer les administrateurs système...
</p>

    ]]></content>
  </entry>
  <entry>
    <title>Maîtriser le temps...</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1146" />
    <id>http://artisan.karma-lab.net/node/1146</id>
    <published>2008-10-21T16:14:02+02:00</published>
    <updated>2008-10-21T23:10:02+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="drupalfr.org" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
   Garder son PC à l'heure ou synchroniser plusieurs machines sur la même base de temps n'est pour diverses raisons pas toujours évident. Et pourtant c'est primordiale lorsque l'on est plusieurs à accéder à une même ressource, ou simplement pour éviter de louper un rendez-vous... 
</p>
<p>
  Les distributions règlent généralement ce problème en collant un serveur NTP en mémoire mais c'est un peu prendre un marteau pour écraser une mouche et surtout cela manque de souplesse. Voyons donc comment fonctionne le temps sur un PC, et sur GNU/Linux en particulier. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
   Garder son PC à l'heure ou synchroniser plusieurs machines sur la même base de temps n'est pour diverses raisons pas toujours évident. Et pourtant c'est primordiale lorsque l'on est plusieurs à accéder à une même ressource, ou simplement pour éviter de louper un rendez-vous... 
</p>
<p>
  Les distributions règlent généralement ce problème en collant un serveur NTP en mémoire mais c'est un peu prendre un marteau pour écraser une mouche et surtout cela manque de souplesse. Voyons donc comment fonctionne le temps sur un PC, et sur GNU/Linux en particulier. 
</p>
<!--break-->


	<a name='chapter_7'></a>
  <h2>Horloge Système</h2>
	
<p>
  Depuis que le PC est PC, il y a toujours eu deux horloges, l'une logicielle et l'autre matérielle. 
</p>
<p>
  L'horloge logicielle des premiers PC et PC/XT, était prise en charge par une puce 
  <a target='_blank' href='http://fr.wikipedia.org/wiki/Intel 8253'>
  Intel 8253
  </a> relevée avec les PC/AT par la <a class='external' target='_blank' href='http://ftp.utcluj.ro/pub/users/calceng/PMP/231164.pdf' >8254</a>. Ces puces "timer-counter" étaient programmées par le BIOS pour générer une interruption toutes les 54.936 secondes, soit environ 18.206 fois par secondes. A l'époque le manque de précision impliquant que l'horloge se désynchronisait avec la réalité en perdant en gros une minute par jours. Aujourd'hui les sources sont beaucoup plus précise avec des puces comme les <a class='external' target='_blank' href='http://www.netburner.com/downloads/mod5270/APPNOTE-MOD5270-PIT.pdf' >PIT</a> (Programmable Interrupt Timer) utilisé notamment par Linux (clock=pit au démarrage du kernel). 
</p>
<p> 
  La commande pour lire et écrire dans cette horloge est donc :
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># réglage de l'horloge, petite remontée dans le temps...</div><div class='command'><span class='prompt'>root#</span>date --set="9/22/96 16:45:05"</div><div class='result'>dim. sept. 22 16:45:05 CEST 1996</div><div class='result'>&nbsp;</div><div class='co0'># lecture du l'horloge système</div><div class='command'><span class='prompt'>root#</span>date</div><div class='result'>dim. sept. 22 16:45:17 CEST 1996</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
<p>
  Mais même si elle sont plus précise, les horloges logicielles gardent une lacune de taille, elle ne savent pas compter le temps lorsque le PC est éteint. 
</p>



	<a name='chapter_8'></a>
  <h2>Horloge Matérielle</h2>
	
<p>
<image file="Realtimeclock_Motherboard_Baby_AT_crop.jpg" width="200px"/>
  Cette horloge là est dite RTC (Real Time CLock) et prise en charge par un composant spécifique sur la carte mère (dans le temps, la fameuse "Dallas") même si aujourd'hui elle est de plus en plus intégrée au southbridge. Cette horloge est généralement basée sur un quartz qui oscille, comme celui des montres, à une fréquence de 32768Hz, soit 2<sup>15</sup> fois par secondes, ce qui est pratique pour le comptage binaire. Ce circuit a sa propre alimentation, par une simple pile au lithium ou un 
  <a target='_blank' href='http://fr.wikipedia.org/wiki/supercondensateur'>
  supercondensateur
  </a>. Le résultat en est une horloge relativement précise qui tourne tout le temps, même PC éteint. C'est aussi grâce à ce composant que l'on peut, via le BIOS, allumer un PC à une heure précise. 
</p>
<p>
  Pour lire et écrire dans l'horloge matérielle la commande est 
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># lecture de l'horloge (on remarque que c'est bien une heure différente de celle de "date")</div><div class='command'><span class='prompt'>root#</span>hwclock --show</div><div class='result'>mar. 21 oct. 2008 15:24:57 CEST  -0.408169 secondes</div><div class='result'>&nbsp;</div><div class='co0'># Réglage de l'heure hardware</div><div class='command'><span class='prompt'>root#</span>hwclock --set --date="9/22/98 16:45:05"</div><div class='result'>&nbsp;</div><div class='co0'># vérification</div><div class='command'><span class='prompt'>root#</span>hwclock --show</div><div class='result'>dim. 22 sept. 1998 16:45:09 CEST  -0.751474 secondes</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>
<p>
  Vous avez constaté en lançant ces commandes que la réaction n'est pas instantanée, en lecture comme en écriture, ce qui explique sûrement (mais je n'en suis pas bien sur) pourquoi les OS n'utilisent pas uniquement cette horloge. 
</p>
<p>
  Maintenant voyons comment synchroniser l'horloge matérielle avec l'horloge logicielle et inversement :

  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># Horloge interne -> système en utilisant le temps universel</div><div class='command'><span class='prompt'>root#</span>hwclock --hctosys --utc</div><div class='result'>&nbsp;</div><div class='co0'># L'horloge système est maintenant en 1998</div><div class='result'>&nbsp;</div><div class='co0'># Horloge système -> interne en utilisant le temps universel</div><div class='command'><span class='prompt'>root#</span>hwclock --systohc --utc</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>


	<a name='chapter_9'></a>
  <h2>Horloge distante</h2>
	
<p>
  Maintenant nos deux horloges sont bien sympathique mais qu'en est-il du "vrai" temps qui passe ? L'idéal pour être à l'heure est de la demander à un serveur qui sait de quoi il parle. Ce sont les serveurs NTP (Net Time Protocol). Et il y'en a de nombreux de disponible, alors autant en profiter.
</p>
<p>
 Le seul problème est que la majorité des distributions passent par une usine à gaz pour récupérer le temps sur un serveur distant en passant par l'installation locale d'un service <kbd>ntpd</kbd> alors que là aussi, il existe une commande faite pour cela.
</p>
<p>
  Cette commande c'est <kbd>ntpdate</kbd> du paquet <kbd>ntp-client</kbd> et son rôle est simplement de mettre à jour l'horloge système avec un serveur NTP distant. Ce serveur distant peut être sur <a class='external' target='_blank' href='http://www.pool.ntp.org/zone/europe' >Internel</a>, mais aussi installé <a class='external' target='_blank' href='http://blog.nicolargo.com/2008/10/installation-dun-serveur-ntp.html' >par vos soins</a>. 
</p>
<p>
  Une fois que vous votre adresse, ici j'utilise <kbd>fr.pool.ntp.org</kbd>, vous pouvez lancer la commande de synchronisation :

  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># récupération de l'heure du serveur NTP</div><div class='command'><span class='prompt'>root#</span>ntpdate -s -b fr.pool.ntp.org</div><div class='result'>&nbsp;</div><div class='co0'># Vérification de la synchronisation avec l'horloge système</div><div class='command'><span class='prompt'>root#</span>date</div><div class='result'>mar. oct. 21 15:40:27 CEST 2008</div><div class='result'>&nbsp;</div><div class='co0'># Et l'horloge matérielle est quant à elle encore en 1998</div><div class='command'><span class='prompt'>root#</span>hwclock --show</div><div class='result'>dim. 22 sept. 1998 16:59:15 CEST  -0.251837 secondes</div><div class='command'><span class='prompt'>root#</span><span class='cursor'>&nbsp;</span></div>
  </div>
  
  </div>
</p>


	<a name='chapter_10'></a>
  <h2>Mise en musique</h2>
	
<p>
  Maintenant nous n'avons plus qu'à mettre tout cela dans un script
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; <span class="co0">#! /bin/sh</span><br />
<br />
&nbsp; <span class="co0"># synchronisation serveur NTP -&gt; horloge logicielle</span><br />
&nbsp; <span class="sy0">/</span>usr<span class="sy0">/</span>sbin<span class="sy0">/</span>ntpdate -s -b fr.pool.ntp.org<br />
<br />
&nbsp; <span class="co0"># Quelque chose c'est mal passé ? </span><br />
&nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$?</span> <span class="sy0">!</span>= <span class="nu0">0</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; <span class="kw3">echo</span> <span class="st0">&quot;Erreur lors de la synchronisation de l'heure&quot;</span> <span class="sy0">&gt;</span> <span class="sy0">/</span>dev<span class="sy0">/</span>stderr<br />
&nbsp; <span class="kw1">else</span><br />
&nbsp; &nbsp; <span class="co0"># synchronisation horloge logicielle -&gt; horloge matérielle </span><br />
&nbsp; &nbsp; <span class="sy0">/</span>sbin<span class="sy0">/</span>hwclock --systohc --utc<br />
&nbsp; <span class="kw1">fi</span>
  </div>
  <div class='caption'>/sbin/sync-clock.sh</div>
  </div>
</p>
<p>
  Ce script peut être lancé à la main en cas de besoin ou mieux, être collé dans le CRON pour être exécuté sur une base journalière. Mais Comme le fait très justement remarquer Axone dans un commentaire un peu plus bas ce n'est pas très sympathique pour les serveurs distant su tout le monde les appelle à heure entière (ex. xx:00). Donc nous allons faire cela plus intelligemment en créant un fichier <kbd>/etc/cron.d/time-sync</kbd> :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="nu0">17</span> <span class="nu0">23</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">*</span> <span class="sy0">/</span>sbin<span class="sy0">/</span>sync-clock.<a target="blank" href="http://pwet.fr/man/linux/commandes/sh"><span class="kw2">sh</span></a>
  </div>
  <div class='caption'>/etc/cron.d/time-sync</div>
  </div>
</p>
<p>
  Ainsi la mise à jour est faite tous les jours à 23:17, ce qui limite bien les risques. 
</p>


	<a name='chapter_11'></a>
  <h2>Conclusion</h2>
	
<p>
   Voilà, pas de grosse artillerie donc pour simplement s'assurer que deux machines fonctionnent sur la même base de temps ou que votre portable ne vous fait pas louper un rendez-vous...
</p>
    ]]></content>
  </entry>
  <entry>
    <title>Créer un environnement de test &#039;la(p|m)p&#039; avec Chroot</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1055" />
    <id>http://artisan.karma-lab.net/node/1055</id>
    <published>2008-10-03T12:31:12+02:00</published>
    <updated>2008-10-28T22:12:27+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="drupalfr.org" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>
   Lorsque l'on a besoin de créer un environnement de test il est nécessaire que sa composition soit strictement contrôlé (paramétrages, applications et services disponibles et lancées, etc). Il n'est du coup généralement pas conseillé d'utiliser sa machine de travail, sauf si elle ne sert qu'à cela, sous peine d'en détériorer le fonctionnement en cas de test malheureux ou de modifier sans le vouloir le comportement de ce que l'on cherche à tester. Nous sommes alors contraints d'avoir soit une machine virtuelle dédiée aux tests, soit une machine physique supplémentaire. 
</p>
<p>
  Ce serait sans compter sur la commande <kbd>chroot</kbd> qui permet dans certaines conditions d'obtenir un environnement de test ou d'intégration identique à celui en production, sans machine physique supplémentaire et sans que la machine principale soit ralentie ou compromise. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
   Lorsque l'on a besoin de créer un environnement de test il est nécessaire que sa composition soit strictement contrôlé (paramétrages, applications et services disponibles et lancées, etc). Il n'est du coup généralement pas conseillé d'utiliser sa machine de travail, sauf si elle ne sert qu'à cela, sous peine d'en détériorer le fonctionnement en cas de test malheureux ou de modifier sans le vouloir le comportement de ce que l'on cherche à tester. Nous sommes alors contraints d'avoir soit une machine virtuelle dédiée aux tests, soit une machine physique supplémentaire. 
</p>
<p>
  Ce serait sans compter sur la commande <kbd>chroot</kbd> qui permet dans certaines conditions d'obtenir un environnement de test ou d'intégration identique à celui en production, sans machine physique supplémentaire et sans que la machine principale soit ralentie ou compromise. 
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Qu'est-ce qu'un chroot?</h2>
	
<p>
  Comme vous le savez sûrement déjà, le système fichier d'un *NIX est construit autour d'une racine (le <kbd>/</kbd>) sur laquelle les partitions sont ensuite "montées" formant ainsi l'espace de fichier accessible. Ce que l'on sait moins c'est que cette racine est un paramètre du processus. Tout processus lancé peut avoir pour racine un chemin arbitraire issu de celle de son processus parent. Si ce paramètre n'est pas définit, ce qui est généralement le cas, c'est '/' qui est utilisé par défaut, en quelque sorte la racine de la racine du parent. La commande <kbd>chroot</kbd> permet de lancer une commande et dans la foulée de définir ce paramètre pour le processus engendré. 
</p>
<p>
  La commande <kbd>chroot</kbd> peut donc avoir deux paramètres principaux : un chemin dans l'arborescence et une commande. Ainsi, si en tant qu'utilisateur <kbd>root</kbd> nous lançons <kbd>chroot /lapp /bin/bash</kbd>, voilà ce qui se passe :
  <ol>
   <li>La commande <kbd>chroot</kbd> engendre un processus qui a pour racine la même que celle de son processus parent, généralement le <kbd>/</kbd> (mais rien n'empêche de faire des poupées russes...).</li>
   <li>En interne, <kbd>chroot</kbd> appel de la fonction kernel <kbd>chroot("/lapp")</kbd>. Le kernel va donc modifier la valeur de la racine pour ce processus et lui associer la valeur <kbd>/lapp</kbd>.</li>
   <li>Le processus de <kbd>chroot</kbd>, exécute la commande passée en 2nd paramètre, <kbd>/bin/bash</kbd>. Comme la racine de <kbd>chroot</kbd> a été changée, c'est en quelque sorte bien le <kbd>/bin/bash</kbd> à partir de la nouvelle racine <kbd>/lapp</kbd> qui va être exécuté.</li>
   <li>Cette exécution débouche sur la création d'un processus fils de celui du <kbd>chroot</kbd> qui hérite donc de cette nouvelle racine.</li>
   <li>Tout ce que <kbd>/bin/bash</kbd> lancera par la suite héritera de cette nouvelle racine jusqu'à ce que l'on tape <kbd>exit</kbd> qui mettra fin au processus <kbd>/bin/bash</kbd>, et par domino à celui du <kbd>chroot</kbd> qui a permis son lancement.
  </ol>
</p>

<p>
  Le premier constat que nous pouvons tire de cela est qu'il faut que notre dossier <kbd>/lapp</kbd> contienne un <kbd>bin/bash</kbd>, mais aussi toutes les librairies dont a besoin <kbd>bash</kbd> pour fonctionner, ainsi que tous les dossiers systèmes qui lui sont nécessaire et qu'il s'attend à trouver comme sous une "vraie" racine. Ainsi la seule problématique posée sera le peuplement de notre nouvelle racine. 
</p>
<p>
  Le second constat est qu'un chroot <strong>n'est pas une virtualisation</strong>. Une virtualisation définit des conteneurs bien hermétiques avec leur mémoire propre, leur espace disque propre, leurs périphériques propres, etc. Le chroot ne fait rien de tout cela. La mémoire, le CPU, les périphériques (réseau, disque, écran, etc) sont partagées par l'environnement racine et chrooté. C'est d'ailleurs pour cela qu'un chroot est aussi rapide que si tout était lancé sur la racine principale. 
</p>
<p>
  Chroot ne fait donc que "faire croire" à un processus qu'il travaille sous la "vraie racine" alors qu'il n'est que dans un sous-dossier. Ainsi la seule garantie que fournit le <kbd>chroot</kbd> est l'<strong>étanchéité des fichiers</strong> dans le sens enfant-parent. C'est pour cet aspect que le <kbd>chroot</kbd> est d'ailleurs généralement utilisé, pour "mettre en prison" des applications critiques (serveur web, serveur mail, etc.) de sorte à ce que si une vulnérabilité permet à un cracker de casser le serveur, il ne puisse atteindre les fichiers se trouvant hors du chroot et ainsi limiter les dégâts. A noter que ce billet <strong>ne traite pas</strong> de cette utilisation critique du chroot et que d'un point de vue général il existe nombre d'exploits permettant de s'échapper de cette prison. 
</p>

<p>
  Malgré ses limitations, le <kbd>chroot</kbd> est juste parfait pour une utilisation : la création d'un environnement de test et/ou d'intégration pour des applications WEB. Il permet en effet très facilement de créer une configuration LA(P|M)P (Linux-Apache-Postgres/MySQL-PHP), facile à maintenir, facile à recréer, testable de la machine principale sans modification particulière comme si tout était installé "localement". 
</p>


	<a name='chapter_2'></a>
  <h2>Mise en oeuvre</h2>
	
<p>
  Notre but est donc ici de créer un environnement chrooté comprenant un Linux de base, Apache, Postgresql et PHP. La première étape est donc de créer notre future racine. Je le fait en <kbd>/lapp</kbd> mais cela pourrait être virtuellement n'importe où, y compris sur le dossier d'une clef mémoire ou sur un espace volatile type <kbD>tmpfs</kbd>. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> <a target="blank" href="http://pwet.fr/man/linux/commandes/mkdir"><span class="kw2">mkdir</span></a> <span class="sy0">/</span>lapp
  </div>
  
  </div>
</p>
<p>
  Maintenant vient le moment de peupler notre racine. Là, il y a trois approches possibles. 
</p>
<p>
  Nous avons l'approche dite "bourrine" consistant à dupliquer sauvagement son environnement principal :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://pwet.fr/man/linux/commandes/cp"><span class="kw2">cp</span></a> -a <span class="sy0">/</span>usr <span class="sy0">/</span>bin <span class="sy0">/</span>lib <span class="sy0">/</span>sbin <span class="sy0">/</span>var <span class="sy0">/</span>lapp
  </div>
  
  </div>
</p>
<p>
  L'inconvénient est que c'est souvent très volumineux et peu adapté à un environnement de test contrôlé dans la mesure où des tas de choses inutiles sont injectées dans la nouvelle racine. 
</p>
<p>
  Ensuite il y a l'approche "minimaliste" qui cherche à ne copier que ce qui est nécessaire. Cela peut se faire à la main avec la commande <kbd>ldd</kbd> ou beaucoup plus simplement, comme me l'a indiqué Guyou, avec les outils <a class='external' target='_blank' href='http://www.floc.net/makejail/' >makejail</a> ou <a class='external' target='_blank' href='http://freshmeat.net/projects/chrootbin/' >chrootbin</a>. Mais cette technique est plus adaptée au lancement d'un serveur dans une prison chroot qu'à notre besoin. 
</p>
<p>
  Enfin nous avons l'approche "raisonnable" consistant à utiliser les outils fournis par les debian's et autres mandriva's qui permettant d'installer tout simplement sur une racine arbitraire une distribution complète. C'est clairement dans notre cas cette approche qui s'impose. 
</p>
<p>
  Sous mandriva (et distributions dérivées), l'installation d'un linux de base sur une racine se fait simplement par la commande suivante :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> urpmi basesystem urpmi locales-fr --root <span class="sy0">/</span>lapp
  </div>
  
  </div>
</p>

<p>
  Simple et diablement efficace. Comme vous l'aurez noté, ce sont trois paquets qui sont ici installés: le linux de base, la langue française et le système de gestion de paquets. Ce dernier point nous offrira beaucoup de souplesse car au sein même du chroot il sera du coup possible d'installer, désinstaller ou même mettre à jour la distribution.
</p>
<div class='inline-box note'>
  A noter que ce n'est pas du "one shot", il est toujours possible d'ajouter des paquets à la racine "de l'exterieur" par :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> urpmi un_paquer --root <span class="sy0">/</span>lapp
  </div>
  
  </div>
</div>

<p>
  Les distributions basées sur debian disposent elle aussi d'une méthode très efficace pour créer une racine minimale en utilisant cette fois la commande <kbd>debootsrap</kbd>. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> debootstrap --arch i386 &nbsp;--<span class="re2">include=</span>locales-all &nbsp;sid <span class="sy0">/</span>lapp http:<span class="sy0">//</span><a target="blank" href="http://pwet.fr/man/linux/commandes/ftp"><span class="kw2">ftp</span></a>.fr.debian.org<span class="sy0">/</span>debian
  </div>
  
  </div>
</p>

<p>
  Vous pouvez remplacer <kbd>sid</kbd> par toute distribution debian disponible (etch, sarge, etc..). Pour le reste cela fonctionne comme la méthode précédente a la différence que la gestion de paquet n'est pas optionnelle et vous aurez donc automatiquement accès à apt-get dans le chroot. 
</p>

<div class='inline-box note'>
   Un détail intéressant est que la commande <kbd>debootstrap</kbd> est aussi disponible sous Mandriva et vous permet sans aucun problème, d'installer une racine de debian dans une mandriva. 
</div>


<p>
  Notre racine étant maintenant peuplée et les utilitaires que nous avons utilisé ont normalement pris soin de créer à la "racine" les dossier vitaux <kbd>tmp</kbd>, <kbd>var</kbd>, <kbd>dev</kbd>, <kbd>sys</kbd> et <kbd>proc</kbd>. Si ce n'est pas le cas, faites le vous-même. 
</p>

<p>
  Maintenant comme vous le savez, certains dossiers de Linux ne sont pas de "vrais" dossier mais une vue sur des variables du système. C'est le cas de <kbd>/proc</kbd>, <kbd>/sys</kbd> et <kbd>/dev</kbd>. Si nous lancions maintenant notre nouvelle racine, ces dossiers seraient donc vides provoquant des erreurs sur certaines fonctions. Il nous faut donc avant monter ces dossiers. Pour ce faire, nous allons simplement les "relier" (mount --bind) aux mêmes dossiers de la vraie racine.

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> <a target="blank" href="http://pwet.fr/man/linux/commandes/mount"><span class="kw2">mount</span></a> -bind <span class="sy0">/</span>dev <span class="sy0">/</span>lapp<span class="sy0">/</span>dev <br />
<a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> <a target="blank" href="http://pwet.fr/man/linux/commandes/mount"><span class="kw2">mount</span></a> -bind <span class="sy0">/</span>proc <span class="sy0">/</span>lapp<span class="sy0">/</span>proc<br />
<a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> <a target="blank" href="http://pwet.fr/man/linux/commandes/mount"><span class="kw2">mount</span></a> -bind <span class="sy0">/</span>sys <span class="sy0">/</span>lapp<span class="sy0">/</span>sys
  </div>
  
  </div>
</p>

<p>
  Concernant le réseau dans un chroot, la configuration sera la même que celle de l'environnement parent. Tout fonctionnera donc sans avoir à faire quoi que ce soit. En revanche il est important de vérifier que la résolution de noms se fait correctement. Pour cela nous allons simplement recopier le fichier <kbd>/etc/resolv</kbd> :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://pwet.fr/man/linux/commandes/cp"><span class="kw2">cp</span></a> <span class="sy0">/</span>etc<span class="sy0">/</span>resolv.conf <span class="sy0">/</span>lapp<span class="sy0">/</span>etc<span class="sy0">/</span>resolv.conf
  </div>
  
  </div>
</p>

<p>
Maintenant tout est en place, c'est le moment du lancement. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://pwet.fr/man/linux/commandes/sudo"><span class="kw2">sudo</span></a> <a target="blank" href="http://pwet.fr/man/linux/commandes/chroot"><span class="kw2">chroot</span></a> <span class="sy0">/</span>lapp <span class="sy0">/</span>bin<span class="sy0">/</span>bash
  </div>
  
  </div>
</p>

<p>
  Voilà, une fois ceci exécuté, nous sommes "prisonnier" de la nouvelle racine et toutes les commandes qui suivent sont contrainte dans cet espace. Pour en sortir il suffit de faire un "exit". Comme vous le voyez tout fonctionne, vous pouvez utiliser le réseau, installer des paquets, etc. C'est ce que nous allons faire pour mettre en place notre environnement de test :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  urpmi apache-mod_php postgresql-server
  </div>
  
  </div>
</p>

<p>
  Ceci fait, vous pouvez constater que votre système fonctionne en lançant les services :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="sy0">/</span>etc<span class="sy0">/</span>init.d<span class="sy0">/</span>httpd start<br />
<span class="sy0">/</span>etc<span class="sy0">/</span>init.d<span class="sy0">/</span>postgresql start
  </div>
  
  </div>
</p>
<p>
  Maintenant, en allant, sur votre environnement principal aidé d'un navigateur web sur l'adresse <kbd>http://localhost</kbd>, vous devriez avoir accès à la page de test du serveur Apache. Pour le reste, à vous de jouer...
</p>


	<a name='chapter_3'></a>
  <h2>Automatisation</h2>
	
<p>
   Comme vous l'aurez constaté, le chroot n'effectue pas, et heureusement, un démarrage réel du linux installé à la nouvelle racine. Il se contente d'exécuter <kbd>/bin/bash</kbd> ce qui vous oblige de votre côté à lancer les services à la main. 
</p>
<p>
  Pour rendre cela beaucoup plus simple à utiliser sur une base quotidienne, le plus propre reste de créer un service dédié au lancement de notre racine qui va créer le montages et lancer apache, postgres, etc... Son arrêt ferra l'inverse :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co0">#!/bin/sh</span><br />
<br />
<span class="co0"># chkconfig: 345 56 50</span><br />
<span class="co0"># description: This startup script launches Chroot Starter</span><br />
<br />
<span class="co0">### BEGIN INIT INFO</span><br />
<span class="co0"># Provides: lappd</span><br />
<span class="co0"># Required-Start: </span><br />
<span class="co0"># Required-Stop: </span><br />
<span class="co0"># Default-Start: 345</span><br />
<span class="co0"># Short-Description: Chroot Starter</span><br />
<span class="co0"># Description: This startup script launches Chroot Starter</span><br />
<span class="co0">### END INIT INFO</span><br />
<br />
<span class="re2">PATH=</span><span class="sy0">/</span>usr<span class="sy0">/</span>sbin:<span class="sy0">/</span>usr<span class="sy0">/</span>bin:<span class="sy0">/</span>sbin:<span class="sy0">/</span>bin<br />
<span class="re2">NAME=</span>lapp<br />
<span class="re2">DESC=</span><span class="st0">&quot;Chroot Starter for $NAME&quot;</span><br />
<span class="re2">ROOT=</span><span class="sy0">/</span><span class="re1">$NAME</span><br />
<br />
<span class="co0"># Source function library.</span><br />
. <span class="sy0">/</span>etc<span class="sy0">/</span>init.d<span class="sy0">/</span>functions<br />
<br />
<span class="kw1">case</span> <span class="st0">&quot;$1&quot;</span> <span class="kw1">in</span><br />
&nbsp; start<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="sy0">!</span> -z <span class="st0">&quot;$(mount | grep $ROOT)&quot;</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; gprintf <span class="st0">&quot;$NAME is already started<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">3</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
<br />
&nbsp; &nbsp; gprintf <span class="st0">&quot;Starting chroot for %s&quot;</span> <span class="st0">&quot;$NAME&quot;</span><br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/mount"><span class="kw2">mount</span></a> --bind <span class="sy0">/</span>proc <span class="re1">$ROOT</span><span class="sy0">/</span>proc<br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/mount"><span class="kw2">mount</span></a> --bind <span class="sy0">/</span>dev <span class="re1">$ROOT</span><span class="sy0">/</span>dev<br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/mount"><span class="kw2">mount</span></a> --bind <span class="sy0">/</span>sys <span class="re1">$ROOT</span><span class="sy0">/</span>sys<br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/chroot"><span class="kw2">chroot</span></a> <span class="re1">$ROOT</span> <span class="sy0">/</span>init.<a target="blank" href="http://pwet.fr/man/linux/commandes/sh"><span class="kw2">sh</span></a> start<br />
&nbsp; &nbsp; echo_success<br />
&nbsp; &nbsp; <span class="kw3">echo</span><br />
&nbsp; &nbsp; <span class="sy0">;;</span><br />
<br />
&nbsp; stop<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> -z <span class="st0">&quot;$(mount | grep $ROOT)&quot;</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; gprintf <span class="st0">&quot;$NAME is already stopped<span class="es0">\n</span>&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">3</span><br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
<br />
&nbsp; &nbsp; gprintf <span class="st0">&quot;Stopping chroot for %s&quot;</span> <span class="st0">&quot;$NAME&quot;</span><br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/chroot"><span class="kw2">chroot</span></a> <span class="re1">$ROOT</span> <span class="sy0">/</span>init.<a target="blank" href="http://pwet.fr/man/linux/commandes/sh"><span class="kw2">sh</span></a> stop<br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/umount"><span class="kw2">umount</span></a> <span class="re1">$ROOT</span><span class="sy0">/</span>proc <br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$?</span> -ne <span class="nu0">0</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; echo_failure<br />
&nbsp; &nbsp; &nbsp; <span class="kw3">echo</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">3</span>;<br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/umount"><span class="kw2">umount</span></a> <span class="re1">$ROOT</span><span class="sy0">/</span>dev<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$?</span> -ne <span class="nu0">0</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; echo_failure<br />
&nbsp; &nbsp; &nbsp; <span class="kw3">echo</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">3</span>;<br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
&nbsp; &nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/umount"><span class="kw2">umount</span></a> <span class="re1">$ROOT</span><span class="sy0">/</span>sys<br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#91;</span> <span class="re4">$?</span> -ne <span class="nu0">0</span> <span class="br0">&#93;</span> ; <span class="kw1">then</span><br />
&nbsp; &nbsp; &nbsp; echo_failure<br />
&nbsp; &nbsp; &nbsp; <span class="kw3">echo</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">3</span>;<br />
&nbsp; &nbsp; <span class="kw1">fi</span><br />
&nbsp; &nbsp; echo_success<br />
&nbsp; &nbsp; <span class="kw3">echo</span><br />
&nbsp; &nbsp; <span class="kw3">exit</span> <span class="nu0">0</span><br />
&nbsp; &nbsp; <span class="sy0">;;</span><br />
<br />
&nbsp; restart<span class="sy0">|</span>force-reload<span class="br0">&#41;</span><br />
&nbsp; &nbsp; $<span class="nu0">0</span> stop<br />
&nbsp; <a target="blank" href="http://pwet.fr/man/linux/commandes/sleep"><span class="kw2">sleep</span></a> <span class="nu0">1</span><br />
&nbsp; &nbsp; $<span class="nu0">0</span> start<br />
&nbsp; &nbsp; <span class="sy0">;;</span><br />
<span class="kw1">esac</span><br />
<span class="kw3">exit</span> <span class="nu0">0</span>
  </div>
  <div class='caption'>/etc/init.d/lapp</div>
  </div>
</p>
<p>
  Ensuite dans notre racine il faut rajouter, et rendre exécutable, un fichier <kbd>/init.sh</kbd> contenant le démarrage/arrêt des services <kbd>httpd</kbd> et <kbd>postgresql</kbd>, et qui prendra en paramètre <kbd>start</kbd> ou <kbd>stop</kbd> :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co0">#! /bin/sh </span><br />
<br />
<span class="sy0">/</span>etc<span class="sy0">/</span>init.d<span class="sy0">/</span>httpd $<span class="nu0">1</span><br />
<span class="sy0">/</span>etc<span class="sy0">/</span>init.d<span class="sy0">/</span>postgresql $<span class="nu0">1</span>
  </div>
  <div class='caption'>/init.sh</div>
  </div>
</p>
<p>
  Après, vous pouvez rendre le lancement de ce service automatique (avec <kbd>chkconfig</kbd> ou l'outil dédié à cela pour votre distribution), ou faire cela à la main :
  
  <div class='code-block code-block-traces'>
  <div class='container'>
  <div class='co0'># lancement du service</div><div class='command'><span class='prompt'>gaston$</span>sudo /etc/init.d/lapp start</div><div class='result'>Starting chroot for lapp                                        [  OK  ]</div><div class='result'>&nbsp;</div><div class='co0'># ouverture d'une session sur la racine</div><div class='command'><span class='prompt'>gaston$</span>sudo chroot /lapp /bin/sh</div><div class='co0'># ...</div><div class='co0'># exit</div><div class='result'>&nbsp;</div><div class='co0'># extinction du service</div><div class='command'><span class='prompt'>gaston$</span>sudo /etc/init.d/lapp stop</div><div class='result'>Starting chroot for lapp                                        [  OK  ]</div><div class='command'><span class='prompt'>gaston$</span><span class='cursor'>&nbsp;</span></div>
  </div>
  <div class='caption'>exemple d&#039;utilisation</div>
  </div>
</p>
<p>
  Personnellement j'ai mis ce service en démarrage manuel et ajouté un profile dans <kbd>gnome-terminal</kbd> qui me lance directement la commande <kbd>chroot /lapp /bin/sh</kbd>. 
</p>



	<a name='chapter_4'></a>
  <h2>Conclusion</h2>
	
<p>
La commande chroot ne manque donc pas d'intérêt en restant très simple à mettre en oeuvre si on en saisi bien les fondamentaux. C'est une bonne alternative à la "lourdeur" de la virtualisation et permet de créer à une vitesse record des environnements de développement rapides, efficaces et non-polluant pour le reste du système. 
</p>

    ]]></content>
  </entry>
  <entry>
    <title>Mise en oeuvre d&#039;un serveur MPD</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1603" />
    <id>http://artisan.karma-lab.net/node/1603</id>
    <published>2008-08-09T16:49:41+02:00</published>
    <updated>2008-08-09T16:52:21+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="Serveurs" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p>
   MPD est finalement assez peu connu et pourtant, dans le cadre d'une <a class='external' target='_blank' href='/node/1310' >architecture domestique</a>, il répond au besoin récurrent des mélomanes qui aiment à donner une ambiance musicale différente à chacune de leurs pièces. L'objectif de ce tutoriel est de vous proposer une simple "mise en scelle", le monde MPD étant juste une vaste trop pour le couvrir d'une seul passe...</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
   MPD est finalement assez peu connu et pourtant, dans le cadre d'une <a class='external' target='_blank' href='/node/1310' >architecture domestique</a>, il répond au besoin récurrent des mélomanes qui aiment à donner une ambiance musicale différente à chacune de leurs pièces. L'objectif de ce tutoriel est de vous proposer une simple "mise en scelle", le monde MPD étant juste une vaste trop pour le couvrir d'une seul passe...</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Qu'est-ce que MPD ?</h2>
	
<image file="overview.png"/>
<p>
    MPD (<a class='external' target='_blank' href='http://www.musicpd.org' >Music Player Daemon</a>) c'est :
    <ul>
       <li>Un lecteur audio multi-formats entièrement contrôlable à travers le réseau.</li>
       <li>Un explorateur d'audiothèques capable de stocker les étiquettes (ID3 &amp; co.) de vos morceaux dans une base de donéne et d'y effectuer des recherches.</li>
       <li>Un gestionnaire de liste de lecture (playlist).</li>
     </ul>
</p> 
<p>
   A l'inverse, 
   <ul>
   	<li>MPD n'est pas un lecteur de vidéo, diapos &amp; co.</li>
   	<li>MPD ne dispose pas d'une belle interface.</li>
   	<li>MPD n'embarque pas de serveur WEB/AJAX.</li>
   	<li>MPD n'est absolument pas sexy et n'impressionnera jamais vos amis.</li>
   </ul>
</p>
<p>
   En somme, MPD n'a (à mon sens) d'intérêt que dans trois cas de figure :
   <ul>
   <li>Lorsque l'on a chargé une machine sans écran, ni clavier de la sonorisation d'un espace.</li>
   <li>Lorsque plusieurs personnes sont amenées à prendre la main sur la musique diffusée, chacune avec un outil différent.</li>
   <li>Lorsque l'on désire diffuser de l'audio en mode "shoutcast", via <a class='external' target='_blank' href='http://www.icecast.org/' >Icecast</a> (ce n'est pas le sujet de ce tutoriel cependant).  
</ul>
</p>



	<a name='chapter_2'></a>
  <h2>Mise en oeuvre</h2>
	
<h3>Installation</h3>
<p>
   Là, rien de très sorcier. MPD est sans aucun doute déjà dans votre distribution. Un coup d'<kbd>urpmi mpd</kbd> ou d'<kbd>apt-get install mpd</kbd> devrait suffire à installer le serveur. Ensuite tout ce passe dans le fichier <kbd>/etc/mpd.conf</kbd>.
</p>


	<a name='chapter_3'></a>
  <h2>Les fichiers audio</h2>
	
<p>
   Pour que MPD puisse fonctionner, il lui faut... de la musique et peu importe, ou presque, le format. MPD peut lire les fichier mp3, mp2, ogg, flac, wav, au, aiff, aif, mpc, amf, dsm, far, gdm, imf, it, med, mod, mtm, s3m, stm, stx, ult, uni et xm. Il existe même une version plus "underground" lisant les AAC (dispo sur le dépôt PLF pour les mandriva il me semble).</p>
<p>
  Les fichiers audio doivent être accessible en local par MPD. Si vous avez plusieurs instances, vous la placerez donc dans un dossier partagé, par exemple NFS. Dans la suite du tutoriel, nous partirons du principe que vos morceaux se trouver dans le dossier <kbd>/musique</kbd>. 
</p>
<p>
  Dans le fichier <kbd>/etc/mpd.conf</kbd>, il vous faut repérer un bloc ressemblant à cela 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  music_directory &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;~/music&quot;</span><br />
playlist_directory &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;~/playlists&quot;</span><br />
db_file &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;/var/lib/mpd/mpd.db&quot;</span>
  </div>
  
  </div>
</p>
<p>
  Il s'agit de tous les chemins dont a absolument besoin MPD pour fonctionner. La première ligne correspond à la source de fichier audio, nous remplaçons donc comme suit :
    
  <div class='code-block code-block-fragment'>
  <div class='container'>
  music_directory &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;/musique&quot;</span>
  </div>
  
  </div>
</p>
<p>
 La seconde ligne correspond au dossier dans lequel MPD lit et écrit les listes de lectures (fichiers .m3u au format WinAmp). Comme il est sympa de pouvoir partager ces listes entre tous les serveurs MPD, le plus simple est de créer un sous-dossier <kbd>/musique/mdp</kbd>  :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  playlist_directory &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;/musique/mdp&quot;</span>
  </div>
  
  </div>
</p>
<p>
   Ensuite vient la base de donnée qui  contiendra les chemins, les étiquettes, bref, tout ce que MPD découvrira dans le dossier <kbd>/musique</kbd>. Là aussi, il est pratique qu'elle soit partagé car ainsi la création et la mis à jour de cette base sur une machine, sera effective sur toutes les autres :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  db_file &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;/musique/mdp&quot;</span>
  </div>
  
  </div></p>
  
  <h3>Petit cas de droit</h3>
<p>
   Maintenant la partie un peu funky. Un peu plus loin dans le fichier vous devez trouvez quelque chose comme cela :
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  user &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;mpd&quot;</span>
  </div>
  
  </div>
</p>
<p>
  L'idée est que lancer MPD en tant que root, c'est comme croiser les flux, c'est mal. Donc à l'installation du paquet, un gentil utilisateur <kbd>mpd</kbd> bien inoffensif a été créé. Et en toute logique cette utilisateur là n'a aucun droit de lecture, et encore moins d'écriture dans votre dossier <kbd>/musique</kbd>. 
</p>
<p>
   Je ne vais pas rentrer plus avant dans la manière de régler ce "problème" car chacun a son approche. Personnellement j'ai opté pour la création d'un groupe "acces-audio" qui a le même ID sur toutes mes machines. L'utilisateur <kbd>MPD</kbd> appartient à ce groupe. Et tout le dossier musique appartient lui aussi à ce groupe en lecture, et en écriture sur le dossier <kbd>/musique/mpd</kbd>.</p>
<p>
   Vous pouvez aussi prendre la posture barbare du <kbd>chmod g+rwX /musique</kbd> mais à ce moment là, autant dire à MPD d'utiliser "root" comme utilisateur...</p>
<p>
  Enfin, vous pouvez utiliser le fait que l'utilisateur <kbd>mpd</kbd> appartient généralement au groupe <kbd>audio</kbd> et du coup attribuer ce groupe au dossier <kbd>/musique</kbd> comme je le fait pour mon <kbd>acces-audio</kbd>.</p>

<p>
   Bref, c'est ici une histoire de goût et le point important est que l'utilisateur qui lance MPD puisse lire dans <kbd>/musique</kbd> et écrire dans <kbd>/musique/mpd</kbd>, et ce sur toutes les machines où il doit être lancé. 
</p>

<h3>Sorties Audio</h3>
<p>
  MPD est conçu de sorte à pouvoir gérer en simultané plusieurs sorties audio. Il est donc possible avec plusieurs cartes audio de distribuer la même musique sur plusieurs pièces à partir d'un seul serveur. La majorité des clients MPD permettent d'activer ou de désactiver telle ou telle sortie à distance. 
</p>
<p>
  Une sortie MPD peut utiliser les pilotes ALSA ou OSS, les serveurs audio Jack ou Pulse, ou encore un serveur de type ShoutCast. Et si cela ne suffit pas, vous pouvez passer par <a class='external' target='_blank' href='http://xiph.org/ao/' >libao</a> qui permet d'attraper un serveur ESD par exemple. 
</p>

<p>
  Dans notre cas, faisons simple. Déjà si vous avez Pulse d'installé, personnellement je le virerait... Cela se fait très facilement sur une Mandriva en passant par Drakconf. Pulse est bien sympa sur l'idée mais je ne vois pas bien son intérêt en local. </p>

<p>Nous allons donc utiliser une toute classique périphérique audio en utilisant ALSA.  Pour cela il faut aller jeter un oeil un peu plus loin dans le fichier de configuration et chercher les sections nommées <kbd>audio_output</kbd>. Si vous en avez aucune ou si elles sont toutes commentées, ajoutez ce qui suit, sinon vérifiez que ça ressemble un peu à cela :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp;audio_output <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw3">type</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;alsa&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;Sortie vers Chambre&quot;</span><br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
  Si je vous avez une deuxième carte audio, vous pouvez donc ajouter une seconde sortie : 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  audio_output <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw3">type</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;alsa&quot;</span><br />
&nbsp; &nbsp; &nbsp; name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;Sortie vers Buanderie&quot;</span><br />
&nbsp; &nbsp; &nbsp; device &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">&quot;hw:0,1&quot;</span> <br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
   Notez le paramètre <kbD>device</kbd> qui indique que le tape sur le deuxième périphérique ALSA (le premier étant sous entendu dans la première sortie comme étant hw:0,0). 
</p>

<p>
   A ce stade certain peuvent se demander pourquoi ne pas utiliser plutôt un ou plusieurs serveurs, de type ESD ou Pulse sur les machines qui diffuse physiquement l'audio. Si c'est faisable, la réponse est "est-ce rentable ?". Car enfet, cela revient à transbahuter un signal PCM sûrement un peu compressé sur mon réseau. Avec MPD, j'utilise un partage (NFS, CIFS, etc.) qui transporte des fichiers compressés en OGG ou en MP3... D'un point de vue occupation de bande passante je suis clairement gagnant dans le second cas. Pulse & co ont sûrement un usage, mais je ne pense pas que ce soit celui-là. Et c'est à peu prés la même chose pour diffuser du shoutcast. C'est sûrement très bien pour des utilisations de votre musique en extérieur (genre ce que permet <a class='external' target='_blank' href='http://ampache.org/' >Ampache</a>), mais pour des amplis fixes, je ne vois pas bien l'intérêt...
</p>

<p>
  Dernier aspect, le contrôle du volume. Comme pour les sorties audio, vérifiez que les lignes suivantes existent, ne sont pas commentées et concordent bien :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; mixer_type &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &