Installer Webistrano avec nginx et PostgreSQL sous Gentoo

Webistrano est une application Web développée en Ruby On Rails permettant le déploiement automatisé de vos applications, qu’elles soient Web ou non. Ainsi, via le front-end Web, vous n’aurez qu’à appuyer sur un bouton pour que Webistrano récupère vos sources depuis un dépôt (svn, git, …) et depuis un répertoire et le déploie sur votre ferme de serveurs, en lançant par exemple les différents tests que vous aurez effectués. Si une erreur apparaît, Webistrano annule tous les changements et laisse l’application fonctionnelle comme elle l’était.

Pour installer Webistrano, vous avez besoin de Ruby On Rails, d’un serveur Web et d’une base de données. Je vais utiliser nginx comme serveur Web et PostgreSQL comme base de données. Je ne vais pas vous expliquer comment installer nginx et PostgreSQL, il y a déjà de très bons articles qui vous l’expliquent.

Installation du Ruby On Rails

Pour installer Ruby On Rails sur Gentoo, rien de plus simple, installer rudy puis le gem rails :

# emerge -av  dev-lang/ruby
# gem install rails --include-dependencies
# gem install bundler

Configuration de la base de données

Nous allons créer une nouvelle base de données pour Webistrano, ainsi qu’un nouvel utilisateur:

# su postgres
$ psql
postgres=# CREATE USER webistrano WITH PASSWORD '-VOTRE-MOT-DE-PASSE-';
CREATE ROLE
postgres=# CREATE DATABASE webistrano WITH OWNER webistrano;
CREATE DATABASE

Téléchargement et configuration du Webistrano

On va télécharger le tarball de la dernière version de Webistrano depuis le dépôt GitHub et décompressez le à l’endroit que vous souhaitez. Ici, le chemin de Webistrano sera /home/www/webistrano/.

useradd webistrano
mkdir -p /home/www/webistano/
wget https://github.com/peritor/webistrano/tarball/master -O /home/www/webistano.tgz
cd /home/www
tar -xzf webistano.tgz
mv peritor-webistrano-* webistrano
rm webistano.tgz

Ensuite, nous allons configurer Webistrano en éditant les fichiers de configuration mais avant il faut les créer à partir des modèles fournis:

cd /home/www/webistrano
cp config/webistrano_config.rb.sample config/webistrano_config.rb
cp config/database.yml.sample config/database.yml

Continue reading

php-fpm segfault at f6 avec APC

En voulant modifier la configuration d’APC, pour augmenter la taille d’un segment de 30M à 64M, j’ai uniquement modifié la directive apc.shm_size. L’opération m’as valu une erreur de segmentation lors du démarrage de php-fpm.

2012-03-04T09:16:42+01:00 ks2 /etc/init.d/php-fpm[31918]: start-stop-daemon: failed to start `/usr/lib/php5.3/bin/php-fpm'
2012-03-04T09:16:42.670658+01:00 ks2 kernel: php-fpm[31919]: segfault at f6 ip 000000000079187c sp 00007fff8a154b60 error 4 in php-fpm[400000+86e000]
2012-03-04T09:16:42.670671+01:00 ks2 kernel: grsec: From 92.155.17.179: Segmentation fault occurred at 00000000000000f6 in /usr/lib64/php5.3/bin/php-fpm[php-fpm:31919] uid/euid:0/0 gid/egid:0/0, parent /sbin/rc[start-stop-daem:31918] uid/euid:0/0 gid/egid:0/0

Je me suis donc mis à la tâche de mettre à jour PHP ainsi que tous ces modules PECL sous Gentoo. Une fois la mise à jour s’étant bien passé, APC est à la version 3.1.9 mais php-fpm refuse toujours de démarrer… J’ai donc remis la valeur de apc.shm_size à 30M et php-fpm s’est très bien lancé.

On peut donc vérifier la taille maximum de mémoire partagée allouée par le système de le fichier /proc/sys/kernel/shmmax :

ks2 ~ # cat /proc/sys/kernel/shmmax
33554432

Par conséquent, on peut voir qu’APC n’a pas pu réserver 64M de mémoire partagée, puisque le système lui refuse. Je déplore un peu le manque de message d’erreur et l’erreur de segmentation qui peut provenir de “nul-part” si l’on configure son système automatiquement.

À ce stade vous avez deux possibilités:
Continue reading

Utiliser jQuery et MooTools en même temps, sans modifier jQuery

Pour utiliser MooTools en plus de jQuery au sein d’une même application Web, il suffit d’éditer le fichier JavaScript de MooTools et remplacer les chaines suivantes respectivement par les suivantes:

Remplacer:

  • $.
  • $[
  • $(
  • $:

Par:

  • mootools.
  • mootools[
  • mootools(
  • mootools:

Ensuite, utilisez MooTools via mootools et non $.

Symfony2: nom de la route depuis un template Twig

Dans Symfony2, il est possible d’accéder aux propriétés de la requête actuelle à partir d’un template Twig grâce aux variables globales.

En l’occurrence, ça peut être utile pour connaître le nom de la route utilisée. Ainsi, avec la variable app.request, on peut avoir accès aux attributes, et donc à la route utilisée. En PHP, on aurions pu récupérer l’information comme ceci:

$request->attributes->get('_route');

Avec Twig, le code deviens ceci:

{{ app.request.attributes.get('_route') }}

Une fonctionnalité toute bête mais qui peut s’avérer très pratique!

Symfony 2 et PostgreSQL: Mots réservés

Symfony 2 propose une abstraction des entities très intéressante grâce à Doctrine. Je poste ce petit article car j’ai eu une erreur tout simple:

 $ php app/console doctrine:schema:update --force
Updating database schema...
 
[PDOException] SQLSTATE[42601]: Syntax error: 7 ERREUR:  erreur de syntaxe sur ou près de « User » 
LINE 1: CREATE TABLE User (id INT NOT NULL, username VARCHAR(255) NO...              
                       ^          

En fait, j’ai créé un bundle nommé User, et doctrine souhaite donc créer la table User. Le problème, c’est que user est un mot clé réservé dans PostgreSQL. Par conséquent, il faut donc forcer Doctrine à escaper le nom de la table. Pour se faire, il suffit d’ajouter une annotation Table en préfixant et suffixant le nom de la table par `.

Voici par exemple ma classe User avant la correction:

/**
 * @ORM\Entity
 */
class User extends BaseUser
{
    // ...
}

Il suffit donc de d’ajouter l’annotation @ORM\Table en spécifiant le nom de la table entouré de `. Le nouveau code est:

/**
 * @ORM\Entity
 * @ORM\Table(name="`User`")
 */
class User extends BaseUser
{
    // ...
}

Ainsi, Doctrine va générer ses requêtes en ajoutant des caractères d’échappement sur le nom de la table. Ainsi, vous n’aurez plus d’erreur! :)

Polygones de Thyssen: algorithme de Steven Forture en PHP

Pour des besoins professionnels, j’ai réécrit l’algorithme de Steven Fortune permettant d’obtenir un diagramme de Voronoï à partir de points connus, en transformant la librairie JavaScript de gorhill.

Vous pouvez trouver les fichiers sources (en PHP 5) sur ce dépôt GitHub:

Exemple d’utilisation

Voici un exemple d’utilisation, qui permet de générer un diagramme de Voronoï (ou autrement dit des polygones de Thyssen) à partir de points générés automatiquement:

<?php 
require_once '../library/Nurbs/Voronoi.php';
require_once '../library/Nurbs/Point.php';
 
$bbox = new stdClass();
$bbox->xl = 0;
$bbox->xr = 400;
$bbox->yt = 0;
$bbox->yb = 400;
 
$xo = 0;
$dx = $width = 400;
$yo = 0;
$dy = $height = 400;
$n = 20;
$sites = array();
 
// On créé l'image
$im = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($im, 255, 255, 255);
$red = imagecolorallocate($im, 255, 0, 0);
$green = imagecolorallocate($im, 0, 100, 0);
$black = imagecolorallocate($im, 0, 0, 0);
imagefill($im, 0, 0, $white);
//imageantialias($im, true);
 
// On créé des points aléatoires que l'on dessine
for ($i=0; $i < $n; $i++) {
	$point = new Nurbs_Point(rand($xo, $dx), rand($yo, $dy));
	$sites[] = $point;
 
	imagerectangle($im, $point->x - 2, $point->y - 2, $point->x + 2, $point->y + 2, $black);
}
 
$voronoi = new Voronoi();
$diagram = $voronoi->compute($sites, $bbox);
//var_dump($diagram);
 
//var_dump('sites', $sites, 'diagram', $diagram, 'cells', $diagram['cells']);//, 'voronoi', $voronoi);
$j = 0;
foreach ($diagram['cells'] as $cell) {
	// On va agreger les points du polygone.
	$points = array();
 
	if (count($cell->_halfedges) > 0) {
		$v = $cell->_halfedges[0]->getStartPoint();
		if ($v) {
			$points[] = $v->x;
			$points[] = $v->y;
		} else {
			var_dump($j.': no start point');
		}
 
		for ($i = 0; $i < count($cell->_halfedges); $i++) {
			$halfedge = $cell->_halfedges[$i];
			$edge = $halfedge->edge;
 
			if ($edge->va && $edge->vb) {
				imageline($im, $edge->va->x, $edge->va->y, $edge->vb->x, $edge->vb->y, $red);
			}
 
			$v = $halfedge->getEndPoint();
			if ($v) {
				$points[] = $v->x;
				$points[] = $v->y;
			} else {
				var_dump($j.': no end point #'.$i);
			}
		}
	}
 
	// On construit le polygone
	$color = imagecolorallocatealpha($im, rand(0, 255), rand(0, 255), rand(0, 255), 50);
	imagefilledpolygon($im, $points, count($points) / 2, $color);
	$j++;
}
 
// On affiche l'image
imagepng($im, 'voronoi.png');

Voici un exemple d’image:

Zend PHP 5.3 Developer Certified

Ça y est, je suis développeur PHP 5.3 certifié par Zend! :-)

Le principe du concours est très simple: vous avez 90 minutes pour répondre à 70 questions aléatoires concernant le fonctionnement de PHP ainsi que les différents domaines qui l’entour, à savoir le SQL, la sécurité en général, etc…

Je vous conseil de le passer, c’est sans aucun doutes un bon élément sur le CV. Si vous avez un quelconque question, n’hésitez pas!

Un rapport par défaut dans Trac

Dans Trac, lorsque l’on clique sur “Voir les tickets”, on arrive sur la liste des différents rapports disponibles.

Pour des questions pratiques, je préférais arriver directement sur la page du rapport des tickets actifs. On peut donc modifier les liens du menu horizontal pour y arriver! Modifiez donc le fichier trac.ini comme ceci:

[mainnav]
tickets.href = /report/1

Ainsi, ce sera le rapport d’ID 1 qui sera ouvert.

Crypter un mot de passe comme dans /etc/shadow

Petit test pour crypter un mot de passe comme dans le fichier /etc/shadow avec Python! Vous pouvez crypter une chaîne de caractères en utilisant le même SALT, à savoir la clé de cryptage.

Dans une chaine du fichier /etc/shadow, voici un exemple de ligne:

sroze:$6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50:15224:0:99999:7:::

Ici, on peut voir que mon mot de passe personnel est $6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50. Cette chaine signifie que l’encodage utilisé est le numéro 6 ($6$) à savoir le SHA-2, le SALT est jWp7fotG. Vous pouvez retrouver plus d’informations à ce sujet ici.

En utilisant la même clé, on peut donc retrouver le mot de passe, comme ceci!

# python -c "import crypt, getpass, pwd; print crypt.crypt('-PASSWORD-', '\$6\$jWp7fotG\$')"
$6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50

On vérifie la correspondance:

# cat /etc/shadow | grep sroze | cut -d":" -f2
$6$jWp7fotG$ikvxu3kvwbn36XvznP1FHnokYpY/MScI6QjYz.vJJ1r/klF2Nwiv3lkuSvs8hz4fZ08v7OAANFKfOaotPsjL50

:-)

C: Régler le problème des defunct process

Lorsque vous développez une application, il est parfois très intéressant d’utiliser des threads ou plusieurs processus pour exécuter plusieurs tâches simultanément. Nous allons ici voir un problème qui arrive lors que l’on utilise plusieurs processus, via un fork(). En effet, en C, la fonction fork permet de créer un nouveau processus, qui devient fils du processus appelant le fork.

Processus zombies (defunct)

Par défaut, lorsque le processus père s’arrête, tous les processus fils s’arrête. À l’inverse, lorsqu’un processus fils s’arrête – via un exit(0); par exemple -, sa mémoire est libérée, il devient un processus zombie (seul le bloc de contrôle reste présent) et le processus père continue de fonctionner.

Ainsi, l’on peut voir de nombreuses lignes marquées par un defunct lorsque l’on liste les processus avec un ps:

root      9175  0.0  0.0 136380  1100 ?        Sl   Jun30   0:00 /[...]/relay
root      9629  0.0  0.0      0     0 ?        Z    Jun23   0:00 [relay] <defunct>
root      9853  0.0  0.0      0     0 ?        Z    Jun30   0:00 [relay] <defunct>
root      9884  0.0  0.0      0     0 ?        Z    Jun30   0:00 [relay] <defunct>

C’est parce que le processus père n’écoutes pas le signal SIGCHLD, qui est envoyé par le fils lors de son extinction. Ainsi, en écoutant le signal, le père peut libérer son bloc de contrôle. En C, c’est la fonction waitpid qui nous sera utile.

Une ligne à ajouter

Il n’y a qu’une seule ligne (ainsi qu’un #include) à ajouter à votre code C pour que les processus zombies soient “ramassés” par votre processus père. De temps en temps – l’idéal étant la boucle principale s’il y a -, exécutée cette ligne ci:

while (waitpid(WAIT_ANY, NULL, WNOHANG) != 0);

Les arguments sont les suivants:

  • WAIT_ANY est la constante permettant de dire que l’on souhaite attendre n’importe quel des processus fils de ce processus. À la place, nous aurions pu mettre le pid d’un processus particulier.
  • NULL permet de ne pas récupérer d’informations de statut du processus.
  • WNOHANG est une option permettant d’exécuter waitpid en mode non-bloquant.

N’oubliez pas d’inclure l’en-tête des fonctions et constantes ainsi:

#include <sys/wait.h>

Ainsi, il ne restera plus de processus zombie, ou defunct.