blog.notmyidea.org/status-board-fr.html
2019-07-02 22:54:50 +00:00

248 lines
No EOL
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<title>Status board - Carnets Web</title>
<meta charset="utf-8" />
<link href="https://blog.notmyidea.org/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Carnets Web Full Atom Feed" />
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/poole.css"/>
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/syntax.css"/>
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/lanyon.css"/>
<link rel="stylesheet" href="//fonts.googleapis.com/css?family=PT+Serif:400,400italic,700%7CPT+Sans:400">
<link rel="stylesheet" href="https://blog.notmyidea.org/theme/css/styles.css"/>
<style>
h1 {
font-family: "Avant Garde", Avantgarde, "Century Gothic", CenturyGothic, "AppleGothic", sans-serif;
padding: 80px 50px;
text-align: center;
text-transform: uppercase;
text-rendering: optimizeLegibility;
color: #202020;
letter-spacing: .1em;
text-shadow:
-1px -1px 1px #111,
2px 2px 1px #eaeaea;
}
#main {
text-align: justify;
text-justify: inter-word;
}
#main h1 {
padding: 10px;
}
.post-headline {
padding: 15px;
}
</style>
</head>
<body>
<!-- Target for toggling the sidebar `.sidebar-checkbox` is for regular
styles, `#sidebar-checkbox` for behavior. -->
<input type="checkbox" class="sidebar-checkbox" id="sidebar-checkbox">
<!-- Toggleable sidebar -->
<div class="sidebar" id="sidebar">
<div class="sidebar-item">
<div class="profile">
<img src="https://blog.notmyidea.org/theme/img/profile.png"/>
</div>
</div>
<nav class="sidebar-nav">
<a class="sidebar-nav-item" href="/">Articles</a>
<a class="sidebar-nav-item" href="https://www.vieuxsinge.com">Brasserie du Vieux Singe</a>
<a class="sidebar-nav-item" href="http://blog.notmyidea.org/pages/about.html">A propos</a>
<a class="sidebar-nav-item" href="https://twitter.com/ametaireau">Messages courts</a>
<a class="sidebar-nav-item" href="https://github.com/almet">Code</a>
</nav>
</div> <div class="wrap">
<div class="masthead">
<div class="container">
<h3 class="masthead-title">
<a href="https://blog.notmyidea.org/" title="Home">Carnets Web</a>
</h3>
</div>
</div>
<div class="container content">
<div id="main" class="posts">
<h1 class="post-title">Status board</h1>
<span class="post-date">29 décembre 2012</span>
<img id="illustration" src="" />
<div class="post article">
<h1>🌟</h1>
<p>À force de démarrer des services web pour un oui et pour un non, de proposer
à des copains d'héberger leurs sites, de faire pareil pour quelques assos etc,
je me suis retrouvé avec, comme dirait l'autre, <em>une bonne platrée</em> de sites et
de services à gérer sur <cite>lolnet.org</cite>, mon serveur.</p>
<p>Jusqu'à très récemment, rien de tout ça n'était sauvegardé, et non plus monitoré.
Après quelques recherches, je suis tombé sur <a class="reference external" href="http://www.stashboard.org/">stashboard</a>, un &quot;status board&quot; qu'il est bien fait. Le seul
problème, c'est écrit pour se lancer sur GAE, <em>Google App Engine</em>.
Heureusement, c'est open-source, et ça a été forké pour donner naissance
à <a class="reference external" href="https://github.com/bfirsh/whiskerboard">whiskerboard</a> (la planche
moustachue, pour les non anglophones).</p>
<img alt="Capture d'écran du site." src="images/status_board.png" />
<div class="section" id="verifier-le-statut-des-services">
<h2>Vérifier le statut des services</h2>
<p>Donc, c'est chouette, c'est facile à installer, tout ça, mais… mais ça ne fait
en fait pas ce que je veux: ça ne fait que m'afficher le statut des services,
mais ça ne vérifie pas que tout est bien &quot;up&quot;.</p>
<p>Bon, un peu embêtant pour moi, parce que c'est vraiment ça que je voulais. Pas
grave, je sais un peu coder, autant que ça serve. J'ai ajouté quelques
fonctionnalités au soft, qui sont disponibles sur mon fork, sur
github:: <a class="reference external" href="https://github.com/ametaireau/whiskerboard">https://github.com/ametaireau/whiskerboard</a> .</p>
<p>Entres autres, il est désormais possible de lancer <a class="reference external" href="http://celeryproject.org/">celery</a> en tache de fond et de vérifier périodiquement
que les services sont toujours bien vivants, en utilisant une tache spécifique.</p>
<p>C'était un bonheur de développer ça (on a fait ça à deux, avec guillaume, avec
un mumble + tmux en pair prog, en une petite soirée, ça dépote).</p>
<p>Les modifications sont assez simples, vous pouvez aller jeter un œil aux
changements ici:
<a class="reference external" href="https://github.com/ametaireau/whiskerboard/compare/b539337416...master">https://github.com/ametaireau/whiskerboard/compare/b539337416...master</a></p>
<p>En gros:</p>
<ul class="simple">
<li>ajout d'une <cite>connection_string</cite> aux services (de la forme
protocol://host:port)</li>
<li>ajout d'une commande <cite>check_status</cite> qui s'occupe d'itérer sur les services et
de lancer des taches celery qui vont bien, en fonction du protocole</li>
<li>ajout des taches en question</li>
</ul>
</div>
<div class="section" id="deploiement">
<h2>Déploiement</h2>
<p>Le plus long a été de le déployer en fin de compte, parce que je ne voulais pas
déployer mon service de supervision sur mon serveur, forcément.</p>
<p>Après un essai (plutôt rapide en fait) sur <a class="reference external" href="http://heroku.com">heroku</a>, je me
suis rendu compte qu'il me fallait payer pas loin de 35$ par mois pour avoir un
process <cite>celeryd</cite> qui tourne, donc j'ai un peu cherché ailleurs, pour
finalement déployer la chose chez <a class="reference external" href="https://www.alwaysdata.com/">alwaysdata</a></p>
<p>Après quelques péripéties, j'ai réussi à faire tourner le tout, ça à été un peu
la bataille au départ pour installer virtualenv (j'ai du faire des changements
dans mon <cite>PATH</cite> pour que ça puisse marcher), voici mon <cite>.bash_profile</cite>:</p>
<pre class="literal-block">
export PYTHONPATH=~/modules/
export PATH=$HOME/modules/bin:$HOME/modules/:$PATH
</pre>
<p>Et après y'a plus qu'à installer avec <cite>easy_install</cite>:</p>
<pre class="literal-block">
easy_install --install-dir ~/modules -U pip
easy_install --install-dir ~/modules -U virtualenv
</pre>
<p>Et à créer le virtualenv:</p>
<pre class="literal-block">
virtualenv venv
venv/bin/pip install -r requirements.txt
</pre>
<p>Dernière étape, la création d'un fichier <cite>application.wsgi</cite> qui s'occupe de
rendre l'application disponible, avec le bon venv:</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="n">activate_this</span> <span class="o">=</span> <span class="s1">&#39;/home/lolnet/venv/bin/activate_this.</span>
<span class="nb">execfile</span><span class="p">(</span><span class="n">activate_this</span><span class="p">,</span> <span class="nb">dict</span><span class="p">(</span><span class="vm">__file__</span><span class="o">=</span><span class="n">activate_this</span><span class="p">))</span>
<span class="n">paths</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;/home/lolnet/public&#39;</span><span class="p">,]</span>
<span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">paths</span><span class="p">:</span>
<span class="k">if</span> <span class="n">path</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="p">:</span>
<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">django.core.handlers.wsgi</span>
<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;DJANGO_SETTINGS_MODULE&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;settings&#39;</span>
<span class="n">application</span> <span class="o">=</span> <span class="n">django</span><span class="o">.</span><span class="n">core</span><span class="o">.</span><span class="n">handlers</span><span class="o">.</span><span class="n">wsgi</span><span class="o">.</span><span class="n">WSGIHandler</span><span class="p">()</span>
</pre></div>
</div>
<div class="section" id="ssl-et-requests">
<h2>SSL et Requests</h2>
<p>Quelques tours de manivelle plus loin, j'ai un celeryd qui tourne et qui
consomme les taches qui lui sont envoyées (pour des questions de simplicité,
j'ai utilisé le backend <cite>django</cite> de celery, donc pas besoin d'AMQP, par
exemple).</p>
<p>Problème, les ressources que je vérifie en SSL (HTTPS) me jettent. Je sais pas
exactement pourquoi à l'heure qu'il est, mais il semble que lorsque je fais une
requête avec <a class="reference external" href="http://docs.python-requests.org/en/latest/">Requests</a> je me
récupère des <em>Connection Refused</em>. Peut être une sombre histoire de proxy ? En
attendant, les appels avec <cite>CURL</cite> fonctionnent, donc j'ai fait <a class="reference external" href="https://github.com/ametaireau/whiskerboard/blob/master/board/tasks.py#L17">un fallback
vers CURL lorsque les autres méthodes échouent</a>.
Pas super propre, mais ça fonctionne.</p>
<p><strong>EDIT</strong> Finalement, il se trouve que mon serveur était mal configuré.
J'utilisais haproxy + stunnel, et la négiciation SSL se passait mal. Une fois
SSL et TLS activés, et SSLv2 désactivé, tout fonctionne mieux.</p>
</div>
<div class="section" id="et-voila">
<h2>Et voilà</h2>
<p>Finalement, j'ai mon joli status-board qui tourne à merveille sur
<a class="reference external" href="http://status.lolnet.org">http://status.lolnet.org</a> :-)</p>
</div>
Vous pouvez également <a onclick="(function(){
let here = document.location;
document.location = `http://pdf.fivefilters.org/simple-print/url.php?size=A4#${here}`;
return false;
})();return false;">télécharger cet article en pdf</a>.
</div>
</div>
</div>
<label for="sidebar-checkbox" class="sidebar-toggle"></label>
<script>
(function(document) {
var i = 0;
// snip empty header rows since markdown can't
var rows = document.querySelectorAll('tr');
for(i=0; i<rows.length; i++) {
var ths = rows[i].querySelectorAll('th');
var rowlen = rows[i].children.length;
if (ths.length > 0 && ths.length === rowlen) {
rows[i].remove();
}
}
})(document);
</script>
<script>
/* Lanyon & Poole are Copyright (c) 2014 Mark Otto. Adapted to Pelican 20141223 and extended a bit by @thomaswilley */
(function(document) {
var toggle = document.querySelector('.sidebar-toggle');
var sidebar = document.querySelector('#sidebar');
var checkbox = document.querySelector('#sidebar-checkbox');
document.addEventListener('click', function(e) {
var target = e.target;
if(!checkbox.checked ||
sidebar.contains(target) ||
(target === checkbox || target === toggle)) return;
checkbox.checked = false;
}, false);
})(document);
</script>
<!-- Piwik -->
<script type="text/javascript">
var _paq = _paq || [];
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//tracker.notmyidea.org/";
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', 3]);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<noscript><p><img src="//tracker.notmyidea.org/piwik.php?idsite=3" style="border:0;" alt="" /></p></noscript>
<!-- End Piwik Code -->
</div>
</body>
</html>