mardi 31 décembre 2013

Installation de Visual Editor sur mediawiki

Mediawiki est le nom du logiciel qui fait tourner les wikis de la fondation wikipedia. Depuis maintenant quelques années, ces derniers cherchent à mettre en place un éditeur de code wiki user friendly et compatible avec le code wiki existant. En effet, la fondation a constaté que la syntaxe du wiki était un obstacle à l'arrivée de nouveaux contributeurs. Même si la situation n'est pas non plus catastrophique, la fondation a donc voulu diminuer cette difficulté en lançant un éditeur plus conviviale.

Les résultats de ces travaux sont l'extension Visual Editor pour mediawiki. Je vous laisse vous rendre sur cette page pour avoir plus de détail : http://meta.wikimedia.org/wiki/VisualEditor/MediaQ%26A

Cette interface a été déployé sur pratiquement tout l'ensemble des serveurs de la fondation wikipedia et fait toujours l'objet de travaux.

Voilà pour le contexte. Voyons maintenant comment nous en servir sur notre propre wiki.

Fonctionnement de Visual Editor

Un des pré-requis de ce logiciel comme je l'expliquais plus haut est de rester compatible avec la quantité énorme d'article déjà existant et donc de respecter le rendu des articles existants. Pour se faire, l'éditeur passe par une phase de rendu du code wiki en HTML en utilisant l'API du wiki avant d'être resservi à l'internaute au travers d'un éditeur HTML. Quand une modification est opérée (sur le code HTML), ce code est renvoyé au travers un sérialiseur qui se chargera de faire une translation inverse et surtout de supprimer les fausses différences. Par fausses différences, j'entends la suppression des espaces surnuméraires, le remplacement des doubles quotes (") par de simple quote (') etc.

Pour les plus curieux, je vous laisse découvrir l'article suivant qui explique ça mieux que moi : https://blog.wikimedia.org/2013/03/04/parsoid-how-wikipedia-catches-up-with-the-web/

Bref, ces deux services sont assurés à l'aide d'un webservice écrit en node.js (serveur d'application en javascript). Vous l'aurez compris, il va donc s'agir dans un premier temps d'installer ce serveur d'application et de l'intégrer ensuite dans notre wiki.

Installation de node.js

Par la suite, nous travaillerons sur une Ubuntu quantal (12.10) mais toutes les versions suivantes devraient fonctionner sans problème. J'ai également réalisé cette installation sur une CentOS 6.4. Il faut juste savoir qu'il faut disposer d'une version node 0.8 ou 0.10 minimum.

Bref, sous Ubuntu, nous allons tout d'abord rajouter les sources qui nous manquent :

add-apt-repository ppa:chris-lea/node.js
apt-get update
apt-get install nodejs

Installation de Parsoid

Node.js est maintenant présent sur la machine, nous allons nous attacher à récupérer les sources de Parsoid. Ce dernier ne fait pas encore l'objet d'une livraison stable mais se récupère directement au niveau du repository git. Cette récupération se fait à l'aide de la commande suivante :

git clone https://gerrit.wikimedia.org/r/p/mediawiki/services/parsoid

Rendons-nous maintenant dans l'arborescence nouvellement récupéré et lançons la récupération des plugins pré-requis :

cd parsoid
npm install

Au bout de quelques temps, nous devrions être en mesure de lancer notre instance Parsoid avec la commande suivante :

node api/server.js

A ce moment, node.js vous lancera des workers Javascript afin de prendre en charge le travail requis pour le webservice dont nous avons parlé plus haut. Pour vous assurez que tout fonctionne, nous pouvez vous rendre sur l'adresse suivante : http://localhost:8000/

Sachez que vous aurez peut-être des choses à adapter à votre configuration en fonction de votre wiki. La personnalisation se fera dans le fichier api/localsettings.js. Sachez qu'il y a un fichier exemple (localsettings.js.example) afin de vous donner des exemples de syntaxe.

Pour plus de détail, je vous laisse consulter l'article sur Parsoid à l'adresse suivante : http://www.mediawiki.org/wiki/Parsoid

Intégration au wiki

Le présent article n'a pas pour vocation d'expliquer comment s'installe mediawiki. Si vous avez besoin d'une piste pour faire cette étape, je vous laisse consulter cet article sur le sujet. Sachez qu'il vous faudra une version récente de mediawiki avec au moins une version 1.22.

Seconde chose, il va nous falloir récupérer une version de l'extension Visual Editor sur le site de mediawiki. La page suivante devrait vous permettre de récupérer ça : http://www.mediawiki.org/wiki/Special:ExtensionDistributor/VisualEditor

Il faudra ensuite :

  • Se rendre dans le répertoire des extensions du wiki : 
cd /var/www/wiki/extensions
  • Décompresser l'extension :
tar xfv .../wikimedia-mediawiki-extensions-VisualEditor-43e96d7.tar.gz
  • Renommer le répertoire :
mv wikimedia-mediawiki-extensions-VisualEditor-43e96d7/ VisualEditor

Enfin, nous pouvons rajouter les lignes suivantes à la fin du fichier LocalSettings.php :

# Parsoid and Visual Editor configuration
require_once("$IP/extensions/VisualEditor/VisualEditor.php");
$wgDefaultUserOptions['visualeditor-enable'] = 1;
$wgHiddenPrefs[] = 'visualeditor-enable';

$wgVisualEditorParsoidURL = 'http://localhost:8000';
$wgVisualEditorParsoidPrefix = 'localhost';

Une petite démonstration parlant mieux qu'un long discours, je vous laisse découvrir une petite démo du fonctionnement de ce plugin :


NB : Bonne année à tous !

mardi 1 octobre 2013

Quelques benchs sur Logstash et ElasticSearch

Voilà, je n'ai pas pu y résister. L'autre jour, j'étais tranquillement en train de traîner dans la tribune de rédaction de linuxfr et j'ai aidé à rédiger un article sur ma nouvelle lubie : Logstash, ElasticSearch et Kibana. L'article est relativement pédagogique mais ne pousse pas la réflexion plus loin que la mise en place. Il aurait été intéressant d'ajouter quelques benchs.

Comme de mon côté, je n'avais pas vraiment eu l'occasion de trop pousser le produit non plus (juste au travers un petit POC pas super poussé en terme de volumétrie) je me suis dit qu'après tout ça serait l'occasion de le faire.

Les conditions du test

Comme vous savez sûrement, j'attache énormément d'importance à la pensée Cartésienne. Pour se faire je me dois de vous donner quelques caractéristiques sur la machine sur laquelle je travaille. En voici quelques-unes (ne pas hésiter à me signaler des manquements) :
  • Processeur : AMD Phenom(tm) II X4 965 Processor ;
  • Mémoire : 8 Go - Swap : 8 Go ;
  • Java : OpenJDK (IcedTea 2.3.10) (7u25-2.3.10-1ubuntu0.13.04.2) ;
  • Taille du fichier : 167997125 (~ 160 Mo) ;
  • Nombre de ligne : 1354848.
Attention : les benchs qui vont être réalisés plus loin sont fait par un néophyte sur ces produits. Si vous pensez que j'ai pu faire des erreurs, n'hésitez pas à me les signaler !

Quelques benchs

Les premiers pas

Pour me faire une idée de la capacité de traitement de logstash, j'ai voulu démarrer par un test très simple : en entrée une socket d'écoute simple et la sortie dans un fichier sans aucun traitement dessus. Pour mémoire, voici le fichier de configuration (bench.conf) que j'ai utilisé :

# Écoute sur le port 2048 de la machine
input {
  tcp {
    port => 2048
  }
}
# Balance le JSON obtenue dans un fichier
output {
  file {
    path => "./bench.json"
  }
}

Le lancement de logstash se fait avec la commande suivante :

java -Xms256m -jar logstash-1.2.1-flatjar.jar agent \
     -f bench.conf

Il ne me reste plus qu'à injecter le contenu de mon fichier dans la socket - ce que je fais à l'aide de la commande nc (netcat) - précédé par la commande time pour avoir une idée du temps que je mets :

time cat /var/log/syslog.1 | nc localhost 2048

Grosso modo, j'arrive donc à un temps de traitement de 41 secondes (soit environ 4 Mo/s ou encore 33045 lignes/s).

Voyons maintenant quelque chose de plus proche de la réalité.

Injection dans un moteur ElasticSearch

J'ai tout d'abord utilisé le moteur ElasticSearch embarqué. La configuration était la suivante :

output {
  elasticsearch {
    embedded => true
  }
}

En lançant le bench, j'obtiens une injection en environ 144 secondes.

Injection dans un moteur ElasticSearch externe

Ici, on va simplement configurer un moteur ElasticSearch afin de le faire tourner dans un process séparé. La configuration est relativement simple puisque nous allons reprendre celle par défaut. Une fois décompresser, le lancement se fait donc avec la commande suivante :

./bin/elasticsearch -f

NB : On procédera également à la suppression des données du moteur entre deux lancements du bench afin d'éviter une influence sur le résultat.

Enfin, du côté de logstash, nous allons simplement modifié la section output de la configuration de la manière suivante :

output {
  elasticsearch {
    host=> "robert"
    cluster => "elasticsearch"
    embedded => false
  }
}

En relançant le traitement, nous obtenons 113 secondes. Bonne nouvelle, c'est mieux.

Quelques modifications de paramètres sur Logstash

Essayons de buffuriser un peu nos écritures afin de voir l'impact que ça pourrait avoir. Le premier sera le paramètre flush_size (nombre maximum d'événement à flusher, par défaut 100). Voici l'impact sur le temps de traitement en fonction de sa valeur :
  • 200 : 114 secondes ;
  • 1000 : 110 secondes ;
  • 10000 : 105 secondes ;
  • 100000 : 101 secondes ;
  • 1000000 : 105 secondes.
Le gain est relatif et on peut voir que nous arrivons à un plafond au delà duquel, nous n'avons plus du tout d'impact sur les performances.

On va maintenant se pencher sur le paramètre idle_flush_time (temps maximum d'attente entre deux flushs, par défaut à 1 seconde). Ici encore, voyons l'impact sur les performances (avec un flush_size à 100000) :
  • 2 s : 104 secondes ;
  • 4 s : 107 secondes.
Bref, ça s'améliore pas. Donc de ce côté ci, on va arrêter les recherches !

Quelques modifications sur ElasticSearch

On va tout d'abord essayer d'espacer les flushs sur disque en bougeant le paramètre index.translog.flush_threshold_period (temps entre deux commits, par défaut 30m). En le passant à 5 s, nous baissons le temps de traitement à 99 secondes.

J'ai ensuite essayé divers modifications en suivant le document suivant : https://gist.github.com/duydo/2427158. Malheureusement, je n'ai jamais trouvé d'autre levier suffisamment efficace pour améliorer les choses. Il semblerait que ma machine manque de puissance pour pouvoir aller plus loin.

Pour conclure

Le but de ce bench était de se faire une idée de la capacité de traitement de notre ami Logstash et de son copain ElasticSearch sur une machine seule. Pour résumer, il faut tout de même se dire qu'on est en mesure de traiter environ 16 000 lignes / secondes ou 1,6 Mo / secondes (ce qui n'est pas mal du tout !). Même si j'ai déjà vu des choses particulièrement atroces qui devait pas être loin de cette volumétrie, je pense que ces produits ont du potentiel.

Autre point, nous sommes sur une infrastructure non distribué avec l'indexeur et le shipper sur la même machine. Je pense qu'il aurait été intéressant de distribuer la charge sur plusieurs machines (notamment pour ElasticSearch). Je vais essayer de voir si je ne pourrais pas récupérer quelques machines pour aller un peu plus loin dans mes tests. Mais en l'état, je pense que je vais arrêter mes tests pour l'instant.

mardi 27 août 2013

Back to basic : maîtriser le multitâche dans une session en mode texte


Bon, je sais, je vais passer pour un vieux schnoque mais voilà : on n'a pas toujours la possibilité d'avoir du multitâche (surtout en SSH sur un serveur dans une DMZ ou connecté en directe sur une console au cul d'un serveur) mais c'est bien pratique de pouvoir passer d'une tâche à une autre. Je ne prétends pas tout connaître mais, je vais vous livrer quelques petits trucs que j'utilise (ou que j'ai eu utilisé) dans le domaine.

Les terminaux virtuels

Je pense qu'il s'agit du mode le plus simple et qu'on privilégiera dans le cas où vous êtes sur une machine Linux sans connexion X. Ici, rien de bien compliqué, vous pouvez passer d'un terminal à un autre en utilisant la combinaison de touche Alt+Fn (il faut rajouter Ctrl dans le cas où vous avez une connexion sous X).

Par ce mécanisme, vous pouvez tout à fait ouvrir un premier terminal puis éditer un fichier à l'aide de vi (ou emacs) et, sur un autre terminal, parcourir une arborescence (par exemple). Dans ma jeunesse (je vous l'avais dit que je passerai pour un vieux teuteu), j'avais l'habitude de lancer l'excellent mpg123 en arrière plan pour écouter mes mp3s sans risque de voir ma session X me planter ma lecture.

Petit problème, si vous travaillé en SSH, ça ne fonctionne plus et en plus de ça, il n'est pas dit que votre vieille version d'Unix propriétaire le gère (en même temps, y'a t'il des fous prêt à travailler avec un M4000 ou autre station à base de Power7 posé sur son bureau ...).

Gérer des tâches en ligne de commande avec votre shell

Voilà, vous êtes maintenant connecté en SSH sur votre serveur, vous êtes en train d'éditer votre fichier et vous avez besoin de jeter un coup d'oeil rapide sur le contenu d'un autre fichier. Bien sûr, il est toujours possible de le faire avec vi (en lançant un shell avec !bash) mais c'est loin d'être pratique. Pourtant il y a beaucoup plus simple : l'utilisation des tâches en shell.

C'est ici qu'entre en scène la combinaison de touche Ctrl+Z. Quand vous faîtes cette combinaison de touche, votre programme en cours d'exécution se retrouve mis en pause et vous vous retrouvez directement sur votre shell qui était resté tranquillement en arrière plan. Ci-dessous voici ce que nous obtenons en faisant cette combinaison de touche dans vi :

[yperre]/home/yannig> vi toto

[1]+  Stopped                 vi toto
[yperre]/home/yannig>

Une fois que vous avez réalisé l'opération que vous vouliez, vous voulez revenir à votre tâche précédente. Tapez simplement la commande fg (foreground) et vous voici de retour dans votre éditeur comme si rien ne s'était passé.

Bon mais voilà, maintenant, vous voulez éditer un second fichier en parallèle. Du coup, vous passer votre première instance vi en arrière plan et vous éditer le fichier titi. Et tout d'un coup, vous voulez revenir à votre première tâche d'édition. Problème, avec fg, vous revenez à la dernière commande que vous avez lancé. Dans ce cas, il suffit de taper %1, %2 etc. en fonction du numéro de la tâche que vous voulez rebasculer en premier plan.

Maintenant, vous êtes en train d'expérimenter un nouveau produit (tomcat, elasticsearch, logstash etc.) mais comme souvent, le shell est mal foutu et se bloque à l'exécution. Problème, vous avez toujours envie de consulter un fichier et vous êtes un peu bloqué. En effet, lorsque vous faîtes Ctrl-Z, votre process est en pause et ne traite plus les requêtes entrante. C'est là qu'entre en scène l'ami bg (background).

Comme vous êtes joyeux et que vous avez lancé plusieurs process en arrière plan et maintenant vous voulez en tuer un ou deux. Alors vous avez toujours la solution du bon vieux kill . Mais sinon, vous pouvez également utiliser kill %1.

Pour conclure

Loin de moi l'idée d'avoir présenter toutes les possibilités dans le domaine. Vous pourrez également vous tourner vers l'utilitaire screen qui a également l'avantage de pouvoir faire persister votre session même si votre connexion SSH se plante lamentablement. Je ne saurais que trop vous conseiller de l'utilisier dans le cas d'un long traitement critique (migration/import de base, recopie de données, mise à jour etc).

vendredi 26 juillet 2013

Installation d'application Ruby on Rails sans connexion internet

Bizarrement, je n'avais jamais trop travaillé sur les applications écrit en rails et par conséquent, je n'avais jamais eu affaire aux désagréments qui vont avec. Bien sûr, je ne parle pas du langage en lui-même ni des frameworks qui vont avec. Non, c'est plutôt dans la gestion des gems avec le fameux utilitaires bundler.

Oui, parce qu'il faut savoir c'est que, si vous avez une connexion internet, ce brave ruby va gérer tout seul ses dépendances et compagnie. Par contre, si vous êtes comme moi dans une DMZ dans laquelle il n'est même pas question d'entendre parler de flux sortant sur un proxy, vous allez vite vous sentir seul.

C'est donc après avoir bien galéré que je me suis dit qu'une petite entrée sur mon blog aurait un double bénéfice (au delà de l'aspect purement narcissique) : me servir de pense bête et vous servir à vous les nombreux lecteurs de ce blog.

Par la suite, nous travaillerons sur l'installation de l'application Kibana (pour faire de la recherche de grosses données dans le nuage, euh, je veux dire, du scoring de big data dans le cloud).

Au début il vous faut quand même une connexion internet

Pour l'installation initiale de votre application, il vous faudra au moins une connexion internet pour commencer. Si vous n'avez pas accès directement à internet, vous pouvez toujours passer par un proxy. Pour cela, il faut exporter la valeur du proxy dans la variable http_proxy :

export http_proxy=http://user:mdp@proxy:port

Une fois ceci fait, vous pouvez lancer le bundle de votre application. Mais vous vous en doutez, avant de le faire il faut installer bundler. A noter que vous devrez installer les packages ruby et rubygems (si vous êtes sous Redhat, ça se fait très rapidement avec la commande yum install ruby rubygems). L'installation de bundler se fait simplement avec la commande suivante :

gem install bundler

Une fois que bundler est installé, nous allons pouvoir maintenant récupérer les gems pour notre application. Prenons le cas de l'application Kibana. Pour se faire, il vous faudra :
  • Décompresser votre application ;
  • Se rendre dans le répertoire décompressé et lancer la commande suivante :
bundle install

De là, l'ami bundle va se connecter sur internet et récupérer toutes les dépendances dont nous avons besoin.

Création d'un bundle

Maintenant que notre application tourne, nous allons maintenant pouvoir faire un bundle de nos dépendances afin de les recopier sur nos serveurs de production qui n'ont pas du tout de connexion internet (les pauvres ...). L'opération est très simple et se fait avec la commande suivante :

bundle package
Your Gemfile contains path and git blablabla.
Resolving dependencies...
Using rake (10.1.0)
Using daemons (1.1.9)
[...]
Your bundle is complete! blablabla.
Updating files in vendor/cache

De là, l'ami bundle devrait vous faire un répertoire vendor/cache avec les fameux gems à installer.

Installation en production

Il ne vous reste plus qu'à faire un transfert de ce répertoire dans le répertoire de l'application sur vos serveurs de production et de lancer la commande suivante :

bundle install --local

Là, bundle devrait comprendre qu'il faut qu'il utilise le contenu du répertoire vendor/cache. Il ne vous restera plus qu'à prendre un café à ma santé.

mercredi 24 juillet 2013

Packager NSClient++ sous Windows (64 bits) à l'aide de puppet

Bon, pas la peine d'en rajouter sur le titre, j'ai honte. Mais bon voilà, j'avais commencé à vouloir packager NSClient++ avec l'OS alternatif propriétaire (avec ce plugin), et je me suis rendu compte que le package NSClient++ était réinstallé tout le temps. J'ai donc voulu savoir pourquoi.

En effet, en lançant l'application du catalogue sur mon noeud, j'avais systématiquement ce message :

Notice: /Stage[main]/Nscp/Package[nscp]/ensure: created
Notice: /Stage[main]/Nscp/File[C:\Program Files\NSClient++\nsclient.ini]/content:

Info: /Stage[main]/Nscp/File[C:\Program Files\NSClient++\nsclient.ini]: Filebucketed C:/Program Files/NSClient++/nsclient.ini to main with sum e3daba1
4bc76433649a9c4af706042ac
Notice: /Stage[main]/Nscp/File[C:\Program Files\NSClient++\nsclient.ini]/content: content changed '{md5}e3daba14bc76433649a9c4af706042ac' to '{md5}38b
2bb3dbe8530f33d983ccfd8394628'
Info: /Stage[main]/Nscp/File[C:\Program Files\NSClient++\nsclient.ini]: Scheduling refresh of Service[nscp]
Notice: /Stage[main]/Nscp/Service[nscp]: Triggered 'refresh' from 1 events
Notice: Finished catalog run in 11.64 seconds

En gros, mon package nscp était constamment réinstallé et ce dernier venait également mettre à jour le fichier nsclient.ini. Je me suis donc dit que le package n'avait pas le bon nom et qu'il fallait que je trouve le bon. Après avoir essayé NSClient++, NSClientpp, j'en ai eu marre de chercher et je me suis posé la question de savoir comment avoir le nom de ce fameux package. C'est là que j'ai découvert l'existence de la commande puppet resource package. Ci-dessous un extrait de la sortie de cette commande :

[...]
package { 'NSClient++ (x64)':
  ensure => 'installed',
}
package { 'Puppet Enterprise':
  ensure => 'installed',
}
[...]

J'avais enfin le nom de mon package ('NSClient++ (x64)') et du coup, NSClient arrêtait de s'installer systématiquement et donc, le fichier nsclient.ini n'était plus à mettre à jour. En gros, mon agent n'avait plus rien à faire. Bonne nouvelle donc !


lundi 22 juillet 2013

Utilisation de Puppet sous AIX pour la gestion des logicals volumes

Depuis quelques temps, j'ai découvert un nouveau sujet d'amusement : Puppet. Le produit est particulièrement intéressant et j'ai commencé à travailler sur un POC impliquant des agents pour différents OS (AIX, Linux et bien sûr Windows).

C'est à cette occasion que j'ai découvert l'existence de Puppet Forge et notamment l'excellente extension permettant de gérer les volumes groupes de Linux (extension lvm). Suite à ça j'ai voulu disposer de la même chose pour AIX. Au début, j'ai voulu implémenter ça directement dans le module lvm mais devant le travail que ça représentait, j'ai préféré faire quelque chose de spécifique mais surtout de plus simple. Je verrai plus tard pour faire ça comme il faut :)

Cette classe s'utilise sous la forme de module. Il vous faut donc créer un répertoire /etc/puppet/modules/aix avec un sous répertoire manifests:
mkdir -p /etc/puppet/modules/aix/manifests
Créer ensuite le fichier aix/manifests/logical_volume.pp avec le contenu suivant :

# Handle AIX LVM
define aix::logical_volume(
  $mount_point,
  $ensure = "present",
  $vg = "rootvg",
  $size = "",
  $lv_options = "",
  $fs_options = ""
) {

  $lv_name = $title
  $fs_type = "jfs2"

  case $ensure {
    # Clean up the whole chain.
    cleaned: {
        mount { $mount_point: ensure => "unmounted",
                atboot=> false, device => "/dev/$lv_name" } ->
        exec {"/usr/sbin/rmfs /dev/$lv_name ":
            onlyif => "/bin/test -n \"`/usr/sbin/lsfs $mount_point 2> /dev/null`\"",
        }
    }
    # Create the whole FS
    /^(present|created)$/: {
        # Creation du FS avec un nombre de block = 1
        exec {"/usr/sbin/mklv -t$fs_type -y $lv_name $options $vg 1":
            onlyif => "/bin/test ! -b /dev/$lv_name"
        } ->
        exec {"/usr/sbin/crfs -v$fs_type -d $lv_name -m $mount_point $options -A yes -a logname='INLINE'":
            onlyif => "/bin/test -z \"`/usr/sbin/lsfs $mount_point 2> /dev/null`\"",
        } ->
        mount { $mount_point: ensure => "mounted", atboot=> true, device => "/dev/$lv_name" }
        case $size {
            /^(\d+)([KMGT])$/: {
                $size_hash = { "K" => 1, "M" => 1024, "G" => 1048576, "T" => 1073741824 }
                $kilo_size = $1 * $size_hash[$2]
                $block_size = $kilo_size * 2
                exec {"/usr/sbin/chfs -a size=$size $mount_point":
                    onlyif => "/bin/test ! \"`/usr/sbin/lsfs $mount_point | /usr/bin/awk '/$lv_name/ { print \$5 }'`\" = \"$block_size\"",
                    require => Mount[$mount_point]
                }
            }
            /^\s*$/: { }
            default: {
                fail ( 'size is not valid (eg: 1G, 256M, 1T etc.)' )
            }
        }
    }
    default: {
        fail ( 'aix::logical_volume: ensure parameter can only be set to cleaned or present/created' )
    }
  }
}
De là, vous pourrez l'utiliser sous cette forme dans une déclaration de noeud :
node 'machineaix' {
  aix::logical_volume { "test":
      mount_point => "/test",
      size => "1G"
  }
}

Cette merveille a été testé avec succès sous AIX 7.1 et devrait fonctionner sans problème sous AIX 5.3 et 6.1.

vendredi 21 juin 2013

Faire sauter son mot de passe Windows

Si comme moi vous utilisez un ordinateur en dual boot et que ça fait à peu près 1 an 1/2 que vous ne vous êtes pas connecté sur votre compte Windows, vous avez certainement dû l'oublier. Et quand vous devez dans le même temps faire une procédure d'installation sur ce type d'OS et que vous n'avez aucune espèce d'idée de comment faire ça (ni les CD de boot d'ailleurs), vous serez sûrement content d'apprendre que vous pouvez faire ça avec un super utilitaire en ligne de commande : j'ai nommé l'ami chntpw.

Première chose, on va l'installer :

apt-get install chntpw

Quelques secondes plus tard, vous devriez être prêt pour la suite.

Mais où est passé l'ami SAM

Chez Unix, les hash des mots de passe sont dans /etc/shadow. Sous Windows, c'est l'ami SAM qui un rôle à peu près équivalent (en tout cas, il contient les hashs des mots de passes utilisateurs).

Avant toute chose (si ce n'est déjà fait), on va monter notre lecteur Windows dans /mnt :

mount /dev/sda2 /mnt

De là, il faudra se rendre dans le répertoire /mnt/Windows/System32/config où nous pourrons commencer à torturer l'ami SAM.

Première chose, nous allons afficher les comptes déclaré dans notre beau fichier SAM :
# chntpw -l SAM
[...]
* SAM policy limits:
Failed logins before lockout is: 0
Minimum password length        : 0
Password history count         : 0
| RID -|------- Username ---------| Admin? |- Lock? --|
| 01f4 | Administrator            | ADMIN  | dis/lock |
| 01f5 | Guest                    |        | dis/lock |
| 03e8 | TOTO2                    | ADMIN  | dis/lock |

Nous voyons ici 3 comptes mais seul TOTO2 nous intéresse (c'est mon compte). Pour se faire, relançons chntpw avec en paramètre l'utilisateur à modifier :

chntpw -u TOTO2 SAM

Ici, chntpw devrait nous proposer plusieurs choix avec notamment la possibilité de supprimer le mot de passe (choix n°1). chntpw vous demandera une confirmation pour écrire le fichier sur le disque. Répondez oui, que vous êtes un gros gueudin qui n'a peur de rien. Sinon, si vous êtes un peu plus raisonnable, faîtes non et faîtes une sauvegarde avant de tout péter.

Reste plus qu'à démonter le FS du Windows et redémarrer dessus pour vérifier que la manœuvre a bien fonctionné. Si tout c'est bien passé, vous devriez être en mesure de démarrer votre session avec le nouveau mot de passe. Pirate !

jeudi 13 juin 2013

Administration d'un serveur SVN à l'aide de SVN

Ma vie trépidante d'administrateur m'a amené dernièrement à mettre en place un serveur SVN en place (en utilisant le module Apache couplé avec authentification LDAP) et surtout l'isolement de ce serveur dans une bulle derrière des firewalls.

D'un côté c'est vrai que c'est bien la sécurité et tout ça, mais de l'autre, à chaque fois que j'ai envi de modifier un truc sur mon serveur, je suis un peu obligé de me connecter via un VPN + tunnel SSH. Comme chacun sait, je suis un gros feignant et c'est pas par gaîté de coeur que je m'y connecte. C'est donc assez naturellement que je me suis dit : et si j'utilisais un repository SVN pour faire mon administration ? Diabolique non ? De plus je gagnais instantanément un suivi de qui modifié quoi sur mon serveur SVN. Très pratique pour savoir qui taper en cas de problème.

Création du repos adminsvn

La première étape a été de créer un repository sur mon serveur qui allait me servir à ça. Pour cela, rien de plus simple, on crée un repository SVN :
$ svnadmin create /var/svn/adminsvn
On crée ensuite un trunk pour faire jolie ainsi qu'un sous-répertoire admin :
$ svn mkdir --parent file:///var/svn/adminsvn/trunk/admin -m "Création d'un trunk/admin"
Nous allons maintenant alimenter le fichier /etc/httpd/svn.d/droits-svn.conf afin de protéger le repository d'administration :
[groups]
admins_svn = yannig,cnorris

[/]
* = rw

[adminsvn:/]
# Personne ne peut lire le contenu de ce repository
* =
# Par contre, les admins SVN ont le droit de tout faire
@admins_svn = rw
Alimentons maintenant nos utilisateurs dans le fichier svn.passwd :
$ htpasswd -nb yannig mdpdeyannig > /etc/httpd/svn.d/svn.passwd
$ htpasswd -nb cnorris chucknorrisnapasbesoindemdp >> /etc/httpd/svn.d/svn.passwd
Ajoutons maintenant ces fichiers dans le repository avec la commande suivante :
$ svn add svn.passwd droits-svn.conf

Mise en place du mécanisme de post commit

Procédons maintenant à un checkout de ce repository SVN dans un coin de notre serveur (en tant qu'utilisateur apache ou www-data selon que vous soyez sous RH ou Debian like) :
$ svn co file:///var/svn/adminsvn/trunk/admin /etc/httpd/svn.d
Nous allons maintenant mettre en place un mécanisme de mise à jour de ce checkout. Rendez-vous dans le répertoire /var/svn/adminsvn/hooks et créons un fichier shell post-commit avec la commande suivante :
echo "svn up /etc/httpd/svn.d" > post-commit
chmod +x post-commit
Comme vous pouvez le voir, le script n'est pas super complexe.

Si vous n'avez pas utiliser le bon utilisateur pour faire le checkout, vous pouvez modifier les droits avec la commandes suivantes :
chown -R apache:apache /etc/httpd/svn.d

Déclaration d'un ensemble de repository dans apache

Déclarons maintenant la racine contenant le repository dans apache en créant le fichier /etc/httpd/conf.d/svn.conf avec le contenu suivant :
<Location /svn>
  DAV svn
  SVNParentPath /var/svn/
  SVNListParentPath On

  Options +Indexes
  AuthType Basic
  AuthName "SVN"

  # Gestion authentification
  AuthBasicProvider file
  AuthzSVNAccessFile /etc/httpd/svn.d/droits-svn.conf
  AuthUserFile /etc/httpd/svn.d/svn.passwd
  Require valid-user
</Location>
Un arrêt/relance de l'ami Apache et nous voilà prêt pour la suite.

NB : Il est bien sûr évidant que vous devez disposer de l'extension mod_dav_svn. Sous RHEL, vous devrez lancer la commande yum suivante pour procéder à l'installation :
yum install mod_dav_svn
Sous Debian, ce module s'appelle libapache2-svn. Vous devrez dans ce cas utiliser la commande suivante :
apt-get install libapache2-svn

Test de notre mécanisme

Cette partie est plus simple puisqu'elle va consister à faire des commits dans notre repository. Pour se faire, vous devez donc vous munir d'un client SVN. En tant que vieux barbu, je fais ça en ligne de commande depuis mon poste Linux :
svn co --username yannig http://monserveursvn/svn/adminsvn/trunk ~/adminsvn
Éditons maintenant votre fichier droits-svn.conf de la manière qu'il nous plaira et lançons le commit :
$ svn diff
Index: changelog.txt
===================================================================
--- droits-svn.conf       (revision 1)
+++ droits-svn.conf       (working copy)
@@ -1,3 +1,4 @@
-admins_svn = yannig,cnorris
+admins_svn = yannig,cnorris,nobody

[/]
* = rw

$ svn ci -m "Ajout de l'utilisateur nobody."
Sending        droits-svn.conf
Transmitting file data .
Committed revision 2.
Allons maintenant faire un tour sur notre serveur pour vérifier que le fichier droits-svn.conf a bien été mis à jour :
$ grep nobody /etc/httpd/svn.d/droits-svn.conf
admins_svn = yannig,cnorris,nobody
La modification a bien été prise en compte. Le mécanisme fonctionne bien comme prévu !

jeudi 30 mai 2013

Installation de Debian squeeze/OpenMediaVault sur PowerEdge R520 et baie Powervault MD1200 Base

Ces derniers temps, j'ai eu à mettre en place une Debian squeeze sur un Dell PowerEdge R520 avec une baie PowerVault MD1200. Comme je suis un mec super sympa, je me suis dit que j'allais raconter aux gens comment ça c'était passé.

Pour mémoire, le pourquoi de la distribution squeeze alors que la wheezy vient de sortir est un choix du client, ce dernier voulant utiliser l'appliance logiciel OpenMediaVault.

Première modification que j'ai apporté concerne la gestion du démarrage. En effet, ce serveur supporte UEFI mais squeeze ne le gère pas. Plutôt que de me prendre la tête sur le sujet à vouloir le faire fonctionner, j'ai décidé de passer le démarrage en mode BIOS.

J'ai ensuite utilisé l'interface BIOS de mon serveur afin de configurer mes deux RAIDs à savoir :

Première bonne surprise : la configuration du RAID se fait en arrière plan et il est possible de faire l'installation sans se préoccuper de la construction (Youpi ! je n'ai pas 3 jours à attendre que ça soit construit !).

Pour mémoire, voici les références de lspci de ces deux cartes :
# lspci | grep -i raid
01:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS 9240 (rev 03)
0a:00.0 RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS TB (rev 05)
Toujours pour mémoire, je vous donne le nom commercial de Dell pour ces cartes :

  • La première à pour petit nom PERC H310 Mini ;
  • La seconde PERC H810 Adapter.

Debian squeeze : premier essai

Confiant dans ma Debian squeeze, j'ai d'abord gravé l'image iso 6.0.7 avec les firmwares. Cette image est téléchargeable à l'emplacement suivant : Debian 6.0.7 incluant les firmwares.

J'ai ensuite démarré sur un disque USB afin de pouvoir entamer l'installation. Le premier écueil est arrivé au niveau de la gestion de la carte réseau (une Broadcom NetXtreme BCM5720 dual ethernet) puisque cette dernière a refusé de fonctionné (poukrel !).

Pour mémoire voici le résultat de la commande lspci :
# lspci | grep -i ethernet
02:00.0 Ethernet controller: Broadcom Corporation Device 165f
02:00.1 Ethernet controller: Broadcom Corporation Device 165f

Debian squeeze : deuxième essai

Dans mon malheur, cette carte semblait supportée par wheezy. J'ai donc cherché à installer le kernel en version backport. Mais comme vous vous en doutez, quand on a pas de réseau sur une bécane, ça devient vite embêtant de vouloir installer quelque chose. C'est pour cette raison que j'ai cherché une image ISO debian embarquant le kernel en version backport. Mes recherches m'ont donc amené sur cette image : Debian 6.0.4 avec un kernel 3.2.0 embarquant les firmwares.

Me voici maintenant à regraver ma distribution et à relancer mon installation. Bonne suprise, ça passe bien côté réseau.

Par contre, je tombe sur un obscure problème de configuration du clavier (du fait qu'il soit USB ?). Afin de m'en affranchir, je prends une option indiquant que le mapping sera celui du kernel. Je pense que ce problème vient du fait que l'image ISO n'embarquait pas les packages nécessaires pour gérer ça.

Pour mémoire, une fois l'installation terminée, j'ai dû lancer la commande suivante pour configurer le clavier de ma console correctement :
apt-get install console-data
De là, il vous sera demandé les informations concernant votre clavier et tout rentrera dans l'ordre.

Pour le reste, rien à signaler. Sachez simplement que la distribution a reconnu directement les deux RAIDs de la machine et que j'ai pu configurer sans problème mes FS alors que mes RAIDs étaient en cours de construction (super bonne suprise là aussi !).

Pensez bien à upgrader votre distribution à la fin de l'installation !

A noter que lors du premier boot, j'ai tout de même constater une certaine lenteur (on est autour des 3 minutes rien que pour l'OS sans compter les 2 minutes d'initialisation du matériel).

Installation d'openmediavault

L'installation se fait en deux fois. Installons d'abord ces packages :
apt-get install openmediavault-keyring postfix libapache2-mod-php5
On peut ensuite lancer l'installation d'openmediavault de la manière suivante :
apt-get install openmediavault locales
Vous devriez récupérer à ce moment pas mal de package et vous devriez avoir quelques réponses à donner sur la configuration des packages.

Installation de openmanage

Ayant du temps de rab, je me suis dit qu'il pourrait être intéressant d'installer l'application OpenManage de Dell. La configuration se fait en ajoutant des ressources dans le fichier /etc/apt/sources.list. Ci-dessous l'extrait en question :
deb http://linux.dell.com/repo/community/deb/latest /
Il faut ensuite l'installer :
apt-get install srvadmin-all
De là, il vous faut redémarrer votre serveur afin de charger les modules nécessaires à la gestion du matériel.

A noter que par défaut l'interface web d'OpenManage ne se lance pas. On peut le faire la première fois en lançant la commande suivante :
/etc/init.d/dsm_om_connsvc start
Afin que cette dernière se lance automatiquement au démarrage, il est possible de le faire avec la commande suivante :
update-rc.d dsm_om_connsvc defaults
L'accès se fait ensuite au travers l'URL suivante : https://machine:1131

L'interface demande un compte d'administrateur. Par défaut, il est possible d'utiliser le compte root mais il est également possible de rajouter des comptes administrateur.

Si vous êtes allergique à tout interface graphique, sachez qu'il est possible d'observer l'état du matériel avec la commande omreport. A noter que pour obtenir de l'aide, il faut utiliser le paramètre -?.

Pour avoir l'état des disques virtuels RAID, vous pouvez essayer la commande omreport storage vdisk. Ci-dessous un exemple de résultat (avec en paramètre le numéro du contrôleur et celui du disque virtuel) :
# omreport storage vdisk controller=1 vdisk=0
Virtual Disk 0 on Controller PERC H810 Adapter (Slot 4)

Controller PERC H810 Adapter (Slot 4)
ID                        : 0
Status                    : Ok
Name                      : Virtual Disk 0
State                     : Background Initialization
Hot Spare Policy violated : No
Encrypted                 : Not Applicable
Progress                  : 81% complete
Layout                    : RAID-6
Size                      : 25,146.00 GB (27000311906304 bytes)
Device Name               : /dev/sdb
Bus Protocol              : SAS
Media                     : HDD
Read Policy               : Read Ahead
Write Policy              : Write Back
Cache Policy              : Not Applicable
Stripe Element Size       : 64 KB
Disk Cache Policy         : Disabled
Dans le cas présent, on voit que notre disque virtuel est en cours de construction (champ Progress). Une fois cette construction terminée, le champ disparaît en indiquant un état (State) à Ready.

On peut également avoir l'état des cartes réseaux :
# omreport chassis nics
Network Interfaces Information

Physical NIC Interface(s)
Index             : 0
Interface Name    : eth0
Vendor            : Broadcom Corporation
Description       : NetXtreme BCM5720 Gigabit Ethernet PCIe
Connection Status : Connected
Slot              : Embedded

Index             : 1
Interface Name    : eth1
Vendor            : Broadcom Corporation
Description       : NetXtreme BCM5720 Gigabit Ethernet PCIe
Connection Status : Connected
Slot              : Embedded

Team Interface(s)
Index             : 0
Interface Name    : bond0
Vendor            : Linux
Description       : Ethernet Channel Bonding
Redundancy Status : Full

Pour conclure

Vous l'aurez compris, avant l'intervention, j'avais quelques appréhensions sur le support de ce matériel (Dell ne fait aucun support officiel). Comme j'ai été agréablement surpris sur certains points (surtout avec OpenManage), je me permets donc de faire un petit retour d'expérience.

Bref, le matos Dell et la wheezy (avec les firmwares), ça marche, mangez en !

vendredi 26 avril 2013

Sauvegarde incrémentale avec rsync

rsync est un programme Unix utilisé pour maintenir une copie d'une arborescence synchrone avec une autre en ne recopiant que les différences. Grâce à lui on peut donc réduire le nombre de fichier à recopier dans le cas d'arborescence qui change peu (c'est souvent utilisé dans le cadre de mirroir de site par exemple).

Pour ma part, je l'utilise souvent avec l'option -av :
rsync -av /mon/premier/repertoire /mon/repertoire/de/sauvegarde
On peut également rajouter l'option --delete afin que rsync procède également à la suppression des fichiers qui ont été supprimé d'un côté.

Seulement voilà, quand on veut faire une sauvegarde incrémentale pour conserver un historique de l'état d'une arborescence (ou les différentes versions d'un fichier), on se rend vite compte que c'est pas vraiment l'idéal. C'est là où on peut faire appel à la commande cp avec l'option -al (a = archive = préservation des liens symboliques + préservation des droits + copie récursive et l = pas de recopie mais utilisation d'un lien hard).

En faisant ainsi, on va recréer notre arborescence mais sans pour autant recopier les données (les fichiers seront identiques puisque pointant sur les mêmes inoeuds). Pour mieux comprendre, faisons quelques tests ...

Quelques tests sur les inoeuds ...

Créons un fichier quelconque :
$ cat > monfichier
Ceci est un fichier.
Recopions ce dernier avec la commande cp -al :
$ cp -al monfichier macopiedefichier
Regardons maintenant la valeur de l'inoeud :
$ ls -l1i monfichier macopiedefichier
457175 -rw-r--r-- 2 yannig yannig 21 Apr 26 15:52 macopiedefichier
457175 -rw-r--r-- 2 yannig yannig 21 Apr 26 15:52 monfichier
On se rend compte que ces deux fichiers sont en tout point identique. Maintenant, nous allons utiliser rsync pour faire cette recopie :
$ rsync -av monfichier uneautrecopie
Regardons à nouveau les inoeuds de nos fichiers :
$ ls -l1i monfichier macopiedefichier uneautrecopie
457175 -rw-r--r-- 2 yannig yannig 21 Apr 26 15:52 macopiedefichier
457175 -rw-r--r-- 2 yannig yannig 21 Apr 26 15:52 monfichier
457176 -rw-r--r-- 1 yannig yannig 21 Apr 26 15:52 uneautrecopie
Le nouveau fichier a bien un inoeud différent. Essayons maintenant de voir dans le cas d'un fichier déjà existant :
$ touch unautrefichier
Son numéro d'inoeud :
$ ls -i unautrefichier
457177 unautrefichier
Lançons maintenant notre synchronisation :
$ rsync -av macopiedefichier unautrefichier
Et jetons un coup d'oeil sur le résultat :
$ ls -l1i monfichier macopiedefichier uneautrecopie unautrefichier
457175 -rw-r--r-- 2 root root 21 Apr 26 15:52 macopiedefichier
457175 -rw-r--r-- 2 root root 21 Apr 26 15:52 monfichier
457178 -rw-r--r-- 1 root root 21 Apr 26 15:52 unautrefichier
457176 -rw-r--r-- 1 root root 21 Apr 26 15:52 uneautrecopie
On se rend bien compte que notre fichier de destination a bien été supprimé avant d'être recréé (457177 != 457178). Ce comportement est normal puisque c'est rsync qui fonctionne de cette manière.

Au final, ceci va donc me permettre de vous proposer un petit mécanisme de sauvegarde incrémentale.

A noter que si vous avez besoin de plus de détails pour comprendre les amis les inoeuds, je vous invite à vous tourner vers Wikipedia ou vers un bon bouquin sur Unix.

Passons maintenant à notre sauvegarde ...

Imaginons une arborescence /var/svn. Vous voulez sauvegarder tout ceci sur un serveur externe via rsync. Pour se faire, lançons tout d'abord une première sauvegarde depuis le serveur SVN :
rsync -av /var/svn/. backup:/var/backup/svn/.
Attention : Notre recopie à distance se fait à l'aide du protocole ssh. Il faudra donc avoir échangé les clés SSH entre le serveur SVN et celui de backup. Le répertoire /var/backup/svn devra également déjà exister sur la machine de backup.

Passons maintenant sur la machine de backup. Avant de lancer le rsync, nous allons d'abord recopier notre arborescence dans un nouveau répertoire en date du jour :
$ cp -al /var/backup/svn /var/backup/svn-date-du-jour
Ceci fait, nous pouvons maintenant lancer la commande de rsync :
$ rsync serveur-svn:/var/svn/. /var/backup/svn-date-du-jour/.
Reste maintenant plus qu'à faire un petit script de cette merveille combiné avec une crontab pour lancer ça automatiquement et vous voilà en face d'un superbe outil de sauvegarde !

A noter qu'il est également possible de se passer de la commande cp -al à l'aide de l'option --link-dest. En effet, cette dernière permet de faire un lien symbolique dans l'ancien répertoire dans le cas où les attributs externes du fichier n'aurait pas changé (permissions et date de modification). Dans ce cas, la commande à passer serait la suivante :
$ rsync --link-dest /var/backup/svn/. serveur-svn:/var/svn/. /var/backup/svn-date-du-jour/.

mercredi 27 mars 2013

Mise en place d'un bridge sous Debian/Ubuntu

Dans ma quête perpétuelle de la mise en place de truc qui fonctionne à moitié, j'ai eu la chance de me frotter aux bridges ethernets et aux interfaces ethernets virtuelles de l'ami Linux.

Mais qu'est ce qu'un bridge ethernet allez-vous me dire et pourquoi vouloir en mettre un en place ?

Un bridge ethernet est l'équivalent d'un switch virtuel au niveau système. L'idée est d'utiliser une interface réelle (mettons eth0) pour faire transiter du trafic des interfaces virtuelles (généralement tap0, tap1 etc.).

Pour ce qui est de l'utilité, vous en avez plusieurs avec notamment les deux exemples suivants :
  • Exposer une machine virtuelle sur un réseau réelle ;
  • Mettre en place un bridge ethernet pour openvpn.
Dans mon cas, je fais ça pour openvpn mais on peut également l'utiliser pour kvm par exemple.

Mise en place d'un bridge

Avant toute chose, il va nous falloir installer deux packages qui vous serons utiles pour gérer les bridges et les interfaces virtuelles (et puis, que serait un article sur Debian sans l'utilisation d'apt-get) :

apt-get install uml-utilities bridge-utils

Ici, rien de bien extraordinaire, nous allons d'abord déclarer un bridge (br0) dans le fichier /etc/network/interfaces, y ajouter notre interface ethernet (eth0) et enfin rattacher l'adresse dhcp au bridge. Ci-dessous, vous trouverez un exemple de fichier avant modification :

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

Après modification, le fichier devrait ressembler à ça :

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto br0
iface br0 inet dhcp
        bridge_ports eth0
        bridge_fd 9
        bridge_hello 2
        bridge_maxage 12
        bridge_stp off

Faîtes ensuite un restart networking pour prise en compte. La commande ifconfig devrait vous renvoyer ce qui suit :

# ifconfig
br0       Link encap:Ethernet  HWaddr 7e:68:47:11:36:c9  
          inet adr:192.168.0.34  Bcast:192.168.0.255  Masque:255.255.255.0
          adr inet6: fe80::7c68:47ff:fe11:36c9/64 Scope:Lien
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Packets reçus:3193 erreurs:0 :0 overruns:0 frame:0
          TX packets:1289 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 lg file transmission:0 
          Octets reçus:273039 (273.0 KB) Octets transmis:331151 (331.1 KB)

lo        Link encap:Boucle locale  
          inet adr:127.0.0.1  Masque:255.0.0.0
          adr inet6: ::1/128 Scope:Hôte
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          Packets reçus:312 erreurs:0 :0 overruns:0 frame:0
          TX packets:312 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 lg file transmission:0 
          Octets reçus:32926 (32.9 KB) Octets transmis:32926 (32.9 KB)

eth0      Link encap:Ethernet  HWaddr c8:60:00:e2:c9:2b  
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Packets reçus:4925 erreurs:0 :0 overruns:0 frame:0
          TX packets:1289 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 lg file transmission:1000 
          Octets reçus:679553 (679.5 KB) Octets transmis:331151 (331.1 KB)

On voit ici que c'est le bridge qui a une adresse IP. Ceci est important pour permettre le fonctionnement correcte de notre machine. Dans le cas contraire, on pourrait avoir des comportements bizarre de notre ami le serveur. Il faut bien voir que notre interface ethernet est simplement considéré comme un connecteur vers le monde réel.

Pour les plus curieux, il est possible de consulter l'état de notre bridge avec la commande brctl :

# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.7e68471136c9       no              eth0

Passons maintenant à la déclaration d'une interface virtuelle.

Déclaration d'une interface virtuelle et rattachement au bridge

Maintenant que notre bridge est fonctionnel, nous allons rattacher une interface virtuelle (tap0). Pour se faire, rien de plus simple, modifions de nouveau notre fichier /etc/network/interfaces de la manière suivante :

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual

auto tap0
iface tap0 inet manual
        pre-up tunctl -t tap0
        up ifconfig tap0 up
        down ifconfig tap0 down

auto br0
iface br0 inet dhcp
        bridge_ports eth0 tap0
        bridge_fd 9
        bridge_hello 2
        bridge_maxage 12
        bridge_stp off

Les lignes concernant tap0 contiennent l'utilisation de la commande tunctl qui va déclarer l'interface. Une fois déclarée, cette interface sera rattachée automatiquement au bridge à l'aide de la ligne bridge_ports.

Pour s'en convaincre, une fois que le réseau a été redémarré (restart networking), il suffit de relancer la commande brctl show br0. Ce dernier devrait renvoyer le résultat suivant :


# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.1c6f65217bc0       no              eth0
                                                        tap0

mercredi 13 mars 2013

Mécanisme de hook de SVN


Je sais, vous allez me dire que SVN est vieillot et que de toute façon, en bon geek qui se respecte, ça fait longtemps que vous êtes passé sous git.

Mais voilà, si vous n'êtes pas encore complètement convaincu que SVN n'est pas une solution si mauvaise que ça et que vous utilisez ça chez votre client/employeur, j'ai quelques astuces pour vous.

Tout d'abord, les hooks sont présent dans le répertoire hooks de votre repository. De base, votre repository SVN, à sa création, vient avec un template pour toutes les opérations de hooks possible sous SVN. Ça se présente sous la forme suivante :


ls *.tmpl
post-commit.tmpl
post-unlock.tmpl
pre-revprop-change.tmpl
post-lock.tmpl
pre-commit.tmpl
pre-unlock.tmpl
post-revprop-change.tmpl
pre-lock.tmpl
start-commit.tmpl

Comme vous pouvez le constater, toutes les opérations possible et imaginable sont disponible. Personnellement, j'ai eu l'occasion d'en mettre deux en oeuvre :

  • pre-revprop-change : lancé avant une modification sur une révision ;
  • post-commit : lancé au moment de la fin d'un commit.


Ces hooks vont servir à changer/régler le comportement de votre repository à l'aide de script. Pour les mettre en place, rien de plus simple :

  • Faîtes un script dans le langage qui vous amuse (même si j'aurais tendance à privilégier un script shell Unix tout simple) ;
  • Copier/lier ce script dans le répertoire du hooks en respectant le nom de l'opération à laquelle vous voulez le lier.

Exemple de hooks SVN : pre-revprop-change


Prenons le cas du pre-revprop-change. Ce script est lancé pour vérifier que l'opération de modification d'une révision de votre repository est bien autorisé. Je sais, vous aller me dire que ce type de demande vous parez étrange. Mais comme chacun sait, le client est roi et à coeur vaillant, rien d'impossible !

Dans le cas présent, nous allons justement restreindre cette opération à la modification du message de log de votre révision. Nous allons également interdire que cette modification puisse se faire par un autre utilisateur que celui à l'origine de la modification.

Sans plus attendre, voici donc le fameux script en charge de cette modification :

#!/bin/bash
REPOS="$1"
REV="$2"
USER="$3"
PROPNAME="$4"
ACTION="$5"

if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ] && \
   [ `svnlook author -r "$REV" "$REPOS"` = "$USER" ]; then
  exit 0
fi

echo "Changing revision properties other than svn:log is prohibited" >&2
exit 1

Le principe est simple :
  • On vérifie bien que nous n'allons modifier que le message de la révision (PROPNAME=svn:log) ;
  • L'action est une modification (ACTION=M) ;
  • Enfin, l'auteur de la modification est bien celui à l'origine du commit (svnlook author ... = $USER).
De là, si ces conditions sont remplies, on renvoie un exit 0 et SVN considère que l'opération est valide.

Dans les autres cas, nous renvoyons exit 1 et SVN refusera de lancer la modification.

Couplage avec Jenkins à l'aide d'un événement de post-commit

Prenons maintenant un autre cas : vous voulez coupler votre repository SVN avec un moteur d'intégration continue (type Jenkins) afin de lancer automatiquement vos constructions sans pour autant avoir à poller régulièrement votre repository SVN tout le temps. Ici, l'utilisation d'un évènement de post-commit fera parfaitement l'affaire et pourra lancer automatiquement votre job de construction.

Pour se faire, nous allons créer le script suivant que nous lierons ensuite dans le répertoire hooks avec comme nom post-commit (bien s'assurer également qu'il est exécutable) :

#!/bin/bash
log="/tmp/post_commit.log"
url_jenkins="http://127.0.0.1:8080/job/makeApp-generic/buildWithParameters?token=makeApp"

REPOS="$1"
TRANS="$2"

exec  > $log
exec 2> $log

repository=$(basename $REPOS)

# Définition des paths des différents binaires
for tag in $(svnlook changed -r $TRANS $REPOS | \
             sed 's/tags\//' | awk '{ print $2 }' | \
             sed 's/\/.*//g' | sort -u)
do
  if [ $tag = "trunk" ]; then tag=HEAD ; fi
  echo "Lancement de la construction de '$repository' (tag='$tag')."
  curl "$url_jenkins&application=$repository&tag=$tag" 2> /dev/null
done
NB : Il va sans dire qu'il faudra que votre serveur Jenkins soit en mesure d'accepter le job qui s'appelle makeApp-generic et surtout que vous ayez créé un token d'appel associé pour pouvoir le lancer avec un curl. Tient, je sens que je vais faire un article sur Jenkins dans peu de temps :).

En gros, le script va simplement regarder les répertoires des fichiers qui vont être modifié et, en fonction de ça, lancer une construction (avec les appels curl) auprès de Jenkins. Dans notre exemple, si la modification se fait sur le trunk, le tag est changé en HEAD.

Il ne nous reste plus maintenant qu'à faire une modification dans notre repository et vérifier que le build s'est bien passé en consultat la log /tmp/post_commit.log :

cat /tmp/post_commit.log
Lancement de la construction de 'test' (tag='HEAD').

Voilà, ça sera à peu près tout pour aujourd'hui. A bientôt pour de nouvelle aventure !

vendredi 8 mars 2013

Configuration de squidguard comme contrôle parental

Ayant de jeunes enfants à la maison, j'ai commencé à me poser la question de mettre en place un contrôle parental afin d'éviter d'amener mes enfants sur des pages que je n'aurais pas voulu qu'il voit (porno, jeux d'argent, violences etc.).

Bref, vous l'aurez compris, papa geek c'est posé la question de savoir qu'est ce qu'il pourrait bien mettre en oeuvre pour faire ce travail. J'ai rapidement trouvé une réponse au travers de l'outil squidguard. Nous allons donc voir ensemble comment rapidement le configurer afin de répondre à ce besoin.

Il va sans dire que papa geek utilise une distribution Linux (ici une Debian like) mais que ces instructions s'appliquent à n'importe quelle distribution Linux (voir à - j'ai du mal à le dire mais tant pis - à MacOS X - herk !).

Installation de squid et squidguard

La première phase est relativement rapide - pour peu que vous utilisiez une distribution Linux - et consiste à installer le package correspondant. Ceci se fait tout naturellement avec apt-get/aptitude/yum :

apt-get install squidguard

Il faut savoir qu'à ce moment, vous allez installer deux produits : squid et squidguard. Squid est un simple proxy HTTP mais qui a la particularité de pouvoir faire appel à des programmes externes pour procéder à des réécritures de contenu. Ici, le programme de réécriture externe est squidguard.

C'est très bien vous allez me dire mais squidguard vient sans aucune règle de configurer : le vilain ne filtre rien du tout ! Nous allons donc voir comment faire pour rajouter un filtrage dans squidguard avec les blacklists de l'université de Toulouse.

Configuration de squidguard

Récupération des blacklists

Rendons nous maintenant dans le répertoire /var/lib/squidguard/ et supprimons le répertoire db (en principe vide) :

rmdir /var/lib/squidguard/db

Récupérons maintenant une archive de la dernière version des blacklists :

cd /tmp/
wget http://dsi.ut-capitole.fr/blacklists/download/blacklists.tar.gz

Décompressons maintenant l'archive :

cd /var/lib/squidguard
tar xfv /tmp/blacklists.tar.gz

Renommons tout ça et attribuons les bons droits :

mv blacklist db
chown -R proxy:proxy /var/lib/squidguard/db

Il faut maintenant modifier le contenu du fichier /etc/squid3/squid.conf avec le contenu suivant :

url_rewrite_program /usr/bin/squidGuard -c /etc/squidguard/squidGuard.conf
url_rewrite_children 10

http_port 3128 transparent

Et faire suivre tout ceci d'un arrêt/relance :

/etc/init.d/squid3 restart

Voyons maintenant comment mettre en place les blacklists.

Mise en place des blacklists

Nous allons maintenant configurer notre squidguard afin qu'il prenne en compte les listes que nous venons de récupérer. Il faudra également choisir les listes que nous allons vouloir activer. Pour info, pour savoir à quoi correspond chacune des listes, il suffit d'ouvrir le fichier global_usage. Chaque catégorie y est présenté comme suit :


NAME: adult
DEFAULT_TYPE: black
SOURCE: http://squidguard.univ-tlse1.fr
DESC EN: Some adult site from erotic to hard pornography.
DESC FR: Des sites adultes allant de l'érotique à la pornographie dure.
NAME EN: Adult (X)
NAME FR: Adulte (X)
NAME IT: Siti per adulti (XXX)
NAME NL: 18+ (X)
NAME RU: Эротика
NAME DE: Porno


Charge à vous de sélectionner les catégories qui vous intéressent et de les ajouter sous cette forme dans le fichier /etc/squidguard/squidGuard.conf :

# Emplacement de la définition de la blacklist :

dbhome /var/lib/squidguard/db
logdir /var/log/squidguard

# Définition des différentes catégories
dest adult {
  domainlist adult/domains
  urllist adult/urls
}

dest sect {
  domainlist sect/domains
  urllist sect/urls
}

dest malware {
  domainlist malware/domains
  urllist malware/urls
}

dest remote-control {
  domainlist remote-control/domains
  urllist remote-control/urls
}

# Règle à appliquer en fonction des catégories définies ci-dessus
acl {
  default {
    pass !adult !sect !malware !remote-control all
    # Page de redirection. Changer là par ce que vous voulez
    redirect http://localhost/block.html
  }
}

Sauvegarder votre fichier et procéder maintenant à une mise à jour des bases de squidguard (soyez patient, c'est un peu long) :

update-squidguard

Attention ! Les espaces en début du fichier de configuration doivent être des tabulations ! Dans le cas  où vous auriez fait une bêtise dans votre fichier, le script se bloquera sans aucun message et sans activité CPU. N'hésitez pas à consulter le contenu du fichier /var/log/squidguard/squidGuard.log ou lancer la commande suivante pour obtenir des informations complétementaires :

squidGuard -d -b -P -C all

Reste maintenant à configurer votre navigateur afin de pointer sur le proxy.

Configuration du navigateur

Ici, rien d'extraordinaire : se rendre dans les paramètres de votre navigateur, dans les paramètres réseaux, rentrer l'adresse de votre proxy (ip : 127.0.0.1 et port : 3128) et c'est parti.

Mutualisation du proxy

Dans le cas où vous voudriez mutualiser votre proxy, il faudra pour cela accepter les connexions depuis votre réseau local. Tout ceci se fait en rajoutant les directives suivantes dans votre fichier /etc/squid3/squid.conf :

acl localnet src 192.168.0.0/16
http_access allow localnet

Reste maintenant à relancer squid pour prendre en compte la modification (/etc/init.d/squid3 restart). Il faudra également renseigner l'adresse IP de la machine qui vous servira de proxy dans les différents navigateurs de vos différentes machines clientes.

A noter que si vous utilisez un serveur DHCP, il est possible de préciser l'adresse de votre proxy. La configuration se fera alors automatiquement.

Je n'ai donc plus qu'à vous souhaiter un bon surf sans trop de saleté pour vos gamins !

jeudi 31 janvier 2013

Utilisation de webdav en ligne de commande

Depuis quelques temps, j'ai comme projet de faire un serveur de publication. Ce dernier doit héberger des sources et autres RPM mais malheureusement, il n'est pas accessible en SSH et nous devrons passer par du WebDAV (en https).

Voici donc en quelques lignes comment le mettre en oeuvre sur un serveur apache sous RedHat Enterprise/Centos 6.

Configuration du serveur apache

Premier point, nous allons créer un nouveau point webdav pour notre serveur. Pour se faire, rien de bien compliquer, il faut créer un fichier /etc/httpd/conf.d/test-webdav.conf avec le contenu suivant :
Alias /test-webdav /var/www/webdav

<Directory "/var/www/webdav">
  Dav On
  Options Indexes
  AllowOverride None
  Order allow,deny
  Allow from all
</Directory>
Bien penser à alimenter notre fichier de mot de passe (/mon/fichier/htpasswd) à l'aide de l'outil htpasswd. Par la suite, nous utiliserons un utilisateur webdav_access avec xxx comme mot de passe.

Créons maintenant notre répertoire et attribuons les droits à l'utilisateur apache (ou www-data dans le cas d'une debian) :
mkdir /var/www/webdav
chown apache:apache /var/www/webdav
Un arrêt relance de notre serveur apache et tout est prêt pour la suite. Pour s'assurer que nous n'avons rien oublier, nous pouvons essayer d'y accéder à l'aide de curl :
curl -u webdav_access:xxx http://localhost/test-webdav/

Voyons maintenant la suite du programme


Maintenant que notre nouveau contexte fonctionne, nous allons essayer d'uploader un fichier à l'aide de curl. Pour se faire, il faut utiliser l'option -T suivi du fichier à uploader. Ci-dessous un exemple :
curl -u webdav_access:xxx -T welcome.html \
     http://localhost/test-webdav/
Le serveur devrait vous renvoyer une réponse en HTML vous indiquant la réussite de l'opération sous la forme du message suivant :
Resource /test-webdav/welcome.html has been created.
C'est bien beau mais on voudrait également gérer des sous répertoires. Il faut dans ce cas utiliser l'option -X MKCOL. Ci-dessous un exemple :
curl -u webdav_access:xxx -X MKCOL \
     http://localhost/test-webdav/new_dir
Le message suivant devrait vous indiquer que ça s'est bien passé :
Collection /test-webdav/new_dir has been created.
Reste ensuite à rajouter un fichier dans ce répertoire :
curl -u webdav_access:xxx -T welcome.html \
     http://localhost/test-webdav/new_dir/

Utilisation en point de montage

Nous avons vu les possibilités de notre serveur. Sachez qu'il est également possible de monter un serveur webdav sur un serveur Linux. Ci-dessous un exemple de montage de notre point de partage :
mount -t davfs http://localhost/test-webdav/ /mnt
Please enter the username to authenticate with server
http://localhost/test-webdav/ or hit enter for none.
  Username:webdav_access
Please enter the password to authenticate user  with server
http://localhost/test-webdav/ or hit enter for none.
  Password:xxx
Rendons nous maintenant sur le point de montage /mnt et faisons quelques tests.
  • Lister le contenu du répertoire :
# cd /mnt/
# ls
lost+found  new_dir  test_webdav.txt  un  welcome.html
  • Supprimer un répertoire :
rmdir new_dir
  • Copier un fichier :
cp /etc/hosts /mnt/
Bref, vous l'aurez compris, tout ceci se comporte comme un FS normal.