Chef la recette !
Posted by JB on 23/03/10 at 17:52
Après avoir comparé au boulot 3 outils de gestion de conf, j’en retiens les éléments suivants :
- Cfengine : DSL spécifique et horrible à apprendre, orientations peu claire (à-la-Nagios), une communauté amorphe, pas hackable. Poubelle.
- Puppet : en ruby, un DSL spécifique pour les confs (bof), a fait ses preuves, une bonne doc, de plus en plus hackable (la doc s’améliore de jour en jour), une communauté dynamique, et le projet est géré sous redmine. Sympa.
- Chef : en ruby, tout en ruby, donc pas de DSL à apprendre (yeah!), une doc pas mal, hackable à l’infini, le projet est hyper mega dynamique, et ils ont des références énormes dans le monde ruby, du genre 37signals ou Engine Yard. Adopté !
Seul défaut de Chef, ça bouge vite, très vite. Et les versions 0.7 présentes dans mes distrib préférées commencent à être vraiment dépassées.
Hier je me prends donc par la main, en m’inspirant de l’article de akitaonrails, et je cherche comment installer une 0.8. Miracle, tout est dans leur wiki, et ils proposent même des dépôts pour ma Ubuntu Lucid.
Voici un script chef-install pondu en 3 secondes :
#installation
add-apt-repository ppa:jtimberman/opschef
aptitude update
aptitude -y install chef
service chef-client stop
update-rc.d chef-client disable >/dev/null
#configuration
sed -i -e 's#^file.*#file_cache_path "/tmp/chef-solo"#' \
-e 's#^cook.*#cookbook_path ["/var/chef-solo/cookbooks"]#' /etc/chef/solo.rb
#cookbooks (install 'git-core' if needed)
mkdir -p /var/chef-solo
cd /var/chef-solo
git clone http://github.com/opscode/cookbooks.git
#hyperspace!
cat >/etc/chef/recipes.json <<EOF
{
"resolver": {"nameservers":["192.168.0.1"], "search":"home"},
"recipes": ["resolver"]
}
EOFGo ?
% sudo chef-solo -j /etc/chef/recipes.json [Tue, 23 Mar 2010 13:47:37 +0100] INFO: Starting Chef Solo Run [Tue, 23 Mar 2010 13:47:42 +0100] WARN: Missing gem 'right_aws' [Tue, 23 Mar 2010 13:47:42 +0100] WARN: Missing gem 'mysql' [Tue, 23 Mar 2010 13:47:43 +0100] INFO: Updating template[/etc/resolv.conf] at /etc/resolv.conf [Tue, 23 Mar 2010 13:47:43 +0100] INFO: Backing up template[/etc/resolv.conf] to /etc/resolv.conf.chef-20100323134743 [Tue, 23 Mar 2010 13:47:43 +0100] INFO: Chef Run complete in 5.588404 seconds
Yeeehaa !
Mon fonctionnement actuel m’empêche de m’attacher à un serveur central et ainsi fonctionner en client/serveur. Je pense que je vais donc commencer à me faire des cookbooks et les utiliser “bêtement” via chef-solo, à voir.
Enfin pour l’instant, c’est juste énorme.
Schema-Free MySQL contre NoSQL
Posted by JB on 19/03/10 at 17:00
En ce moment il y a une vague d’engouement pour les bases non-SQL, comme les bases orientées document CouchDB ou MongoDB. J’ai lu un article récemment qui vaut le détour : Schema Free Mysql VS NoSQL (via). Ce genre de solution permettrait sûrement de faire passer la pillule plus doucement aux gens qui s’accrochent encore au SQL pur à l’ancienne.
Au passage, juste une citation qu’on croirait destinée à certains ayatollahs du boulot :
Open your mind. FriendFeed uses something very similiar to this to handle 250 million entries. Why is it no good for the theorists? Because they don’t solve problems, they make them.
.irbrc pour Rails 3
Posted by JB on 17/03/10 at 19:22
J’utilise souvent IRB. Très souvent pour d’autres choses que Rails (à la base on me paye pour être sysadmin, pas développeur…).
Là arrive Rails 3 beta :
- qui s’appuie sur IRB pour sa console (
rails console) - qui gère ses dépendances via Bundler, ce qui ne permet plus par défaut de charger des Gems en dehors de son appli
Bah oui mais là ça coince. De bêtes require dans mon .irbrc ne fonctionnent plus. Comme discuté sur la liste rails france, je charge dans mon .irbrc des choses dont j’ai très souvent besoin, et qui n’ont rien à voir avec mes applis, même en Rails 3. Par exemple, il n’y a aucune raison qu’une de mes applis dépende de Wirble, une lib pour améliorer IRB.
Bref, faute de mieux pour le moment, voilà le genre d’horreur auquel Rails me pousse :
basedirs = ENV["GEM_PATH"].to_s.split(":").map{|d|"#{d}/gems/*/lib"} Dir.glob(basedirs).each do |dir| $: << dir unless $:.include?(dir) end
Humpf.
Déplacer une base Rails
Posted by JB on 17/03/10 at 14:19
Au boulot nous avons une instance Redmine qui tourne avec une base Sqlite3 pour nos tickets internes. Pratique, mais nous avons aussi développé une offre d’hébergement Redmine ouverte à la demande sur l’intranet, sous Mysql. D’où passage de l’instance Sqlite sous Mysql.
On ne peut bien sûr pas se contenter d’un export SQL de Sqlite à réimporter sous Mysql : ces deux moteurs ne respectent pas exactement la même syntaxe SQL, et ne stockent pas leurs types primitifs de la même manière (exemple: les booléens, stockés en “1/0” sous Mysql, et en “t/f” sous Sqlite).
C’est là qu’arrive yaml_db , une biblitothèque à installer comme une gem ou comme un plugin dans une appli Rails, qui permet de réaliser des exports ou imports de sa base sous un format neutre, YAML (wikipedia).
Pour une migration “one shot”, le plus simple sera de cloner la lib dans le répertoire plugins de vos applis et de suivre les instructions proposées dans le README :
cd /path/to/my/app cd vendor/plugins git clone http://github.com/ludicast/yaml_db.git cd - rake db:dump #modifications éventuelles du fichier db/data.yml (chez nous l'appli change d'adresse, donc on a remplacé toutes les anciennes URLs) #changement de database.yml rake db:load
Un outil simple, comme on aime :)
EDIT: j’ai titré “déplacer une base Rails” car ce plugin fonctionne bien surtout avec une base ActiveRecord, ORM de Rails par défaut. Pour une base quelconque rien de garanti :)
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 ;-)