Mercurial : Publier sur plusieurs dépôts

Le problème

Vous avez plusieurs dépôts Mercurial, en général un principal et un miroir (pour la sauvegarde). Cependant, toujours garder les deux dépôts synchronisés n’est pas toujours une mince affaire.

Une solution

Ayant fait fasse au problème ci-dessus il y a peu, j’ai cherché une solution qui pourrait le résoudre. Impossible cependant, de mettre la main sur quoi que ce soit. J’ai donc décider d’écrire ma première extension pour Mercurial. Voici hg-publishall. Une extension simple qui rajoute une commande à l’outil hg : pushall. Lors de son exécution, l’extension va lire le fichier .hg/hgrc du dépôt et y récupérer tous les éléments dans [paths], et pour chaque va effectuer un hg push <url_du_depot>.

Installation

Récupérez la dernière version du script : hg-publishall (trunk). Décompressez l’archive et déplacez le script publishall.py là où vous placez vos extensions Mercurial (chez moi c’est /Users/thomas/Library/Mercurial/). Pensez à le rendre exécutable par le ou les utilisateurs qui vont utiliser le script (chmod +x publishall.py sous Linux/BSD).

Vous devez ensuite configurer le dépôt qui va bénéficier de cette extension :

Soit le dépôt ~/depot-test/, j’ouvre le fichier ~/depot-test/.hg/hgrc et le modifie comme suit :

[paths]
default = ssh://server.localnet/depot-test/
bitbucket = https://:<user>:<pass>@bitbucket.org/<user>/depot-test/

[extensions] publishall = /Users/thomas/Library/Mercurial/publishall.py

Votre dépôt est maintenant configuré pour utiliser l’extension hg-publishall; et il sera publié sur deux autres dépôts : default (un dépôt sur le serveur du réseau local) et bitbucket (notez au passage que l’authentification sur les dépôts distant est exactement la même qu’ailleurs dans Mercurial).

Utilisation

Rien de bien compliqué. Toujours dans ~/depot-test/, après y avoir travaillé un peu comme vous en avez l’habitude, il suffit de taper :

$ hg pushall
Et c’est parti, les modifications que vous avez effectué sur le dépôt vont être publiées. Pour information : vous pouvez aussi utiliser hg pusha, qui est un alias à hg pushall.

Conclusion

Amusez vous bien, et n’hésitez pas à faire remonter tout ce que vous pouvez !

Posted in None at October 23rd, 2009. Comments.

FreeBSD : serveur web Lighttpd

Je pars ici sur le fait que vous avez d’une part, les bases d’utilisation d’une FreeBSD (ou de n’importe quelle autre *BSD, voir distribution Linux) et d’autre part un système FreeBSD récent (7 series actuellement) installé, fonctionnel et connecté à internet.

Servir pour le web

Pour cela, vous devez déterminer quel serveur web remplira cette tache pour vous. Chacun ses choix, chacun ses arguments. Je choisi ici d’installer Lighttpd (a.k.a. Lighty), car il convient parfaitement à mes besoins et est simple pour une utilisation standard.

Je couvrirais ici son installation et sa configuration pour l’utilisation suivante :

Rien de bien sorcier, le tout étant d’être méthodique et de prévoir dès le départ où on veut aller.

Lighty

Rien de bien compliquer dans l’installation de Lighty par les ports :

$ cd /usr/ports/www/lighttpd

make install clean

Normalement, les options de compilation pour Lighty doivent vous être demandées. Voici celles que j’ai choisi :

Options de compilation Lighty

Options de compilation Lighty

Normalement, l’installation devrait se dérouler sans trop de problème. Ajoutez maintenant la ligne suivante à /etc/rc.conf :

lighttpd_enable="YES"
Rien d’autre à faire ici. Pour votre information, le fichier de configuration est placé suivant la norme FreeBSD : /usr/local/etc/lighttpd.conf. Pour lancer/arrêter/redémarrer le serveur, utilisez /usr/local/etc/rc.d/lighttpd start|stop|restart. Pour récupérer des infos en cas de soucis, c’est tail -f /var/log/lighttpd.error.log.

PHP5

Là aussi, on va utiliser les ports :

$ cd /usr/ports/lang/php5

make install clean

Rien de très palpitant ici. Il nous faut maintenant installer les extensions PHP voulues, toujours par les ports :

$ cd /usr/ports/lang/php5-extensions

make install clean

Lors de la configuration, la liste des extensions à installer devrait vous êtres demandée. Choisissez celles que vous voulez. Pour info, j’ai choisis celles-ci : ctype, curl, dom, gd, imap, mbstring, mcrypt, mysql, mysqli, pcre, posix, session, simplexml, xml, xmlreader, xmlrwriter, zlib.

A la fin de l’installation, ouvrez le fichier de configuration de Lighty et effectuez les modifications suivantes :

  • Dans la liste server.modules, dé-commentez mod_fastcgi.
  • Descendez et dé-commentez le bloc relatif à fastcgi.server :
    fastcgi.server = ( ".php" =>
                             ( "localhost" =>
                                  (
                                   "socket" => "/tmp/php-fastcgi.socket",
                                   "bin-path" => "/usr/local/bin/php-cgi"
                                  )
                             )
     )

Enregistrez et relancer Lighty. PHP est maintenant opérationnel (vous pouvez tester avec un <?php phpinfo(); ?>).

Django

C’est ici la partie qui m’intéresse le plus.

Premièrement, installez Django (notez que ceci n’est qu’une façon de faire) :

$ cd /usr/ports/devel/py-setuptools

make install clean

/usr/local/bin/easy_install django

OK. Bon, dans mon cas, j’ai une application située dans /storage/www/thomas/, qui sera accessible depuis le web par http://thomas.pelletier.im/. Adaptez suivant vos besoins.

  1. Créez un dossier public dans /storage/www/thomas/.
  2. Adaptez et placez-y le fichier lighty.sh suivant :
    #!/bin/sh
    app_path='/storage/www/thomas/'
    p='/tmp/thomas-django.pid'
    cd "$app_path"
    if [ -f $p ]; then
     kill $(cat -- $p)
     rm -f -- $p
    fi
    
    exec /usr/bin/env \
     PYTHONPATH="$app_path/.." python \
     manage.py runfcgi \
     daemonize=false \
     method=prefork \
     maxspare=2 \
     pidfile="$p"
  3. Rendez le exécutable par www :
    $ chown www:www lighty.sh
    $ chmod +x lighty.sh
  4. Créez un fichier vide django.fcgi dans public/ (pas nécessaire je pense, mais ça marche pour moi).
  5. Ajoutez le bloc suivant à votre ligtttpd.conf :
    $HTTP["host"] == "thomas.pelletier.im" {
            server.document-root = "/storage/www/thomas"
    
            url.rewrite-once = (
                    "^(/.*)$" => "/public/django.fcgi$1",
            )                    
    
            fastcgi.server = (
                    ".fcgi" => (
                            "django" => (
                                    "socket" => "/tmp/thomas-django.socket",
                                    "bin-path" => "/storage/www/thomas/public/lighty.sh",
                                    "check-local" => "disable"
                            )
                    )
            )
    
    }
  6. Enregistrez et relancer Lighty.

Normalement c’est bon, votre projet Django est maintenant servi par lighty !

Mercurial

NB : je ne vais pas entrer dans les détails de la configuration d’un dépôt mercurial.

Il existe plusieurs moyens de servir des dépôts mercurial. J’ai choisis hgwebdir. Le site officiel détail l’installation en CGI. Je trouve ça dommage. Pour ma part, j’utilise ici FastCGI.

Je pars du fait que vous avez vos dépôts déjà configurés et fonctionnels dans /mesdepots/ et que vous avez deux dépôts : un publique : “helloworld” et l’autre privé “myproject”.

Pour la petite histoire, helloworld sera accessible en lecture ET écriture par tout le monde. C’est fait exprès, à but purement pédagogique. myproject lui, n’est accessible en écriture et en lecture uniquement par vous.

Premièrement, créez un dossier hg dans /mesdepots/. Placez-y le fichier hgwebdir.fcgi suivant :

#!/usr/bin/env python
#

An example CGI script to export multiple hgweb repos, edit as necessary

adjust python path if not a system-wide install:

import sys

sys.path.insert(0, "/path/to/python/lib")

enable demandloading to reduce startup time

from mercurial import demandimport; demandimport.enable()

Uncomment to send python tracebacks to the browser if an error occurs:

import cgitb

cgitb.enable()

If you'd like to serve pages with UTF-8 instead of your default

locale charset, you can do so by uncommenting the following lines.

Note that this will cause your .hgrc files to be interpreted in

UTF-8 and all your repo files to be displayed using UTF-8.

#

import os

os.environ["HGENCODING"] = "UTF-8"

from mercurial.hgweb.hgwebdir_mod import hgwebdir from flup.server.fcgi import WSGIServer

The config file looks like this.  You can have paths to individual

repos, collections of repos in a directory tree, or both.

#

[paths]

virtual/path1 = /real/path1

virtual/path2 = /real/path2

virtual/root = /real/root/*

/ = /real/root2/*

#

[collections]

/prefix/to/strip/off = /root/of/tree/full/of/repos

#

paths example:

#

* First two lines mount one repository into one virtual path, like

'/real/path1' into 'virtual/path1'.

#

* The third entry tells every mercurial repository found in

'/real/root', recursively, should be mounted in 'virtual/root'. This

format is preferred over the [collections] one, using absolute paths

as configuration keys is not supported on every platform (including

Windows).

#

* The last entry is a special case mounting all repositories in

'/real/root2' in the root of the virtual directory.

#

collections example: say directory tree /foo contains repos /foo/bar,

/foo/quux/baz.  Give this config section:

   [collections]

   /foo = /foo

Then repos will list as bar and quux/baz.

#

Alternatively you can pass a list of ('virtual/path', '/real/path') tuples

or use a dictionary with entries like 'virtual/path': '/real/path'

WSGIServer(hgwebdir('hgweb.config')).run()

Toujours dans le même dossier, créez et complétez le fichier hgweb.config suivant :
[paths]
helloworld = /mesdepots/helloworld/
myproject = /mesdepots/myproject/

[extensions] hgext.highlight=

[web] style = monoblue allow_archive = bz2 gz zip baseurl = /hg/ pygments_style =

Dans le fichier .hg/hgrc de myproject, ajoutez les paramètres suivant dans le bloc [web] :
allow_push = monutilisateur
allow_read = monutilisateur
Vous allez maintenant devoir créer le fichier contenant les comptes virtuels (ie : les utilisateurs mercurial ne sont pas des utilisateurs système). Créez le fichier /mesdepots/hg/passwords et ajoutez une ligne par utilisateur (vous pouvez utiliser des outils en ligne pour générer les lignes à rajouter). Pensez que dans l’exemple, le nom d’utilisateur est monutilisateur.

Editez le fichier /usr/local/etc/lighttpd.conf en l’adaptant à vos besoin : ici, les dépôts sont accessibles depuis http://monsite.com/hg/.

$HTTP["host"] == "monsite.com" {
    server.document-root = "/mesdepots/"
    server.follow-symlink = "enable"
    fastcgi.debug = 1

url.rewrite-once = (
    "^/hg(.*)" =&gt; "/hg/hgwebdir.fcgi$1",
)

$HTTP["url"] =~ "^/hg/" {
    dir-listing.activate = "enable" 

    # My Private repositories
    auth.debug = 2
    auth.backend = "htpasswd"
    auth.backend.htpasswd.userfile = "/mesdepots/hg/passwords"
    $HTTP["url"] =~ "myproject/" {
        auth.require = ( "" =&gt; (
                "method" =&gt; "basic",
                "realm" =&gt; "This is a private repository. If not allowed, go fuck yourself.",
                "require" =&gt; "valid-user"
            )
        )
    }

    # Global config

    fastcgi.server = (
        ".fcgi" =&gt; (
            "hgwebdir" =&gt; (
                "bin-path" =&gt; "/mesdepots/hg/hgwebdir.fcgi",
                "socket" =&gt; "/tmp/hg.socket",
                "check-local" =&gt; "disable",
            )
        )
    )
}

}

Définissez l’utilisateur et le groupe www comme propriétaire du dossier /mesdepots/hg (chown -R www:www /mesdepots/hg). Donnez enfin les droits d’exécution à hgwebdir.fcgi (chmod +x /mesdepots/hg/hgwebdir.fcgi) et redémarrez votre lighty.

Posted in None at October 17th, 2009. Comments.

FreeBSD : serveur DNS Bind9

Je pars ici sur le fait que vous avez d’une part, les bases d’utilisation d’une FreeBSD (ou de n’importe quelle autre *BSD, voir distribution Linux) et d’autre part un système FreeBSD récent (7 series actuellement) installé, fonctionnel et connecté à internet.

Gardez en tête que je n’aborde ici que les aspects techniques de l’affaire, le domaine des DNS étant un trop vaste sujet.

Je discerne deux utilisations d’un serveur de noms :

  1. Servir de cache pour le réseau local : les postes utilisant le serveur verront leur vitesse de résolution de noms augmenter fortement (chez moi, je suis passé de 400ms à 6ms).
  2. Agir en maître d’un domaine : cela vous permet, si vous possédez mondomaine.com, d’indiquer au monde que serveur.mondomaine.com réside à telle ou telle adresse IP, entre autres.

Bien sûr, il est possible de faire bien plus de choses avec Bind9, mais ça ne m’intéresse pour le moment pas. Gardez aussi à l’esprit que je présente une méthode pour atteindre les objectifs prévus. Il doit en exister pleins d’autres. Si la mienne ne vous convient pas, et ben allez voir ailleurs tiens :)

Installation de Bind9

En fait, cette section est plus faite pour faire beau qu’autre chose, car Bind9 (aussi connu sous le nom de Named) est installé par défaut sous FreeBSD. Pour l’activer, rien de plus simple :

  1. Ajoutez la ligne suivante à /etc/rc.conf
    named_enable="YES"
  2. Démarrez le démon :
    /etc/rc.d/named start

Néanmoins, je tiens à préciser un point : par défaut, Bind9 n’écoute qu’en local, c’est-à-dire que seule la machine sur laquelle il tourne peut y accéder. Si vous voulez ouvrir votre serveur à l’extérieur (votre réseau local, mais aussi le net),  modifiez la ligne suivante dans /etc/namedb/named.conf :

listen-on       { 192.168.0.16; };
192.168.0.16 est l’adresse IP sur le réseau local de la machine en question.

Servir de cache pour le réseau local

Bien. Tout se passe dans le fichier /etc/namedb/named.conf. Ouvrez le avec votre éditeur favori et suivez le guide.

Exploiter les serveurs DNS de votre FAI

Pour éviter que votre propre serveur DNS n’ai a attaquer directement les serveurs DNS mondiaux (pour des raisons d’efficacité et d’encombrement de réseau), vous devez donner à Bind9 l’IP du serveur DNS primaire et secondaire de votre FAI. Dans mon exemple, c’est Numéricable, mais vous devriez pouvoir trouver les infos concernant le votre sur cette page.

Recherchez, décommentez et complétez l’options forwarders comme ceci :

forwarders {
 89.2.0.1;
 89.2.0.2;
};

N’autoriser que votre réseau local

Si vous laissiez votre serveur DNS répondre à n’importe quelle machine, je pense que ça ferait bien mal à votre serveur, votre bande passante, et votre moral. C’est pourquoi nous allons définir une Acess Control List, que vous allez adapter suivant votre configuration actuelle.

Ajoutez ce bloc avant le bloc options du fichier de configuration :

acl localnet {
 127.0.0.1/32;
 192.168.0.1/24;
};
Ici, je dit qu’appartiendront au groupe localnet les ordinateurs ayant les ips de type 127.0.0. et 192.168.0., autrement dit : le serveur lui même et les ordinateurs de mon réseau local.

Les permissions

Le plus gros du travail est fait. Maintenant vous devez dire à Bind9 qu’il doit :

  • Autoriser les requêtes venant de tous le monde (important pour la suite, voyez-ci après si vous ne voulez pas que ce soit le cas).
  • N’autoriser uniquement les membres du groupe localnet crée plus tôt à demander de résoudre un nom dont le serveur n’est pas le maître (on appelle cela la recursion. C’est plus compliquer que ça, mais on va laisser la théorie de côté pour aujourd’hui).

Dans le bloc options du fichier de configuration, ajoutez les 3 lignes suivantes :

allow-query     { "any"; };
allow-transfer  { localnet; };
allow-recursion { localnet; };
Il est important que allow-query soit sur any si vous souhaitez agir en tant que maître d’un domaine (voir ci-après). Si seul le cache vous intéresse, n’accordez les requêtes que depuis localnet (pour éviter le flood) :
allow-query     { localnet; };
C’est tout ! Redémarrez Bind9 : /etc/rc.d/named restart, et admirez.

Agir en maître d’un domaine

Pour l’exemple, je vais configurer un domaine local : localnet. Pour information, si vous voulez gérer un domaine international (mondomaine.com par exemple), c’est exactement la même chose !

Le but de mon domaine local est de fournir des adresses canoniques à certaines de mes machines :

  • server.localnet -> mon serveur perso : 192.168.0.16
  • router.localnet -> le routeur de la maison : 192.168.0.1
  • hdd.localnet -> le disque dur réseau : 192.168.0.14

Et c’est tout. Mais c’est quand même déjà sympathique.

Je ne vais pas rentrer dans le détail de la configuration. Les fichiers parlent d’eux-mêmes, et si vous les trouvez obscur, Google arrivera à vous éclairer.

Premièrement, créez et complétez le fichier /etc/namedb/localnet :

$TTL    2h

@    IN    SOA    server.localnet. postmaster.localnet. ( 2009101201 8H 2H 1W 1D )

@    IN    NS    server.localnet.

server        A    192.168.0.16 router        A    192.168.0.1 hdd         A    192.168.0.14

C’est ce fichier qui permet à Bind9 d’associer une adresse IP à un nom (on lui donne le nom, il nous rend l’IP). Il faut aussi qu’il soit capable de faire l’inverse : on lui donne une IP, il nous donne le nom. Le fichier qui s’en occupe est relativement semblable.

Créez et complétez le fichier /etc/namedb/localnet.reverse :

$TTL 2h
@    IN    SOA    server.localnet. postmaster.localnet. (
                              2009101201
                              8H
                              2H
                              1W
                              1D
 )

@    IN    NS    server.localnet.

1     IN    PTR    router.localnet. 16    IN    PTR    server.localnet. 14    IN    PTR    hdd.localnet.

Notez que les nombres à gauche sont la dernière partie de l’adresse IP local de la machine cible. Exemple de mon routeur : son IP est 192.168.0.1 le numéro qui apparait en première place de sa ligne est donc 1.

Vous devez ensuite dire à Bind9 qu’il est le DNS maître du domaine localnet et qu’il ne doit répondre pour ce domaine qu’aux requête du groupe localnet (celui qu’on a crée plus haut).

Ajoutez à la fin du fichier /etc/namedb/named.conf :

zone "localnet" {
 type master;
 file "/etc/namedb/localnet";
 allow-query { localnet; };
};

zone "0.168.192.in-addr.arpa" { type master; file "/etc/namedb/localnet.reverse"; allow-query { localnet; }; };

Vous devez faire attention ici dans le deuxième bloc : 0.168.192 est l’inverse de 192.168.0. Donc si vos IP de votre réseau local sont du genre 192.168.1.*, vous devrez indiquer la zone 1.168.192.in-addr.arpa.

Redémarrez Bind9, et si votre ordinateur est configuré pour utiliser le serveur en tant que serveur DNS, vous devriez pouvoir ping router.localnet (dans mon exemple).

Conclusion

Voilà, c’est tout. C’est pas bien compliqué quand on y pense. Bon courage avec votre DNS !

Posted in None at October 12th, 2009. Comments.

FreeBSD : Serveur Mail

Je viens de trouver un excellent howto (en anglais) concernant la mise en place d’un serveur mail complet (IMAP/SMTP/webmail/antispam/antivirus) avec FreeBSD.

Je comptais en écrire un, mais je ne pense pas pouvoir faire mieux (tout au mieux, le traduire en français), donc le voici :

FreeBSD Mail Server Setup on purplehat.org

Posted in None at October 11th, 2009. Comments.

FreeBSD, ça le fait

Un petit message rapide pour annoncer deux choses :

  1. J’ai enfin fini de mettre en place les serveurs HTTP, DNS, IMAP, SMTP (entre autres) sur mon serveur perso sous FreeBSD. Si il y en a qui sont intéressés, je peux sans soucis écrire un howto et le diffuser ici.
  2. J’en profiter pour annoncer mon changement d’adresse email (cf A propos).
Posted in None at October 5th, 2009. Comments.