dpkgcheck - Überprüfe installierte Debian-Pakete
Winfried Mueller, www.reintechnisch.de, Start: 07.02.2007, Stand: 09.02.2007
Die Idee für dieses Werkzeug kam mir bei der Aufgabe, mehrere Debian oder Ubuntu Linux-Server paketmäßig synchron zu halten. Alles, was also auf einem Master-Server installiert wird, soll später auch auf mehreren anderen Servern genauso installiert sein.
Mit dem Werkzeug dpkgcheck kann man hierfür einen Schnappschuss der installierten Pakete des Mastersystems erzeugen. Dieser Schnappschuss kann in einer Datei gespeichert werden.
Das zu synchronisierende System kann nun mit diesem Schnappschuss verglichen werden. Hierbei wird angezeigt, welche Pakete auf diesem System fehlen und welche ein Update erfahren müssen.
Um sich die Arbeit noch zu erleichtern, kann das Ausgabeformat so eingestellt werden, dass direkt ein Bash-Skript ausgegeben wird, in dem die entsprechenden "apt-get install ..." Anweisungen drin stehen.
Gleichzeitig ist dpkgcheck aber auch universell gehalten, so dass es für eine Reihe weiterer Anwendungsfälle nutzbar sein wird. So kann man z.B. gelegentlich überprüfen, welche Pakete seit einem bestimmten Snapshot nachinstalliert wurden. Oder welche Pakete in der Zwischenzeit alle aktualisiert worden sind. Es ist damit ein Werkzeug, mit welchem man Paketveränderungen auf Systemen dokumentieren oder überwachen kann.
Einsetzbar ist das Werkzeug natürlich nur auf Systemen, die dpkg als zentrales Paketmanagment nutzen.
Das Werkzeug sollte sofort auf jedem Ruby 1.8.x System lauffähig sein. Es braucht keine speziellen Bibliotheken. Am besten spielt man mal mit den unter --help aufgeführten Beispielen, dann wird schnell klar, was man mit machen kann.
Übrigens: Genau sowas brauche ich nun auch noch für das Gem-Paketsystem von Ruby. Auch hier ist es nervig, wenn auf einem Master-System alles läuft, auf einem Zielsystem aber Ruby-Skripte nicht funktionieren und man mühsam schrittweise herausfinden muss, was denn nun alles nachinstalliert werden muss.
Quellcode
#!/usr/bin/ruby1.8 # dpkgcheck - Überprüfe/Erstelle dpkg-Liste # Winfried Mueller, www.reintechnisch.de, (c) 2007, GPL # Start: 08.02.2007, Stand: 09.02.2007 # # Generate List # dpkgcheck -l > myserver.lst # # Check List # dpkgcheck -c myserver.lst # DEBUG = true Version = "2007/02/09" require 'optparse' require 'ostruct' def makelist() getpackages.each do |package| case $options.format when "p" puts package['Name'] when "pv", nil puts package['Name'] + " " + package['Version'] when "inst" puts "apt-get install #{package['Name']}" else puts "Undefined List-Format." end end end def getpackages() l = `export COLUMNS=200;dpkg -l` al = l.split( "\n" ) #Header löschen l = false 10.times do d = al.shift if d =~ /^\+\+\+/ l = true break end end raise "Kann Anfang von dpkg -l nicht finden." unless l packages = [] al.each do |package| if package =~ /^(ii|hi)\s+(.*?)\s+(.*?)\s+/ packages << { 'Name' => $2, 'Version' => $3 } end end packages end def checklist( list ) line_nr = 1 packages = getpackages c_packages = Hash.new packages.each do |package| c_packages[package['Name']] = package['Version'] end f_packages = Hash.new File.foreach( list ) do |line| package, version = line.split( /\s+/ ) raise "Error in list-Format line: #{line_nr}" if !package || !version case $options.format when "all", nil if !c_packages[package] puts "#{package}: Install" else if c_packages[package] != version puts "#{package}: Update: #{version} => #{c_packages[package]}" end end when "apt" if !c_packages[package] puts "apt-get install #{package}" end when "install" if !c_packages[package] puts "#{package}: Install" end when "update" if (cv = c_packages[package]) if cv != version puts "#{package}: Update: #{version} => #{c_packages[package]}" end end end f_packages[package] = version line_nr += 1 end packages.each do |package| case $options.format when "all", nil, "remove" if !f_packages[package['Name']] puts "#{package['Name']}: Remove" end when "apt" if !f_packages[package['Name']] puts "apt-get remove #{package['Name']}" end end end end # ---------------------------------------------------------------- ARGV.options do |o| o.banner = "Usage: dpkgcheck [options]" o.separator( "dpkgcheck - Generate and Compare dpkg-list" ) o.separator( "" ) o.on( "-l", "--mklist [FORMAT]", "Make a dpkg-list to stdout. [p|pv|apt]" ) do |fmt| $options.mklist = true $options.format = fmt end o.on( "-f", "--format FORMAT", "Output Format for -c [all|apt|install|update|remove]" ) do |fmt| $options.format = fmt end o.on( "-c", "--check FILELIST", "Compare installed package with dpkg-list." ) do |f| $options.check = f end o.on( "-v", "--verbose", "All Check results (default only different Files)." ) do $options.verbose = true end o.on_tail("-h", "--help", "This help." ) do puts o puts( "" ) puts( "Examples:" ) puts( " dpkgcheck -l > myserver-2007-02-07.lst # make dpkg-list snapshot" ) puts( " dpkgcheck -l p # list all installed packages" ) puts( " dpkgcheck -l apt # generate apt-get install list" ) puts( " dpkgcheck -c myserver-2007-02-07.lst # View changes from snapshot" ) puts( " dpkgcheck -f apt -c myserver-2007-02-07.lst # Make a package install script" ) puts( " dpkgcheck -f install -c myserver-2007-02-07.lst # View only packages to install" ) puts( " dpkgcheck -f update -c myserver-2007-02-07.lst # View only packages to update" ) puts( "" ) exit end o.on_tail("--version", "Show version") do puts o.ver puts "Written by Winfried Mueller, www.reintechnisch.de" puts "" puts "Copyright (C) 2007 Winfried Mueller" puts "This is free software; see the source for copying conditions." puts "There is NO warranty; not even for MERCHANTABILITY or" puts "FITNESS FOR A PARTICULAR PURPOSE." exit end end # ---------------------------------------------------------------- begin $options = OpenStruct.new $options.verbose = false err_code = 0 ARGV.parse! if $options.mklist != nil makelist( ) elsif $options.check != nil checklist( $options.check ) else STDERR.puts ARGV.options.to_s end rescue SystemExit rescue Exception => exc STDERR.puts "E: #{exc.message}" #STDERR.puts ARGV.options.to_s raise if DEBUG end exit err_code