CentOS 6 – Varnish & GeoIP

Linux Aucun commentaire »

centosNous allons voir comment déporter le système de géo-localisation IP sur Varnish.
L’objectif final est de permettre à vos backends de récupérer le Pays de l’utilisateur au sein de la requête HTTP.

Par défault, Varnish n’intègre pas de système de géo-localisation par IP, en revanche il existe quelques plugins qui permettent l’utilisation de GeoIP de MaxMind.

Voici les parties de l’article :

  • Installation de Varnish
  • Installation de GeoIP pour Varnish
  • Configuration du Varnish Module
  • Configuration de SELinux

A noter que nous avons opter pour le VMOD Geoip-vmod par leed25d. Contrairement aux autres plugins, celui-ci ne travail pas le header HTTP de manière autonome. Ce sera à vous de le faire, et grâce à cela vous allez pouvoir choisir comment…

Varnish

Pour compiler le VMOD, il vous faudra récupérer les sources de Varnish et les compiler même si vous choisissez l’installation par YUM.
De mon coté, je n’utilise pas en production la version que je compile mais la version provenant du dépot varnish-cache.org. A vous de voir.

Commençons par l’installation de Varnish via YUM (cf. Doc officielle):

rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-3.0/el5/noarch/varnish-release-3.0-1.noarch.rpm
yum install varnish

Pour compiler Varnish nous allons avoir besoin de quelques outils et des sources.

yum install pcre-devel make
cd && curl -o varnish-source.tar.gz http://repo.varnish-cache.org/source/varnish-3.0.2.tar.gz
tar -xvzf varnish-source.tar.gz

On lance la compilation de Varnish.

cd varnish-3.0.2/
./configure
make

Normalement, Varnish a été compilé dans votre repertoire $HOME/varnish-3.0.2/.

GeoIP VMOD

On récupère les sources sur github.

Après l’installation de quelques outils dont GeoIP, on lance la compilation du VMOD.
Attention, pour les version 32Bits utiliser VMODDIR=/usr/lib/varnish/vmods/.

yum install unzip automake autoinstall libtool geoip geoip-devel
unzip leed25d-geoip-vmod-[REVISION].zip
cd leed25d-geoip-vmod-[REVISION]
./autogen.sh
./configure VARNISHSRC=$HOME/varnish-3.0.2/ VMODDIR=/usr/lib64/varnish/vmods/
make
make install

Suite à l’installation Varnish, penser à ouvrir votre firewall.

#/etc/sysconfig/iptables
-A INPUT -m tcp -p tcp --dport 80 -j ACCEPT
service iptables restart

De même, il faut configurer Varnish pour écouter sur le port 80 à la place du 6081.

#/etc/sysconfig/varnish</strong>
VARNISH_LISTEN_PORT=80

Ensuite, on va vérifier que l’on peut lancer Varnish en chargeant le plugin GeoIP.

#/etc/varnish/default.vcl
#Top of file.
import geoip;

On va lancer le processus en debug pour voir si tout se passe bien :

varnishd -d -f /etc/varnish/default.vcl
start

Si vous n’avez pas d’erreur, c’est une bonne chose. Sinon, vérifier les étapes ci-dessus.

On va donc pouvoir inclure le pays de l’utilisateur dans le Header HTTP en suivant l’exemple de l’auteur du VMOD

#/etc/varnish/default.vcl
import geoip;
 
sub vcl_recv {
    set req.http.X-Forwarded-For = client.ip;
    set req.http.X-GeoIP = geoip.country(req.http.X-Forwarded-For)
}

Maintenant on va pouvoir mettre Varnish en démarrage automatique.

chkconfig varnish on
service varnish start

Attention:
Sachant que vous êtes sous CentOS, SELinux est surement activé et bloquera l’access au fichier de données /usr/share/GeoIP/GeoIP.dat. Vous pouvez le désactiver ou aller voir à la fin de l’article comment le configurer aux petits oignons.

setenforce 0

Et pour finir, un peu de ménage.

cd && rm -Rf varnish-* && rm -Rf leed25d-*
yum remove pcre-devel make unzip automake autoinstall geoip-devel

Pour aller plus loin

Avec la configuration ci-dessus,
Si un client de France se connecte directement à Varnish, lorsqu’une requête sera générée pour atteindre vos backends elle contiendra : X-GeoIP: FR

Vous pourrez donc récupérer le pays de l’utilisateur en analysant le contenu de la requête HTTP.
Il est à noter que GeoIP retourne le code pays « AA » lorsqu’il ne parvient pas à faire la détection.

Voici comment vous pouvez exploiter le contenu du header en PHP :

$headers = apache_request_headers();
$code = null;
 
if ($headers && is_array($headers) && array_key_exists("X-GeoIP", $headers)) {
    $code = $headers["X-GeoIP"];
}
 
if ((null == $code)||("AA" == $code)) {
    $code = $this->getDefaultCountry();
}
 
$code = strtoupper($code);

Retournons du coté de Varnish.
Comment les choses vont se passer si vous ajoutez un Proxy en amont de Varnish. Par exemple, Pound pour gérer le protocole HTTPS.

La detection du pays ne fonctionnera plus normalement car la valeur contenu dans le script VCL ‘client.ip‘ correspondra à l’IP de votre serveur Pound.

Nous allons donc devoir travailler avec un autre Header HTTP: X-Forwarded-For. Celui-ci permet de conserver l’historique des différents point de passage d’une requête HTTP et contient l’IP du client qui a initié la connection HTTP.

Lorsque les différents Proxy implementent correctement ce standard, le champs X-Forwarded-For contient l’IP du client, le proxy A, le proxy B, etc.. le tout séparé avec des virgules.

Voici comment en tenir compte au sein de votre configuration VCL :

sub vcl_recv {
    //...
 
    if (req.restarts == 0) {
        if (req.http.x-forwarded-for) {
            set req.http.X-Forwarded-For =
            req.http.X-Forwarded-For + ", " + client.ip;
        } else {
            set req.http.X-Forwarded-For = client.ip;
        }
    }
 
    set req.http.X-GeoIP = geoip.country(regsub (req.http.X-Forwarded-For, "(,.*)", ""));
 
    //...
}

Maintenant parlons un peu du système de cache de Varnish.
Si vous avez besoin de connaitre le pays de l’utilisateur, il y a donc fort à parier que le contenu retourné à l’utilisateur sera different en fonction de son Pays.

En résumé, pour une URL : /mon-url, en fonction du Pays utilisateur le contenu sera different.
Si on conserve la spécification par défaut de Varnish qui consiste à mettre en cache les données provenant d’une même URL, vous allez avoir quelques mauvaises surprises.

Voici comment tenir compte du pays de l’utilisateur pour gérer les données qui sont mises en cache.

sub vcl_hash {
    //...
 
    hash_data(req.url);
    hash_data(req.http.X-GeoIP);
 
    //...
 
    return (hash);
}

SELinux

Sous Centos, il y a SELinux.
Si vous n’êtes pas un expert en sécurité Linux. Voici comment faire fonctionner Varnish & GeoIP sans désactiver SELinux.
Le processus Varnish fait parti d’un contexte SELinux different du fichier GetIP.dat qui est installé avec GeoIP.
Du coup, nous allons faire un module pour SELinux afin d’autoriser varnish_t à lire les contextes de type usr_t.

mkdir ~/myvarnish; cd ~/myvarnish;
echo "policy_module(myvarnish, 1.0.0) optional_policy(\` gen_require(\` type varnishd_t; ') files_read_usr_files(varnishd_t) ')" > myvarnish.te
make -f /usr/share/selinux/devel/Makefile myvarnish.pp
semodule -i myvarnish.pp

Pour le coup, cette partie provient d’une discussion avec une personne sur #SELinux on freenode.

Mots-clefs :, , , , , , , , , , , , ,
 

Doctrine 2 & i18n

Doctrine, Zend 3 Commentaires »

Doctrine 2 est dépourvu – en natif – de système de traduction.
Grâce au système d’extension, des contributeurs dont certains membres de l’équipe de développement Doctrine ont développés Gedmo, un pack d’extension pour Doctrine.

Cette extension inclue :

  • Tree
  • Translatable
  • Sluggable
  • Timestampable
  • Loggable
  • Sortable

Nous nous intéresserons à Translatable qui nous permettra de traduire nos données.

Travaillant avec le Framework Zend, les exemples seront orientés pour cette architecture, il est à noter que cela n’est pas un pré-requit et que cela fonctionnera avec ou sans Zend Framework.

Fonctionnement

Le module i18n de Gedmo fonctionne grâce à l’utilisation d’un table annexe contenant la traduction de certaines propriétés de vos Entités.
La table de traduction contient donc le nom du champs traduite, la langue, la valeur, le type d’objet ainsi qu’une reference vers cet objet.

Par défaut, l’extension aura besoin de la table : ext_translations
Les champs suivant seront ainsi necessaire :

  • id
  • content
  • field
  • locale
  • foreign_key
  • object_class

Voici un jeu de donnée qui vous permettra de mieux comprendre l’utilisation de ce type de structure :

  • content : Un día me voy a comprar el mundo
  • field : title
  • locale : es_es
  • foreign_key : 3
  • object_class : \Entity\Article
  • content : Un jour j’achèterai le monde
  • field : title
  • locale : fr_fr
  • foreign_key : 3
  • object_class : \Entity\Article
  • content : Le monde semble être à l’agonie, que pouvons nous faire pour le sauver.
  • field : description
  • locale : fr_fr
  • foreign_key : 3
  • object_class : \Entity\Article

A noter, que les données relatives à la langue par défaut de votre application sont stockés au sein de la table gerant directement votre entité.
Par défaut, nous utilisons la langue « en_US« , ce qui signifie que la table ext_translations ne contiendra pas de traduction pour « en_US ».
Dans mon exemple, ces données seront stockés dans la table « articles » de l’entité \Entity\Article

Ainsi, l’extension stockera l’ensemble des traductions de votre application au sein d’une même table.
Attention, le champs « forien_key » ne correspond pas à une clé étrangère pour votre base de donnée relationnelle.
Une des possibilités de l’extension consiste à pouvoir définir une table spécifique à la traduction d’une Entités, ainsi vous pourrez définir une vrai clé étrangère au sein de votre RDBMS.

Exploitation

Au niveau de l’exploitation des données,
Vous définirez la langue utilisée au sein de votre application lors de l’execution, cela correspondra normalement à la langue de l’utilisateur.
Il ne restera plus qu’a utiliser votre application comme vous en avez l’habitude.

Nous partons du principe que votre environnement Doctrine est correctement configuré et fonctionnel.

Voici la configuration minimum a définir :

$classLoader = new \Doctrine\Common\ClassLoader( 'Gedmo', APPLICATION_PATH . '/../library/');
$classLoader->register();
 
$config 	= new \Doctrine\ORM\Configuration();
 
$driverChain		= new \Doctrine\ORM\Mapping\Driver\DriverChain();
$entityDriver 		= new \Doctrine\ORM\Mapping\Driver\XmlDriver ();
 
$translatableDriver = $config->newDefaultAnnotationDriver( APPLICATION_PATH . '/../library/DoctrineExtensions/Gedmo/Translatable/Entity');
 
$driverChain->addDriver ($entityDriver,		'Entity\Article');
$driverChain->addDriver ($translatableDriver, 	'Gedmo\Translatable');
 
$config->setMetadataDriverImpl($driverChain);
 
$eventManager		= new \Doctrine\Common\EventManager();
$translatableListener 	= new \Gedmo\Translatable\TranslationListener();
 
$translatableListener->setTranslationFallback( true );
$eventManager->addEventSubscriber($translatableListener);
 
$entityManager = \Doctrine\ORM\EntityManager::create($conn, $config, $eventManager);

Ensuite, il faut configurer vos entités.
J’utilise le XML Mapping, vous trouverez facilement l’équivalence pour YAML / Annotation.

<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
	<entity name="Entity\Article" table="articles">
		<id name="idArticle" type="integer" column="id_article">
			<generator strategy="AUTO" />
		</id>
		<field name="title" type="string">
			<gedmo:translatable/>
		</field>
		<field name="description" type="string">
			<gedmo:translatable/>
		</field>
	</entity>
</doctrine-mapping>

Nous avons simplement ajouté le noeud XML gedmo:translatable à notre champs afin de spécifier que celui-ci peut-être traduit.
A noter qu’il faut inclure l’espace de nom xmlns:gedmo.

Voici un exemple d’utilisation avec Doctrine

//En utilisant la langue par défaut qui est l'anglais,
$article 	= $entityManager->find('\Entity\Article', 3);
$article->getTitle (); 
//One day I'll buy the world
 
//En spécifiant la langue espagnole,
$translatableListener->setTranslatableLocale("es_es");
$article 	= $entityManager->find('\Entity\Article', 3);
$article->getTitle (); 
//Un día me voy a comprar el mundo

Entity de traduction

Nous avons vu précédemment que les traductions sont par défaut stockées dans la table ext_translations.
Voyons comment utiliser une table dédiée à la traduction d’une entité. Cela permettra en plus d’avoir une structure de base de donnée plus propre, et d’avoir des clés étrangère au sein de votre RDBMS.

<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
	<entity name="Entity\Article" table="articles">
		<gedmo:translation entity="Entity\ArticleTranslation" />
		..
	</entity>
</doctrine-mapping>

Créons la class ArticleTranslation qui n’a rien de bien extraordinaire, sauf qu’elle doit étendre AbstractTranslation qui va définir les differentes propriétés de votre table de traduction.

namespace Entity
 
use Gedmo\Translatable\Entity\AbstractTranslation;
use Doctrine\ORM\Mapping as ORM;
 
class ArticleTranslation extends AbstractTranslation
{
 
}

A cela, ajoutons le fichier de mapping.

<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
	<entity name="Entity\ArticleTranslation" table="articles_translation" />
</doctrine-mapping>

Il ne vous reste plus qu’a créer la table article_translation avec les champs énuméré en début d’article.

Conclusion

Comparer à Doctrine 1, la mise en place de l’internationalisation pour votre application peut sembler plus difficile. Par contre, l’exploitation de cette implementation est tout simplement user-friendly.

Mots-clefs :, , , , , , , , , ,
 

Linux – Générer des fichiers binaires

Linux 1 Commentaire »

Dans la série des articles post-it, voici comment créer des fichiers binaires de tailles spécifiques.

Un fichier de 100MBytes.

dd if=/dev/zero of=100MB bs=100M count=1

Un fichier de 500MBytes.

dd if=/dev/zero of=500MB bs=500M count=1

Un fichier de 1GBytes.

dd if=/dev/zero of=1GB bs=1G count=1

Et j’ai envie de dire, ainsi de suite…

Mots-clefs :, , , , , , ,
 

Faire un « svn revert » sur l’ensemble de vos fichiers

Système 2 Commentaires »

Petit article mémo,
J’avais besoin de faire un revert sur l’ensemble des mes fichiers locaux. Or, « svn revert * » ne fonctionne pas.

Voici la petite commande magique

svn st | grep -e '^M' | awk '{print $2}' | xargs svn revert
Mots-clefs :, , , , ,
 

Système d’exploitation Google: Chrome OS

Système Aucun commentaire »

Depuis ce matin cela fait le tour de la toile, Google va sortir son système d’exploitation.

On s’y attendait fortement, mais jusqu’à ce matin nous n’avions aucune confirmation de Google.
En effet, il existe déjà un système d’exploitation made in Google: Android pour les unités mobiles.

Si vous voulez plus d’information: Blog Google, Techcrunch, Clubic, …
A la suite de ces lectures, on en retiendra que le système sera basé sur Linux, pensé avant tout pour fonctionner sur des Notebook, sera supporté par des processeurs x86 / ARM et disponible milieu de l’année 2010 (ce qui arrivera assez vite).

Maintenant, quelles en sont les retombées:
- Google est le centre d’internet pour une très grande majorité des Internautes du monde. Comparé a Microsoft, Apple et d’autres distributions Linux, Google dispose d’un support publicitaire gigantesque. Sachant que Windows 7 doit sortir aussi milieu 2010, je vous laisse imaginer le combat qu’il y aura dans nos magasins.
- Pour les aficionados de Linux, ce n’est pas une mauvaise chose car cela permettra de valoriser un peu plus le monde Libre.
- Déjà que Google tue des Bambis, sait qui est malade, connait nos problèmes médicaux, et qu’il est présent partout autours de nous, il sera aussi le support de nos données.
Le monopole Google est de plus en plus proche !

Mots-clefs :, , , , , ,
 

L’arrêt du système interrompu : la faute à Msn

Windows 1 Commentaire »

Ce matin en arrivant sur mon lieu de travail, je pensais allumer mon Pc, mais non, il était déjà allumé.

On appuie sur un touche pour sortir de la mise en veille, et l’ordinateur que l’on pensait avoir éteint la veille est resté allumé toute la nuit, session ouverte.

La faute à quoi ? A un programme qui n’a pas réussi à se tuer correctement…

Que j’aime Windows de bon matin.

Mots-clefs :, ,
 
Designed by NattyWP Wordpress Themes.
Images by desEXign.