Un peu de webscrapping ?
Posted by JB on 17/06/08 at 23:10
Le webscraping est défini sur la page française de Wikipedia comme suit :
Le Web scraping (parfois appelé Harvesting) décrit généralement en informatique un moyen d’extraire du contenu d’un site internet, via un script ou un programme, dans le but de le transformer ou de changer son format pour permettre son utilisation dans un autre contexte.
J’en faisais régulièrement avant en mIRC scripting, rencontrant souvent des problèmes plutôt http que parsing : suivi des sessions, chunks, etc… Et puis j’étais à un séminaire ces derniers jours, et des collègues m’ont remotivé pour en faire, alors je commence quelques essais en Ruby.
Let’s go !
Installons scRUBYt!, un package qui vient par dessus Hpricot notamment (parser HTML). Les instructions officielles n’étant pas très concluantes, je me suis rabattu sur ce post qui a résolu tous mes soucis :-) Il faudra d’ailleurs que j’examine un de ces jours les avantages de Scrubyt par rapport à Hpricot seul, vues les difficultés d’installation, raisonnables mais un peu aggaçantes (et qui ne feront que s’ajouter aux futures difficultés lors d’installations sur d’autres distribs ou au boulot).
# gem install —version 1.7.1 ParseTree # gem install —version 3.6.3 RubyInline # gem install —version 1.1.6 ruby2ruby # gem install ParseTreeReloaded # gem install RubyInlineAccelleration # gem install scrubyt
Parfois il faut relancer le gem install une ou deux fois, mais ça finit par passer normalement.
Ensuite, premier essai (tiré d’ici) :
require 'rubygems' require 'scrubyt' google_data = Scrubyt::Extractor.define do fetch 'http://www.google.com/ncr' fill_textfield 'q', 'ruby' submit link "Ruby Programming Language/@href" next_page "Next", :limit => 2 end puts google_data.to_xml
# ruby test_scrubyt.rb
/usr/local/lib/site_ruby/1.8/rubygems.rb:139:in `activate': can't activate RubyInline (= 3.6.3), already activated RubyInline-3.7.0] (Gem::Exception)
from /usr/local/lib/site_ruby/1.8/rubygems.rb:155:in `activate'
from /usr/local/lib/site_ruby/1.8/rubygems.rb:154:in `each'
from /usr/local/lib/site_ruby/1.8/rubygems.rb:154:in `activate'
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from test_scrubyt.rb:2
Oopsie !
J’ai donc désinstallé la version 3.7.0 via le choix 2 dans la commande :
# gem uninstall RubyInline
Et là hop !
# ruby test_scrubyt.rb /usr/lib/ruby/gems/1.8/gems/scrubyt-0.3.4/lib/scrubyt/core/scraping/filters/text_filter.rb:25: warning: don't put space before argument parentheses http://www.google.com/search?hl=en&ie=ISO-8859-1&q=ruby http://www.google.com/search?hl=en&ie=UTF-8&q=ruby&start=10&sa=N <root> <link>http://www.ruby-lang.org/</link> <link>http://www.ruby-lang.org/en/20020101.html</link> <link>http://en.wikipedia.org/wiki/Ruby_programming_language</link> <link>http://en.wikipedia.org/wiki/Ruby</link> <link>http://www.rubyonrails.org/</link> <link>http://www.rubys.com/</link> <link>http://www.rubycentral.org/</link> <link>http://www.w3.org/TR/ruby/</link> <link>http://www.zenspider.com/Languages/Ruby/QuickRef.html</link> </root>
Excellent début !
Après un petit patch de /usr/lib/ruby/gems/1.8/gems/scrubyt-0.3.4/lib/scrubyt/core/scraping/filters/text_filter.rb:25 (tu parles d’un patch, j’ai juste supprimé un espace… :D), je compte bien mener d’autres essais, notamment ce dont j’ai parlé dans le résumé :-) Je mettrai les résultats ici !
Quote of the day (2)
Posted by JB on 17/09/08 at 11:41
Je cède à la tentation de transmettre moi-aussi cette citation (via Tristan) :
< niluje> windows est payant, pas linux, ça prouve bien que windows est mieux.
< Clex> Ben niluje, quitte ta femme et va aux putes.
Imaginons qu’on veuille ajouter 10000 jours au 26/06/2008. Date.new(2008,6,26) permet de créer un premier objet date. La méthode “+” permet ensuite d’ajouter des jours, et pour info “>>” d’ajouter des mois. Modulo un require “Date” au début, on a tout ce qu’il faut ! Il faut juste penser à faire un “to_s” à la fin pour sortir une chaine de caractères, sauf si on utilise “puts” qui l’appelle tout seul…
Au final, même pas besoin de faire un script, une oneliner suffit :
root@vds# ruby -e ‘require “Date”; puts Date.new(2008,6,26) + 10000’ 2035-11-12
Même genre de solution pour trouver un écart de dates, ou bien sûr de nombres :
root@vds# ruby -e ‘require “Date”; puts Date.new(2008,9,19) – Date.new(2008,6,26)’ 85 root@vds# ruby -e ‘puts 10000 – 85’ 9915
Dans 10000 jours depuis le 26/06, c’est à dire 9915 jours à compter d’aujourd’hui, nous serons le 12 novembre 2035 ! Merci Ruby :-)
Spam is evil
Posted by JB on 08/10/08 at 06:31
Heureusement que j’ai des heures de boulot pour m’occuper de mon blog et de ma culture personnelle.
Je commence à avoir de plus en plus de spams, j’ai donc naturellement cherché un antispam pour Mephisto. J’ai trouvé une sorte d’inverse captcha ici, l’installation est détaillée ici.
Le principe est vraiment excellent et certainement infaillible pour des sites confidentiels (au sens “trop peu fréquentés pour que les spammers s’y intéressent de près”) : la plupart des sites vous obligent à entrer une suite de caractères tirés d’une image qu’un robot ne saurait pas lire. Pour un “captcha inversé” le principe est diamétralement opposé : il y a un champ (mail par exemple) qui sert de piège aux robots, et que les humains ne doivent pas remplir : au pire un message les informe, au mieux c’est caché via du Javascript ou du CSS. Si ce champ est rempli le commentaire n’est pas validé.
J’avais oublié de publier cet article : ce système tourne sur ce blog depuis mi-septembre, et plus un seul spam depuis. Yeah ;-)
Ubuntu Intrepid Ibex
Posted by JB on 11/11/08 at 23:15
J’ai passé mon PC principal ce week-end sous Ubuntu 8.10, nom de code “Intrepid ibex” (bouquetin intrépide). Après une très désagréable expérience au premier boot, où le bip machine sonnait sans discontinuer, j’ai updaté et plus aucun problème au boot suivant. Pour les possesseurs de cartes nvidia je conseille aussi d’installer les paquets non libres si vous voulez que l’écran cesse de trembler !
Bon, j’ai surtout mis activé et configuré un peu Compiz et il faut avouer que… ça rox. Compiz permet d’avoir des effets graphiques du tonnerre sur son Linux, un peu à la manière d’Aero sous Vista, mais en bien mieux évidemment. C’est très sympa même si on peut s’en lasser assez vite je pense. Démo sur demande quand vous serez de passage chez moi ;-)
J’ai aussi installé Songbird 0.7 (fantastique), Kvirc 3.4.0 (qui remplace fièrement mon mIRC), Netbeans 6.5 (toujours aussi sympa), Scribes (pour tester, il manque une vue “dossiers” à mon sens), et toutes mes extensions Firefox, dont je reparlerai un autre jour, ou pas. Ah, j’ai aussi codé un tout petit peu sur un plugin Redmine, une killer app sous Rails, et regardé un peu ce que donnent le trunk de Typo (un gestionnaire de blog en rails) et Bort (une coquille vide pour démarrer un projet Rails).
Et au milieu de tout ça, j’ai cuisiné, ri, dormi, vibré à l’heure de ma bien aimée, héhé ! Week-end rempli ;-)Configuration de Redmine pour Github
Posted by JB on 12/01/09 at 18:51
L’info est déjà disponible au fond d’une page du wiki Redmine, ici. Je vais faire exactement pareil, parce que c’est bien. Et comme j’ai envie de faire un article technique, je mets ça ici.
Voilà donc en très bref la config que j’ai utilisée pour linker mon Redmine (prochainement en ligne, dès que les bons DNS seront propagés) à mon dépôt github pour Simplelog (rien mis encore dessus, seulement la release officielle).
$ sudo mkdir -p /var/redmine/git_repositories
$ sudo chown rails:rails /var/redmine/git_repositories
$ cd /var/redmine/git_repositories
$ git clone —bare git://github.com/jbbarth/simplelog.git
$ crontab -e
#git repo for simplelog
*/15 * * * * git-pull /var/redmine/git_repositories/simplelog/ 2>&1 | grep -vE "^From|FETCH_HEAD|^Already up-to-date"
Troll du matin...
Posted by JB on 16/01/09 at 10:08
…chagrin. Mais quand même.
2 jours qu’un collègue essaye d’installer OCSInventory sur un serveur Red Hat Enterprise 5. Ce matin, je me connecte à mon poste de test sous Ubuntu 8.10 :
$ sudo apt-get install ocsinventory-server
10 minutes plus tard (le temps du téléchargement et de me souvenir de mon mot de passe MySQL quoi), OCS était installé. Il me demande un mot de passe à la connexion, que je ne connais pas… Oups. Je fouille 2 secondes dans les confs Apache, je trouve le fichier qui va bien…
$ sudo htpasswd -b /etc/ocsinventory/htpasswd.setup admin admin
Et ça marche. 15 minutes VS 2 jours.
Debian/Ubuntu 1 – 0 RedHat.
Là où je bosse, on a la chance (?) de disposer d’un SAN, c’est-à-dire d’un réseau dédié au stockage. En l’occurence c’est un réseau fibre, et tous les flux passent par deux switches fibre McData Sphereon 4500… qu’il faut surveiller d’une manière ou d’une autre.
En l’occurrence on surveille tout ça par Nagios. L’ancien script (qui doit faire partie des nagios plugins du site officiel ?) vérifiait les interfaces une par une, ce qui est gênant dans un environnement évolutif (oubli d’interfaces non surveillées!). Il faisait d’autres choses (check trafic rx/tx, errors) que mon script ne fait pas, mais il ne demande qu’à être amélioré ;-)
Voici donc un script de remplacement qui check toutes les interfaces d’un coup. Gros avantage : on passe les ports non branchés en exception, mais si un port est vu “up” et qu’il est en exception le script sort en Critical. Cela force à maintenir la liste des exceptions à jour ;-)
PS: Il faut bien sûr que ruby soit installé sur votre serveur de supervision.
#!/usr/bin/ruby # Dernière modif: 19/11/2008 # Script de test des ports pour les switches fibre # Jean-Baptiste BARTH <jeanbaptiste.barth@gmail.com> # Remonter les infos à la main (sous l'user "nagios") # $ snmpwalk -c public -v 2c switch_san_a .1.3.6.1.4.1.289.2.1.1.2.3.1.1.2 # SNMPv2-SMI::enterprises.289.2.1.1.2.3.1.1.2.1 = INTEGER: 2 # SNMPv2-SMI::enterprises.289.2.1.1.2.3.1.1.2.2 = INTEGER: 2 # ... # => 2 = OK, 6 = down, 13 = info not available unless ARGV.length >= 2 && ARGV.length <= 3 puts "Mauvais format :" puts "\t./check_fc_setra.rb HOST COMMUNITY [EXCLUSIONS]" puts "Les ports exclus évitent des remontées d'alertes pour les ports non branchés." puts "Exemple: ./check_fc_setra.rb switch_san_a public 1,4,9" exit 2 end # Valeurs prises dans utils.sh STATE_OK=0 STATE_WARNING=1 STATE_CRITICAL=2 STATE_UNKNOWN=3 STATE_DEPENDENT=4 # Parsing arguments host = ARGV.shift community = ARGV.shift exclusions = (ARGV.shift || "none").split(",") # Passage de la commande command = `snmpwalk -c #{community} -v 2c #{host} .1.3.6.1.4.1.289.2.1.1.2.3.1.1.2` result = [] command.each do |line| #puts "DEBUG snmpwalk: "+line matches = line.match /\.(\d+) = INTEGER: (\d+)/ result.push [matches[1], matches[2]] end # Traitement de la sortie not_ignored = result.select{|x| !exclusions.include? x[0]} interfaces_down = not_ignored.select{|v| v[1] == "6"}.map{|x| x[0]} interfaces_ok = not_ignored.select{|v| v[1] == "2"}.map{|x| x[0]} interfaces_unknown = not_ignored.map{|x| x[0]} - interfaces_ok - interfaces_down interfaces_ok_not_normal = (result - not_ignored).select{|v| v[1] == "2"}.map{|x| x[0]} # Output puts "Link DOWN on interfaces : "+interfaces_down.join(",") unless interfaces_down.empty? puts "Link UP on IGNORED interfaces : "+interfaces_ok_not_normal.join(",")+"\n!!!CHANGE THE SERVICE CONFIG!!!" unless interfaces_ok_not_normal.empty? puts "State UNKNOWN : "+interfaces_unknown.join(",") unless interfaces_unknown.empty? puts "Link UP on interfaces : "+interfaces_ok.join(",") unless interfaces_ok.empty? puts "Ignored: "+exclusions.join(",") if !interfaces_down.empty? || !interfaces_ok_not_normal.empty? exit STATE_CRITICAL elsif !interfaces_unknown.empty? exit STATE_UNKNOWN else exit STATE_OK end
Des images dans Simplelog
Posted by JB on 02/02/09 at 12:45
Ma version de Simplelog, disponible sur mon espace Github, supporte désormais l’upload d’images, utilisables ensuite dans les posts ou pages de son choix :

Pour que le tout fonctionne, il faut disposer sur son serveur d’une bibliothèque de traitement d’image pour Ruby. Personnellement j’ai choisi ImageScience pour sa simplicité, mais je viens de me rendre compte qu’il y avait des bugs sur les images PNG. Je vais voir si je peux passer à autre chose pour la suite.
To be continued ;-)
EDIT: je suis passé à RMagick, tout a l’air de marcher pas mal. D’ailleurs pour ma version de Simplelog, c’est mis comme processeur par défaut (pour le moment en dur dans la classe, qui sait peut-être bientôt en configurable) :
class Image < ActiveRecord::Base has_attachment :content_type => :image, :storage => :file_system, :max_size => 5.megabytes, :resize_to => '740x400>', :thumbnails => { :thumb => '100x100>' }, :path_prefix => 'public/assets', :processor => 'Rmagick' validates_as_attachment end
Je reprends le titre de cet article, paru sur le blog du rédacteur en chef de Linux Mag’. Même remarque : soit vous comprenez directement le titre, soit cet article n’est même pas fait pour vous. Quoiqu’il en soit, je vais finalement installer ça au boulot lundi ; seul petite angoisse dans les tuyaux, il semble que le support des cartes Broadcom Netextreme II ne soit pas présent d’origine, ce qui va me lourder quelque peu, mais c’est la vie.
Bonne Saint Valentin et longue vie à Lenny !
Lenteurs DNS Livebox
Posted by JB on 22/03/09 at 12:26
Sous mon PC principal (Ubuntu/wrath), les résolutions DNS sont assez lentes. J’ai trouvé des solutions ici, immédiatement mises en oeuvre :
# echo "supersede domain-name-servers 80.10.246.2, 80.10.246.129;" >> /etc/dhcp3/dhclient.conf # /etc/init.d/networking restart #ou un reboot pour être sûr..
Upgrade Intrepid->Jaunty
Posted by JB on 22/03/09 at 12:29
J’ai upgradé hier ma Ubuntu Intrepid vers une Jaunty, qui commence à être suffisamment bien supportée ; au passage, j’avais tenté de faire ça il y a deux mois, et le support des pilotes Nvidia était lamentable, je n’avais aucun affichage correct, j’étais donc revenu sous Intrepid.
sudo vi /etc/apt/sources.list #puis :%s/intrepid/jaunty/g, et :wq! wajig update && wajig dist-upgrade
A peine une demie-heure plus tard tout marchait impec’ ;-)
Seul bémol, Jaunty supporte ext4 et ma partition racine n’était pas passée en ext4 toute seule (on s’en serait doutés).
J’ai inauguré un petit truc bien sympa, le boot depuis une clé USB live (en lenny, comme ça je m’en resservirai au boulot) :
sudo -s mkdir /tmp/usbkey && cd /tmp/usbkey apt-get install live-helper lh_config -d lenny -b usb-hdd -p xfce-desktop —packages wajig screen ruby lh_build #patienter quelques minutes umount /dev/sdf1 dd if=binary.img of=/dev/sdf bs=1M
Et reboot sur la clé usb ! Tout marche au poil, sauf que le clavier est en Qwerty :
dpkg-reconfigure console-data
Là commence le passage en ext4 ; mes partitions à migrer étaient /dev/sda2, 5 et 6, mais ça ne s’invente pas : fiez vous au /etc/fstab et au besoin, montez temporairement chaque disque sur /mnt. Mon “/” étant sur /dev/sda2
mount /dev/sda2 /mnt vi /mnt/etc/fstab #(remplacement de ext3 par ext4 sur les partitions à migrer)
Et l’opération qui suit est donc à répéter pour chacune de vos partitions :
tune2fs -O extents,uninit_bg,dir_index /dev/sda2 fsck.ext4 -pf /dev/sda2
Un reboot plus tard, everything is ok ;-)
Passage à xfce
Posted by JB on 09/05/09 at 20:10
Envie de changement sur mon NC10, je suis donc passé à XFCE, plus léger que GNOME, et, maintenant que je l’ai sous les yeux, aussi plus joli :-)
J’avais plusieurs problèmes à première vue :
- dans un terminal xfce, screen ne voyait plus la touche “retour arrière” ; après un peu de recherches, j’ai trouvé cet article, et ça remarche.
- les touches Fn liées au son ne fonctionnent pas ; via la page d’aide de la communauté, je suis tombé sur cet article, et en particulier sur le script Python fait par son auteur. La commande proposée amixer—sset Master 100% fonctionne bien, reste que j’aimais bien la petite notification en transparence. Bref, je ne vais pas reprendre tout le boulot du monsieur vu que pour mon utilisation, tout fonctionne à part ça ; d’autant que c’est un peu lourd et non packagé. J’essayerai d’éditer ce post dès que je trouve la soluce pour rétablir l’ancien comportement sous Gnome :-)
EDIT: bon bah, les fn keys pour le son fonctionnent. Ca m’énerve un peu parce que je ne sais pas ce que j’ai fait pour, mais je profite ; xfce est un pur bonheur!
Synchronisation git pour Redmine
Posted by JB on 23/05/09 at 11:42
J’avais évoqué ici la synchronisation de dépôts Git (en l’occurrence Github mais ça n’a pas d’importance).
Mais voilà, ça ne fonctionnait plus tout à fait après migration de serveur, et ce n’était pas très clair pour moi honnêtement. Alors j’ai de nouveau regardé sur le wiki de Redmine et trouvé cet article qui décrit les choses très bien.
Seule différence, j’utilise les branches sous Git, et ce mode ne synchronise que la branche principale (“master”, ce que l’on appellerait le “trunk” sous subversion).
Initialisation de mon dépôt:
cd /var/redmine/git_repositories/ git clone —bare git@github.com:jbbarth/project.git project cd project git remote add origin git@github.com:jbbarth/project.git git fetch -v
Ajout de ceci en CRON:
#sync of my github repos for redmine */10 * * * * /var/redmine/git_repositories/sync_repositories.sh >/dev/null
Et le petit script qui va bien:
#!/bin/sh
base=$(dirname $0)
[ "$base" == "." ] && base=$(pwd)
cd $base
for repo in $(ls -F |fgrep "/"); do
cd $base/$repo
git fetch origin
for branch in $(ls refs/remotes/origin/); do
git reset —soft refs/remotes/origin/$branch
done
doneYoupi!
Need a wiki ?
Posted by JB on 24/05/09 at 08:57
En ce moment j’ai trop d’articles techniques à publier, souvent trop en bazar, ou trop long pour être publiés dans une demi-colone de ce blog. De plus je risque de quitter mon boulot dans quelques mois, et tout ce que j’ai pû documenter là-bas sera perdu pour moi si je ne le récupère pas avant. Bref, j’ai besoin d’un wiki, simple d’utilisation, avec suivi des révisions, formatage en Textile, un peu comme celui de Remine.
Une contrainte supplémentaire, qu’il soit en Ruby on Rails, éventuellement Merb. Pas par idéologie, croyance en REST, ou quelconque connerie de ce genre (et certains en tiennent une couche à ce niveau quand on voit la liste rails-france), mais plutôt parce que j’en ai marre de maintenir 50 technos hétérogènes sur mon serveur. Mon blog, mon gestionnaire de projets tournent déjà en Rails. Ce sera bientôt le cas du site chanmasters.com que je réécris en ce moment. Bientôt le cas également de ma gallerie de photos, qui tourne déjà avec des scripts ruby mais pas administrable en mode web. Donc dommage pour Dokuwiki qui a priori me convenait parfaitement…
J’ai essayé Instiki sans être réellement convaincu, je ne saurais pas bien expliquer pourquoi. Et puis, j’aurais des modifs à faire dessus pour qu’il me convienne (templates trop épurées à mon goût, affichage “geeky” de certains champs, etc…). Ce qui implique un petit peu d’exploration du code, cf la suite. Je n’ai pas trouvé d’autres projets très actifs en Rails et qui me convienne (liste ici)…
En fait, le wiki de Redmine me convient parfaitement. Facile à “hacker” (je commence à connaître un peu le code même si je suis loin d’être un gourou comme les 3 ou 4 grands contributeurs réguliers), maintenu, communauté active, support de textile entre autres, jolis diff, etc. Nickel, à 4 petites choses près :
- le support Textile est un peu foireux parfois ; voir ici
- la coloration syntaxique est hideuse, j’aimerais bien remplacer CodeRay par autre chose ; voir ici
- j’aimerais bien que les hiérarchies soient faites automatiquement, quitte à rendre l’arborescence un peu profonde, pas grave ; voir ici
- j’aimerais bien un système de tags avec un nuage sur le côté ; voir ici, ici et ici
Bref, ça sent bon, et le choix est tout fait ; je documenterai dans le prochain article l’installation et la configuration de Redmine pour me servir de wiki :-)
Redmine as a wiki engine
Posted by JB on 24/05/09 at 10:27
Ce post fait suite à celui-ci.
Tout d’abord, on installe Redmine classiquement ; je passe volontairement les aspects DNS (création d’un sous-domaine, en l’occurence wiki.jbbarth.com), Apache (création du vhost), et “système” (script de démarrage de Mongrel, user et port adéquats, ce genre de choses) :
cd /home/app/jbbarth/ svn co http://redmine.rubyforge.org/svn/trunk _redmine-0.8-wiki ln -s _redmine-0.8-wiki wiki cd wiki/ rake db:migrate rake redmine:load_default_data rake config/initializers/session_store.rb
Après démarrage, on procède à une configuration basique de Redmine :
- modification du user/pass admin
- configuration générale dans Administration > Settings
- création d’un projet public “wiki”, identifiant “wiki” ; tous les trackers décochés, et tous les modules sauf le module “wiki”
- dans ce projet, on configurera la “Start page”, et surtout on la créera/remplira (sous peine d’avoir des erreurs 404 dans la suite)
Là commencent les choses “sérieuses”. Que voulons-nous ?
1) que l’accueil de Redmine se fasse sur la page de démarrage du wiki du projet “wiki”
Pour cela, nous allons éditer config/routes.rb, et remplacer l’accueil défini à la ligne “map.home” par :
#map.home '', :controller => 'welcome' map.home '', :controller => 'wiki', :id => 'wiki'
Après redémarrage de l’instance, ça fonctionne !
2) suppression des liens inutiles pour un wiki ; en particulier la première tab “Overview/Aperçu”, et “Projects/Projets”, “My page/Ma page” et “Help/Aide” dans le menu en haut à gauche (nous n’aurons qu’un seul projet “wiki”)
Pour cela nous allons créer un thème à nous et cacher ces liens via du CSS, ce qui me parait bien suffisant : ils ne représentent aucun “danger”, c’est juste qu’ils perturbent la navigation dans le cadre d’une utilisation wiki-only. Voir donc ici pour la création d’un nouveau thème, et éventuellement ici pour des exemples de thèmes.
Nous créons donc un thème “wiki”, puis quelques lignes suffisent à la fin de public/themes/wiki/stylesheets/application.css :
/* Specific to wiki */
#top-menu .my-page, #top-menu .projects, #top-menu .help { display:none; }
#main-menu .overview { display:none; }3) passage des patches cités dans l’article précédent
cd /home/app/jbbarth/wiki/ mkdir patches
a) passage de CodeRay à UltraViolet :
wget -P patches http://www.redmine.org/attachments/download/1698/syntax_highlighting.diff patch -p0 < patches/syntax_highlighting.diff wget -P patches http://www.redmine.org/attachments/download/1699/redcloth.diff patch -p0 < patches/redcloth.diff wget -P patches http://www.redmine.org/attachments/1700/ultraviolet_highlighter.zip cd patches/ unzip ultraviolet_highlighter.zip cat ultraviolet_highlighter/README.txt apt-get install libonig-dev gem install ultraviolet cp -a ultraviolet_highlighter ../vendor/plugins/ cd ..
Les traductions ne sont pas bien passées, donc on édite à la main config/locales/en.yml et fr.yml, et on supprime les fichiers “.rej” correspondants.
b) pages parent automatiques :
wget -P patches http://www.redmine.org/attachments/download/2082/3108_automatic_parent_with_tests.diff patch -p0 < patches/3108_automatic_parent_with_tests.diff
c) correction d’un petit bug de Redcloth :
wget -P patches http://www.redmine.org/attachments/download/1728/redcloth_arobas.diff patch -p0 < patches/redcloth_arobas.diff
d) système de tagging :
Il y avait un patch proposé ici, mais il ne correspond pas vraiment à ce que je veux. Voici quand même une méthode pour l’appliquer sur une copie de travail SVN :
wget -P patches http://www.redmine.org/attachments/download/2060/wiki_page_categories_20090520.patch sed -i -e 's#- redmine.orig/#- #g' -e 's#\+ redmine/#+ #g' -e 's#diff.*\.orig/\([^ ]*\).*#Index \1\n===============================================#g' patches/wiki_page_categories_20090520.patch patch -p0 < patches/wiki_page_categories_20090520.patch rake db:migrate
Après toutes ces modifs, on se rend compte que certains patches ne sont pas bien passés :
find . -iname "*.rej"
Normalement avec cet ordre de passage des patches, il n’y a que lib/redcloth3.rb dont on résoud les conflits à la main.
Voilà, hormis le système de tagging on a un wiki fonctionnel. Je ferai un nouveau post si je trouve quelque chose pour le support des tags. Il ne reste plus qu’à le remplir maintenant !
EDIT
- pour que l’activité du projet prenne en compte les changements du wiki par défaut : éditer lib/redmine.rb, et modifier autour de la ligne 155/156:
- activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false + activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => true
- la même option permet que les recherches prennent en compte les entrées du wiki sur le projet courant
- pour cacher la liste déroulante de sélection des projets dans la recherche : édition de public/themes/wiki/stylesheets/application.css, ajout de :
select#scope { display:none; }EDIT2
J’ai changé l’ordre de passage des patches pour avoir le moins de choses possibles à résoudre à la main.
D comme Détente, et comme Desktop
Posted by JB on 29/05/09 at 19:24
Ce soir je m’ennuie seul à la maison, alors j’ai décidé de prendre soin de mon PC principal :
- j’ai installé conky, après l’avoir vu dans cet article ; j’ai le même .conkyrc que le monsieur à une vache près, et c’est vrai que ça rend pas mal =) Réservé à mon PC principal, car autant ça rentre bien sur un 22", autant sur un NC 10 et son écran de 10" ça ne va pas le faire. J’ai bien sûr pushé mon .conkyrc sur mon espace github héhé^^
- je me suis posé des questions sur mes sauvegardes ; en particulier je me demande si utiliser un service type Dropbox est intéressant (cf un article que j’ai croisé récemment ici)
- j’ai hésité à passer en karmic ; le seul truc dont j’ai peur, comme d’habitude, c’est le support des pilotes Nvidia. En cours de réflexion…
- … hey ! mais j’ai un serveur à sécuriser moi !
F comme F*cking Firefox
Posted by JB on 01/06/09 at 21:41
Depuis que j’ai mon NC10, ça doit donc faire deux mois, je cherche comment faire pour que mes bookmarks ne passent pas à la trappe à chaque resizing de Firefox. Ou aléatoirement d’ailleurs. Parce que parfois ce renard imbécile étend la barre d’url on ne sait pourquoi, et réduit les dossiers personnels à une misérable double flèche, les rendant beaucoup moins accessibles.
En gros, je voulais que ça arrête de faire ça :
Mais que ça fasse ça (et tout le temps !) :
Après avoir essayé pas mal de trucs sans succès, j’ai trouvé l’inspiration ici ; et voici donc mon UserChrome.css qui fonctionne :
#bookmarksBarContent .bookmark-item { min-width: 70px !important; visibility: visible !important; }
Alors ça ça ronfle comme titre ! Un SAN c’est super, c’est efficace, performant, tu peux étendre tes disques à chaud, gérer ton RAID au clic, faire de la haute dispo, te la raconter à la cafét’, bref c’est merveilleux. LVM aussi, c’est super : ça apporte pas mal de souplesse dans un environnement mouvant, et quand on fait de l’informatique professionnelle, c’est bien souvent le cas.
En gros, voici le topo : on a un volume logique (que certains appelleront abusivement “un(e) LUN”) ld_disk, mappé à un serveur server. Côté serveur, ce disque s’appellera directement (par comodité) ld_disk, donc via multipathd son nom sera /dev/mpath/ld_appli. Derrière on a monté directement l’artillerie LVM, sans partitionner (ce qui aurait été plus souple/facile/intelligent) : ce disque a été déclaré comme volume physique (PV), on a fait dessus un groupe de volumes (VG) vg_appli, sur lequel on a bêtement fait un seul volume logique (LV) sobrement appelé lv_appli. Ce volume fait initialement 300Go. Les besoins changent, et on vous demande de passer le tout à 500Go. L’OS est une RHEL 5, mais ça n’a pas d’importance a priori. Bon, on commence logiquement par étendre le disque logique côté SAN. Et on espère qu’on va pouvoir prendre en compte l’extension au niveau système sans perdre de données.
Mais comme trop de choses en ce bas monde, il est difficile de trouver des infos récentes sur le web. 99% des liens trouvés via Google vont dire que c’est impossible, ou que LVM ne le permet pas encore, qu’on n’a qu’à formatter ou recopier sur un autre disque. Quelques posts assez anciens (2004?) sur des forums dont j’ai perdu la référence hélas vont expliquer qu’il faut d’abord étendre la partition via fdisk. Seulement moi, je n’ai pas de partition, aïe.
Voici donc la marche à suivre :
# on cherche et on note le(s) chemin(s) vers notre disque au sens SCSI (exemple: 3:0:0:0 et 4:0:0:0) multipath -ll # on met le volume offline vgchange -a n vg_appli # on rescanne le périphérique au niveau SCSI echo "1" > /sys/class/scsi_device/3\:0\:0\:0/device/rescan echo "1" > /sys/class/scsi_device/4\:0\:0\:0/device/rescan # on relance la découverte coté multipathd multipath -F multipath -v2 # puis on étend au niveau de LVM ; exemple : pvscan #=> PV /dev/mpath/ld_appli VG vg_appli lvm2 [300,00 GB / 0 free] pvresize /dev/mpath/ld_appli pvscan #=> PV /dev/mpath/ld_appli VG vg_appli lvm2 [500,00 GB / 200,00 GB free] # on réactive le VG vgchange -a y vg_appli # et on étend le LV via la taille : lvextend -L +200G /dev/vg_appli/lv_appli #ou via le nombre d'extents : lvextend -l +123456 /dev/vg_appli/lv_appli # il reste à faire l'extension au niveau EXT3 (attention, ces deux étapes sont très longues) e2fsck -f /dev/vg_appli/lv_appli resize2fs /dev/vg_appli/lv_appli
Hope this helps!
Connaître sa RAM
Posted by JB on 20/06/09 at 22:08
J’apprendrai la prochaine fois à tourner 7 fois ma langue dans ma bouche avant de dire une bêtise ; non, le nombre de /dev/ram* ce n’est pas le nombre de barettes de RAM sur un Linux. Pour connaitre ce genre d’info, lshw ou dmidecode sont plus adaptés. En reformattant la sortie avec ruby, on obtient quelque chose de ce genre :
sudo dmidecode | ruby -ne '( a=[]; 12.times{a << gets.scan(/(?:Size|Speed|Type):\s*(.*)/).first }; puts a.compact.join("/") ) if $_.match /Memory Device$/' | uniq -cPar charité, je vous fais la même en lisible :
sudo dmidecode | \
ruby -ne '\
( a=[]; \
12.times {
a << gets.scan(/(?:Size|Speed|Type):\s*(.*)/).first \
}; \
puts a.compact.join("/") \
) if $_.match /Memory Device$/\
' | uniq -cSur mon NC10:
1 2048 MB/DDR2/533 MHz (1.9 ns)
1 No Module Installed/DDR2/533 MHz (1.9 ns)Et sur un serveur du boulot:
8 4096 MB/<OUT OF SPEC>/667 MHz (1.5 ns)
24 No Module Installed/<OUT OF SPEC>/Unknown(3615 Jmelapète)
Hope this helps..
zsh & wajig
Posted by JB on 21/06/09 at 21:15
Passé récemment sous zsh comme shell par défaut (merci Laurent), je trouve la complétion automatique de mes commandes wajig très lente. Pour mémoire, wajig est une surcouche plutôt sympa des apt* écrite en Python, et il me sert de gestionnaire de package principal sur mes Debian et Ubuntu depuis plus d’un an. La complétion automatique étant relativement rapide avec les commandes apt-get et compagnie, j’ai décidé de jeter un oeil aux scripts de complétion zsh pour wajig en particulier. J’en ai profité pour rajouter le switch -y/—yes qui manque à la complétion bien qu’étant une option parfaitement valide et documentée.
Les scripts de complétion se trouvent dans /usr/share/zsh/functions/Completion/Debian. J’ai repris le script _apt pour adapter la section install dans le script _wajig. Les deux se servent d’un 3e script commun nommé _deb_packages au cas où ça vous intéresse. Le bonheur c’est que sans connaître vraiment le langage ou les structures utilisées, comme c’est du script relativement lisible on peut tenter par des essais/erreurs de modifier ça… et on y arrive !
Voici le résultat sous forme de patch :
% diff _wajig.orig _wajig
11a12
> '(-y —yes)'{-y,—yes}'[assume yes for any questions asked]' \
44,45c45,46
< _alternative \
< 'packages:package:_deb_packages uninstalled' \
—-
> _wanted \
> 'packages:package:_deb_packages "$expl_packages[@]" avail' \Et les complétions sont redevenues rapides ; le fait de changer _alternative par _wanted m’indique d’abord une liste quand j’appuie sur TAB, plutôt qu’enchainer directement sur les options possibles.
EDIT: une simple recherche Google montre que certains poussent pour que le “framework” de complétion apt pour zsh soit aussi utilisé pour wajig ; à creuser, j’éditerai ce billet si je trouve quelque chose d’intéressant…
Xchat : whois en fenêtre active
Posted by JB on 04/07/09 at 21:53
/set irc_whois_front on
Here we go !
Ubuntu is good for U
Posted by JB on 05/07/09 at 19:53
Ca marche aussi avec Debian, ou n’importe quel projet libre avec une communauté vraiment active.
Le problème: ayant raté une update vers Karmic (la prochaine version d’Ubuntu) récemment, j’ai tenté un downgrade, un peu sporty, et finalement je me suis réinstallé une Jaunty flambant neuve. Et depuis, j’avais perdu le bootsplash, vous savez, le logo Ubuntu au démarrage avec la barre de progression orange qui se remplit. A la place, cette barre commençait à peine et j’obtenais la liste des messages de démarrage de tous les outils Linux.. Bof.
Recherche de soluce: Google, je cherche :
jaunty usplash "Reading files needed to boot"
Et donc tout de suite, je tombe sur ça, qui me redirige sur ce rapport de bug sur Launchpad, la plateforme de développement et remontées de bug collaborative de Canonical, utilisée notamment par Ubuntu.
Je suis le petit pas-à-pas pour résoudre le souci, et en effet, au boot suivant, le splash screen s’affiche bien. Pouah, j’adore le libre dans ces moments là.
(je dis ça parce que le dernier message d’erreur (blocante) que j’ai eu au boulot sur un OS de Redmond, m’a amené à 10 ou 15 réponses différentes, des "sometimes it does that but we don’t know why, let’s reboot, put one finger in your neighboor’s nose and say some abracadabra, it might work).
Hihi :)))
Supervision CPU via SNMP
Posted by JB on 24/08/09 at 19:52
Récemment nous avons rencontré divers problèmes au boulot concernant la supervision du CPU : remontées à 100% alors que “top” indiquait 0%, parfois des remontées en “UNKNOWN” sans raison évidente, etc.
Modes de supervision de la charge CPU
J’écourte l’intro faite sur le wiki du boulot : on peut en gros compter sur 2 sources d’information pour superviser le CPU d’une machine Linux/Unix :
- des commandes système :
top(top -b -n 1+ grep/head/sed),vmstat, voire si vous avez de la chanceprocinfoou autres. - via SNMP, qui propose deux types de compteurs : les compteurs moyennés (ssCpu*) et bruts (ssCpuRaw*). Pour des raisons pratiques, on va se concentrer sur ce mode.
Il y a aussi la charge CPU calculée directement par le système, bien sûr. Mais son calcul comme son interprétation sont complexes, varient en fonction du nombre de processeurs, et, accessoirement, la définition varie d’un Unix-like à un autre. Cela dit si ça vous intéresse, il existe plusieurs plugins (peut-être ça aussi, indirectement).
Je viens de trouver ce plugin qui m’a bien pu, et qui gère apparemment le multi-processeur. Mais ça gâche la suite de l’article alors… revenons donc à la terre ferme.
A. Les compteurs ssCpu
Référence: http://net-snmp.sourceforge.net/docs/mibs/ucdavis.html#ssCpuIdle
Le démon snmpd fournit en standard des compteurs ssCpuIdle, ssCpuUser, etc., directement exprimés en pourcentages, qui devraient permettre de superviser l’occupation du CPU sur une période récente. D’ailleurs on ne sait pas exactement laquelle, je n’ai pas trouvé de référence à ce sujet. Mais ces compteurs sont dépréciés, considérés comme non fiables, et inutilisables en l’état sur une plateforme multi-processeurs ou multi-coeurs (le total arrive, selon les implémentations, à 100% ou N*100%). Le script check_snmp_load.pl, utilisé avec l’option “netsc”, utilise un de ces compteurs, le ssCpuIdle. Ce script est fourni en standard avec le bundle Nagios3 que j’ai au boulot.
Mais il semble notamment que ce compteur n’est pas fiable au-delà de 62 jours d’uptime sur les RHEL5 (tickets sur le bugtracker RedHat ici et ici). Ce genre de bêtise, ça donne quand même envie de se flinguer, merci RedHat…
B. Compteurs ssCpuRaw
Référence: http://net-snmp.sourceforge.net/docs/mibs/ucdavis.html#ssCpuRawIdle
Les compteurs ssCpuRaw* fonctionnent sur un mode différent :
$ snmpwalk -v 2c -c public myserver.domain.tld 1.3.6.1.4.1.2021.11 |grep CpuRaw UCD-SNMP-MIB::ssCpuRawUser.0 = Counter32: 7184735 UCD-SNMP-MIB::ssCpuRawNice.0 = Counter32: 3142 UCD-SNMP-MIB::ssCpuRawSystem.0 = Counter32: 7208896 UCD-SNMP-MIB::ssCpuRawIdle.0 = Counter32: 1116976279 UCD-SNMP-MIB::ssCpuRawWait.0 = Counter32: 4329138 UCD-SNMP-MIB::ssCpuRawKernel.0 = Counter32: 6038492 UCD-SNMP-MIB::ssCpuRawInterrupt.0 = Counter32: 53534 UCD-SNMP-MIB::ssCpuRawSoftIRQ.0 = Counter32: 1116870
Il s’agit de compteurs permettant de jauger l’utilisation du Cpu depuis l’initialisation du compteur. Pour connaitre l’utilisation du Cpu sur une période récente, il faut donc prendre les valeurs à un instant t, prendre les valeurs à un instant t+1, et faire la soustraction. C’est ce que faisait notre script au boulot, “check_net-snmp_cpu_usage.pl”, récupéré d’une instance Nagios1.3/Oreon.
Seulement ce script fait les choses “bêtement”, il prévoit une intervalle fixe entre les deux checks pour faire la différence. Or ces compteurs ne sont pas mis à jour en temps réel, mais à intervalles plus ou moins réguliers, en général 2 secondes, mais ça peut monter à 10 ou 15 secondes en cas de forte charge du serveur (à la louche). Résultat, soit on règle l’attente à 15 secondes et dans la majorité des cas on attendra 15 secondes inutilement, soit on règle ça a des valeurs moindres, et de temps en temps le script sortira en UNKNOWN.
Comment faire ? premier essai : check_cpu_load.rb
Voir mon espace Github
Ce script fait la même chose que check_net-snmp_cpu_usage.pl mais de façon un peu plus intelligente : il récupère une première série de valeurs. Puis chaque seconde il en récupère une nouvelle, et il attend que le nombre de cycles CPU total écoulé entre sa mesure en cours et la première série soit suffisamment important. Ensuite (ou au bout de 15 secondes par sécurité), il fait le calcul et sort. Si les compteurs sont mis à jour rapidement et que le delta est représentatif, il peut sortir la mesure au bout d’1 ou 2 secondes. Sinon, il attend d’avoir une mesure plus représentative, au cas où le serveur travaille peu (peu de cycles CPU), ou si les compteurs ne sont pas mis à jour (serveur saturé).
Deuxième essai : check_cpu_avg.rb
Voir mon espace Github
Mais cette mesure n’est pas très pertinente : vérifier toutes les 5 minutes ce que fait le CPU d’une machine sur les 3,4,5 dernières secondes n’est pas représentatif. Il suffit de lancer la commande à la main plusieurs fois de suite pour s’en convaincre, admirez les écarts en quelques secondes sur mon serveur de supervision :
CPU Used OK: 10.17% | Wait=1.52%, System=0.99%, User=6.67%, Nice=0.00%, Idle=89.83% CPU Used OK: 23.66% | Wait=2.49%, System=1.77%, User=17.63%, Nice=0.00%, Idle=76.34% CPU Used OK: 11.39% | Wait=1.84%, System=1.12%, User=7.31%, Nice=0.00%, Idle=88.61% CPU Used OK: 42.97% | Wait=1.59%, System=3.43%, User=34.52%, Nice=0.00%, Idle=57.03% CPU Used CRITICAL: 99.01% > 90 | Wait=1.64%, System=13.64%, User=70.09%, Nice=0.00%, Idle=0.99% CPU Used CRITICAL: 92.06% > 90 | Wait=1.02%, System=4.76%, User=16.44%, Nice=65.08%, Idle=7.94% CPU Used CRITICAL: 100.00% > 90 | Wait=0.00%, System=3.41%, User=6.31%, Nice=86.86%, Idle=0.00% CPU Used OK: 41.59% | Wait=4.00%, System=3.16%, User=8.58%, Nice=22.70%, Idle=58.41% CPU Used OK: 30.33% | Wait=19.17%, System=1.51%, User=8.14%, Nice=0.00%, Idle=69.67% CPU Used CRITICAL: 94.22% > 90 | Wait=0.35%, System=11.70%, User=70.46%, Nice=0.00%, Idle=5.78%
=> ça ne varie pas toujours autant certes, mais lorsque c’est le cas, ça bouge autant que dans un top, ce qui n’est pas le but recherché. A la limite on se moque (?) des pics de charge instantanés. L’objectif est plutôt de détecter si une machine reste à 100% de CPU trop longtemps, auquel cas une application a peut-être un problème, ou la machine est peut-être sous-dimensionnée.
L’idée consiste à ne faire qu’un “passage” de la commande SNMP, de stocker les résultats dans un fichier, et de regarder le delta au check Nagios suivant. C’est ce que fait check_cpu_avg.rb. Il sort en UNKNOWN s’il ne trouve pas de fichier stockant un check précédent, et sinon, il fait la différence (qui devient donc une moyenne sur la période entre les deux checks, 5 minutes environ pour nous), stocke les nouvelles valeurs dans le fichier et renvoie le résultat de la différence.
Peut-être qu’il est plus pertinent de superviser à la fois ce genre d’indicateur et le LOAD au sens Linux. Il faudrait en creuser la définition du load précédemment cité). C’est un peu obscur pour moi pour le moment, mais si un lecteur a un avis, défoulez-vous !
Remise à plat de mon Postfix
Posted by JB on 29/08/09 at 17:53
Sur mon serveur perso, j’ai des besoins simples en terme de mails :
1- envoyer des mails (relai local) n’importe où
2- recevoir des mails sur mes domaines (jbbarth.com et autres)
Seulement voilà, à force de suivre des tutos à droite à gauche, de piquer des conseils d’un côté et de l’autre, et surtout de me référer à la doc officielle Postfix, impossible de s’y retrouver. Je relayais des centaines de spams par jour sans savoir pourquoi, de quoi s’arracher les cheveux.
Premier coupable, Postfix : je ne me suis pas paluché tous les MAN ni toute la doc officielle dans la longueur, mais après en avoir lu une bonne partie, ce truc est d’une complexité e-ffra-yante. OK, c’est puissant, mais après ? En 1 ligne mal placée on fout toute une conf par terre, génial.
Enfin en regardant autour, Exim n’a pas l’air beaucoup plus simple bien qu’il m’attire nettement plus (ça m’a l’air souple, sympa, c’est le choix Debian par défaut, etc.).
Vient le second coupable, moi : j’ai édité les confs à la main, en tatonnant. Là, je décide de rester sous Postfix, mais de chercher une doc bien foutue. Et là hourra, merci Debian encore (<3), je trouve cette page de wiki ; voici donc :
tar cvzf /home/salvor/postfix.tgz /etc/aliases* /etc/postfix/ wajig remove —purge postfix wajig install postfix sudo -s tail /var/log/mail.log postconf -e "myorigin = chanmasters.com" postconf -e "myhostname=$(hostname)" postconf -e "relay_domains = chanmasters.com, vds171.sivit.org, jbbarth.com, trollsports-trial.com" postfix reload vi /etc/postfix/main.cf #ajout des restrictions proposées sur le debian wiki vi /etc/aliases #on vérifie que les aliases sont toujours en place #au besoin, un petit coup de "newaliases" postconf -e "alias_maps = hash:/etc/aliases" postfix reload echo "test" | mail -s "1. Mail test to root" root echo "test" | mail -s "2. Mail test to webmaster@chanmasters.com" webmaster@chanmasters.com echo "test" | mail -s "3. Mail test to jeanbaptiste.barth@gmail.com" jeanbaptiste.barth@gmail.com tail /var/log/mail.log #les trois mails semblent bien passer #ils sont bien arrivés où il faut #mêmes tests de l'extérieur tail /var/log/mail.log #idem, ça roule \o/
:-)
EDIT: petit oopsie, j’ai rajouté l’option permit_mynetworks à la liste smtpd_recipient_restrictions (en premier), et pour des raisons pratiques (liées au comportement par défaut de Rails), j’ai désactivé le TLS pour le moment. Et là, ça marche !
Final countdown
Posted by JB on 20/10/09 at 12:16
ActiveRecord::Base.logger = Logger.new(STDOUT)
(thanks)
Pense-bête sur l'utilisation de LUKS
Posted by JB on 04/01/10 at 17:42
Voir la doc Ubuntu
Créer un volume encrypté :
sudo cryptsetup luksFormat -c aes -h sha256 /dev/sdb
Ajouter une clé :
sudo cryptsetup luksAddKey /dev/sdb
Voir les clés :
sudo cryptsetup luksDump /dev/sdb
Ouverture et formatage manuel :
sudo cryptsetup luksOpen /dev/sdb disk sudo mkfs.ext3 /dev/mapper/disk
Installation de MongoDB sous Karmic
Posted by JB on 12/01/10 at 08:28
Suite au visionnage du Railscasts d’il y a 2 semaines, je voulais tester MongoDB. Problème, il n’existe pas dans les dépôt officiels. Qu’à cela ne tienne, quelqu’un aura sûrement créé un PPA pour ça, et… en effet, il est ici
Un petit coup de add-apt-repository et c’est parti :
sudo add-apt-repository ppa:rattlecentral sudo aptitude update
Hélas, là ça plante, et pour cause, ce PPA ne semble pas suivre la même structure de dossiers que ceux que j’ai pu ajouter via add-apt-repository par le passé. Qu’à cela ne tienne, il suffit d’éditer /etc/apt/sources.list.d/rattlecentral-ppa-karmic.list comme suit :
#deb http://ppa.launchpad.net/rattlecentral/ppa/ubuntu karmic main deb http://ppa.launchpad.net/rattlecentral/mongodb/ubuntu karmic main
Ensuite :
sudo aptitude update sudo aptitude search mongodb sudo aptitude install mongodb
Nouveau problème : le démon de mongodb mongod ne démarre pas. Il suffit de lancer le démon à la main pour se rendre compte du problème :
% sudo /usr/bin/mongod /usr/bin/mongod: error while loading shared libraries: libmozjs.so: cannot open shared object file: No such file or directory
Et le résoudre :
sudo ln -s /usr/lib/libmozjs.so.0d /usr/lib/libmozjs.so sudo /etc/init.d/mongodb start
Y’a plus qu’à.
PS: évidemment, si vous préférez utiliser l’excellent wajig en lieu et place de dpkg/aptitude, ce n’est pas moi qui vous retiendrai :)
Rails 3.0 beta is out !
Posted by JB on 07/02/10 at 20:22
Here we go :
gem install tzinfo builder memcache-client rack rack-test rack-mount erubis mail text-format thor bundler i18n gem install rails --pre
Let’s give it a try ;)
Hello CouchDB
Posted by JB on 08/02/10 at 18:47
On me titille de part et d’autre : Nicolas, Linux Mag (deux fois en 6 mois!), Damien et Damien, et des discussions par-ci par-là.
Donc c’est parti, j’essaie de me faire une appli sur CouchDB. Avec plein d’arrière pensées :
- mieux maitriser l’outil et les concepts sous-jacents pour mieux comprendre (et pourquoi pas contribuer à) Chef
- comparer ça à MongoDB (voir le railscast) ; si je bute trop, j’essaierai peut-être Mongo
- en finir avec le gouffre conceptuel objet/relationnel ; j’espère que ça sera concluant de ce côté :)
Je me fais une petite base de connaissances parce que le besoin commence à être vraiment trop criant. J’ai des tonnes d’items non-lus et/ou à garder dans mon reader RSS, et j’ai vraiment besoin d’un outil pour organiser ça sous forme de tags (et si possible garder des copies locales des articles).
Pour simplifier le tout, je commence à partir sur du Rails 3 :
echo 'gem "couchrest"' >> Gemfile bundle install
Des nouvelles dans les prochaines semaines, le projet sera comme d’hab’ sur github
Redmine Plugins #1 : Ajouter une option vrai/faux à un plugin Redmine
Posted by JB on 20/02/10 at 15:42
Je travaille en ce moment sur des plugins Engines pour Redmine. Ces plugins me serviront au boulot, et permettront de laisser une situation un peu plus propre que les bidouillages actuels à mon départ. En particulier en avançant sur le plugin de gestion d’un datacenter (site et dépôt github), j’apprends énormément de choses sur le fonctionnement de Rails/Redmine/Engines, et j’entame donc une série d’articles sur ces découvertes. Ces articles supposent d’avoir déjà lu le tutoriel du site, et je repartirai souvent de cet exemple.
Cela donnera certainement lieu à des entrées dans le wiki redmine.org ou des suggestions dans les tickets. Et puis ça m’astreindra à publier un peu, comme le fait Eric dans ses Daily Refactor du core Redmine depuis 3 semaines et pour les mêmes raisons, et aussi suite à cet article de Damien.
Allons-y.
init.rb : on y ajoute la clé et la valeur par défaut du paramètre qu’on veut introduire, par exemple ici “boolean_parameter”. On précise également un partial qui permettra de gérer les paramètres du plugin :
settings :default => { :boolean_parameter => true }, :partial => 'settings/my_plugin'
app/views/settings/_my_plugin.html.erb : on place ici un formulaire pour gérer nos paramètres. Il sera automatiquement accessible dans la partie Administration > Plugins > lien “Configurer” sur votre plugin. “plugin_my_plugin” est à remplacer dans ce qui suit par “plugin_[nom de votre plugin]” :
<p> <label>Paramètre booléen</label> <%= check_box_tag 'settings[boolean_parameter]', 1, Setting[:plugin_my_plugin][:boolean_parameter] %> </p>
Et voilà ! Ensuite, n’importe où dans votre plugin, vous pourrez utiliser :
Setting[:plugin_my_plugin][:boolean_parameter]
En réalité en mettant “1” comme deuxième paramètre, vous ne stockerez pas un booléen, mais “1” (coché) ou “nil” (décoché). Si vous souhaitez obtenir “true” ou “false” absolument, vous pouvez utiliser :
!!Setting[:plugin_my_plugin][:boolean_parameter]
A voir en vrai ici
Un shell en ruby ?
Posted by JB on 25/02/10 at 19:00
Dans 4 jours, je vais me faire massacrer tenter un examen interne au boulot, censé valider mes aptitudes de “programmeur système”. Cet examen comporte une épreuve de développement (sur papier, faut pas déconner), que la plupart des gens vont passer en Java ou C/C++. Mais très peu pour moi, j’attaque en Ruby !
Je lis donc des bouquins, qui présentent un squelette de shell en C. Et en Ruby ? Eh bien en fait, contre toute attente, c’est super simple, voici un squelette fonctionnel :
#!/usr/bin/ruby require 'readline' require 'open3' class Rshell def initialize loop do cmd = Readline.readline("$ ") exit if cmd.nil? or cmd == "exit" Open3.popen3(cmd) do |stdin,stdout,stderr| STDOUT.print stdout.read STDERR.print stderr.read end end end end Rshell.new
Il ne faut pas s’attendre à des miracles, aucun builtin, pas de gestion du PATH, mais on peut passer des commandes, différencier éventuellement STDOUT/STDERR pour le futur.
Ca me donne l’occasion de parler d’un vrai shell en Ruby, utilisé chez Heroku, Rush. J’en reparlerai dès que j’aurai testé ça au quotidien au boulot :)
Partie 1 : le retour de la vengeance
Posted by JB on 04/03/10 at 10:20
Que j’aurais pu aussi sobrement appeler :
- refaisons le match
- massacre à la tronçonneuse
- f*ck
require 'find' require 'yaml' require 'digest/md5' class EvaFile attr_accessor :path def initialize(path) @path = path end def infos @infos ||= {:size => File.size(@path).tap{|s| def s.to_s; "#{self.dup} bytes"; end }, :last_modified => File.mtime(@path), :md5_sum => Digest::MD5.hexdigest(File.read(@path))} end end class EvaDir def initialize(subdir) raise "Give me a (sub)directory !" if subdir.nil? || !File.directory?(subdir) @subdir = subdir end def files @files ||= Find.find(@subdir) do |f| Find.prune if File.directory?(f) EvaFile.new(f) if File.file?(f) end.compact end def write_info_file(filename) path = File.join(@subdir,filename) begin info = File.open(path,"w") rescue $stderr.puts "Error opening file #{path} for writing..." end info.write "Size: #{size} bytes\n" info.write "Files: #{nb_files}\n" files_hash = {} files.each do |file| files_hash.merge!(File.basename(file.path) => file.infos) end info.write files_hash.to_yaml info.close_write end def size @size = files.inject(0) do |memo, f| memo + f.infos[:size] end end def nb_files files.length end end class EvaUtil def initialize(dir) raise "Give me a directory !" if dir.nil? || !File.directory?(dir) @dir = dir end def subdirs return @subdirs if @subdirs @subdirs = [ EvaDir.new(@dir) ] @subdirs << Find.find(@dir) do |f| EvaDir.new(f) if File.directory?(f) end @subdirs = @subdirs.compact.uniq end def generate_info_files(filename="infos.txt") @subdirs.each do |s| s.write_info_file(filename) end end def generate_meta_info_file(filename="metainfos.txt") path = File.join(@dir,filename) begin meta = File.open(path,"w") rescue $stderr.puts "Error opening file #{path} for writing..." end meta.write "Total size: #{size} bytes" meta.write "Total number of files: #{nb_files}" meta.write "Last modified (<24h) :\n #{last_modified.join("\n ")}" if last_modified.any? meta.close_write end def last_modified @subdirs.inject([]) do |memo, subdir| memo << subdir.files.select{|f| File.mtime(f) < Time.at(Time.now.to_i - 86400)}.map(&:path) memo.flatten memo end end private def method_missing(symbol, *args) if %w(nb_files size).include?(symbol.to_s) @subdirs.inject(0) do |memo, subdir| memo + subdir.send(symbol) end else super end end end e = EvaUtil.new(ARGV[0]) e.generate_info_files e.generate_meta_info_file
Garanti 100% non testé, 100% fait sans l’API, et surtout 100% fait avec un éditeur de texte. C’est sûrement bourré de conneries, mais au moins avec un truc comme ça j’aurais pas eu honte. Cela dit vue la longueur, je commence à me pardonner d’avoir barbouillé ma copie de blanco, c’était infaisable sans ça. Coder sur papier est définitivement un cauchemard. On se la refait dans 2 ans ;-)