Support for logging to database via grml-live-db. Changed logic of ZERO_LOGFILE to...
authorMichael Prokop <mika@grml.org>
Sun, 13 Dec 2009 14:32:47 +0000 (15:32 +0100)
committerMichael Prokop <mika@grml.org>
Sat, 30 Jan 2010 13:34:10 +0000 (14:34 +0100)
grml-live-db provides a feature to log build information into a sqlite database.

12 files changed:
db/db-to-fai [new file with mode: 0755]
db/dpkg-to-db [new file with mode: 0755]
debian/control
debian/grml-live-db.doc-base [new file with mode: 0644]
debian/grml-live-db.docs [new file with mode: 0644]
debian/grml-live-db.install [new file with mode: 0644]
debian/overrides.grml-live-db [new file with mode: 0644]
debian/rules
docs/Makefile
docs/grml-live-db.txt [new file with mode: 0644]
etc/grml/grml-live.conf
grml-live

diff --git a/db/db-to-fai b/db/db-to-fai
new file mode 100755 (executable)
index 0000000..074cca3
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+# Filename:      db-to-fai
+# Purpose:       convert output of grml-live's sqlite database for use within FAI
+# Authors:       grml-team (grml.org)
+# Bug-Reports:   see http://grml.org/bugs/
+# License:       This file is licensed under the GPL v2 or any later version.
+################################################################################
+
+if [ -z "$2" ] ; then
+  echo "Usage: $0 /path/to/grml-live.db <build-id>"
+  exit 1
+fi
+
+DB="$1"
+BUILD_ID="$2"
+
+if ! [ -r "$DB" ] ; then
+  echo "Error: can not access database ${DB}.">&2
+  bailout 1
+fi
+
+TMPFILE=$(mktemp)
+
+bailout() {
+  rm -f "$TMPFILE"
+  [ -n "$1" ] && exit "$1" || exit 0
+}
+
+# get information from db:
+if ! echo "select package,version FROM packages, build WHERE build.id = $BUILD_ID AND packages.build = build.id and status = 'ii';" | sqlite3 $DB > $TMPFILE ; then
+   echo "Error retrieving values from database ${DB}." >&2
+   bailout 1
+else
+   # make sure we god some matches:
+   if ! grep -q '^[a-zA-Z]*' "$TMPFILE" ; then
+      echo "No packages retrieved from build id $BUILD_ID - wrong id?" >&2
+      bailout 1
+   fi
+
+   # write fai header and package information to stdout:
+   echo "# package list of build $BUILD_ID from database $DB:"
+   echo "PACKAGES aptitude"
+   awk -F\| '{print $1"="$2}' "$TMPFILE"
+fi
+
+# clean exit:
+bailout
+
+## END OF FILE #################################################################
diff --git a/db/dpkg-to-db b/db/dpkg-to-db
new file mode 100755 (executable)
index 0000000..6510d12
--- /dev/null
@@ -0,0 +1,142 @@
+#!/usr/bin/perl -w
+# Filename:      dpkg-to-db
+# Purpose:       add grml build information into a sqlite database
+# Authors:       grml-team (grml.org)
+# Bug-Reports:   see http://grml.org/bugs/
+# License:       This file is licensed under the GPL v2 or any later version.
+################################################################################
+# Requires the following Debian packages (handled via grml-live-db depends):
+# libdbd-sqlite3-perl libdbi-perl libtimedate-perl perl-doc sqlite3
+################################################################################
+
+use strict;
+
+use warnings;
+use Getopt::Long;
+use Pod::Usage;
+use DBI;
+use Date::Format;
+
+
+my ($db, $logfile, $flavour, $help);
+my $rc = GetOptions (
+               'db|d=s' => \$db,
+               'logfile|l=s' => \$logfile,
+               'flavour|f=s' => \$flavour,
+               'help|h' => \$help,
+       );
+
+pod2usage(1) if $help;
+
+pod2usage(-message => "$0: Need a sqlite database.\n") unless $db;
+pod2usage(-message => "$0: Need a logfile to insert.\n") unless $logfile;
+pod2usage(-message => "$0: Need the flavour information\n") unless $flavour;
+
+my $dbh = DBI->connect("dbi:SQLite:dbname=$db","","") or die "Could not connect to database: " . $DBI::err;
+
+# We use foreign key - beware this needs sqlite > 3.6.19
+$dbh->do("PRAGMA foreign_keys = ON");
+
+open (my $fh, '<', $logfile) or die "Could not open $logfile: $!";
+
+# read content of log file - please do not try this at home :)
+my $log = do { local $/; <$fh> };
+
+my $identifier = "$flavour-". time2str('%Y%m%d%H%M%S', time());
+
+# Prepare tables if not yet present {{{
+my $create_table_build = $dbh->prepare("
+CREATE TABLE if not exists build ( id integer primary key autoincrement,
+identifier varchar(30),
+flavour varchar(30),
+date varchar(30),
+logfile blob);
+")
+  or die "Could not create tables: " . $dbh->errstr."\n";
+
+$create_table_build->execute()
+  or die "Can't execute SQL statement: " . $dbh->errstr."\n";
+
+my $create_table_packages = $dbh->prepare("
+CREATE TABLE if not exists packages (  id integer primary key autoincrement,
+package varchar(30),
+status varchar(2),
+version varchar(30),
+build integer,
+FOREIGN KEY(build) REFERENCES build(id));
+")
+  or die "Could not create tables: " . $dbh->errstr."\n";
+
+$create_table_packages->execute()
+  or die "Can't execute SQL statement: " . $dbh->errstr."\n";
+# }}}
+
+
+# Write information to database {{{
+my $sth = $dbh->prepare("INSERT into build ('identifier','flavour','date','logfile') VALUES (?,?,?,?)")
+       or die "Could not prepare db statement: " . $dbh->errstr;
+
+# Execute the query
+$sth->execute($identifier, $flavour, time(), $log)
+       or die "Could not add build to db: " . $sth->errstr;
+
+$sth = $dbh->prepare("SELECT id from build where identifier = ?");
+$sth->execute($identifier) or die "Couldn't execute statement: " . $sth->errstr;
+my $row = $sth->fetch;
+my $id = $row->[0];
+
+die "No id?" unless $id;
+
+$sth = $dbh->prepare("INSERT into packages (package, status, version, build) VALUES (?,?,?,?)")
+       or die "Could not prepare db statement: " . $dbh->errstr;
+
+while (my $line = <>) {
+       next unless $line =~ /^[a-z]{2} /;
+       # remove new lines
+       my ($status, $package, $version, $desc) = split (/\s+/, $line, 4);
+       $sth->execute($package, $status, $version, $id)
+               or die "Couldn't execute statement: " . $sth->errstr;
+
+}
+# }}}
+
+print "recorded buildinformation with identifier $identifier as id $id\n";
+
+# perldoc -F ./dpkg-to-db
+
+__END__
+
+=head1 dpkg-to-db
+
+dpkg-to-db - add grml build information into a sqlite database
+
+=head1 SYNOPSIS
+
+dpkg-to-db [options]
+
+  Options:
+   --help              brief help message
+   --db <database>     database file
+   --logfile <logfile>  logfile which should be added
+   --flavour <flavour>  which flavour the build is
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-help>
+
+Print a brief help message and exits.
+
+=back
+
+=head1 DESCRIPTION
+
+B<dpkg-to-db> will read the given input file(s) which holds output of
+`dpkg --list' and writes the information to the specified database.
+
+=head1 USAGE EXAMPLES
+
+Please see B<man 8 grml-live-db> for further information.
+
+=cut
index 84324b6..2e91104 100644 (file)
@@ -27,3 +27,13 @@ Description: templates/boot/addons for grml-live
  This package provides the boot addons known as the features
  providing bootoptions bsd, dos, grub and hdt. You can safely
  skip this package if you don't need the addons.
+
+Package: grml-live-db
+Architecture: all
+Depends: ${misc:Depends}, grml-live, libdbd-sqlite3-perl, libdbi-perl, libtimedate-perl, sqlite3
+Recommends: perl-doc
+Description: log package build information of grml-live to database
+ This package provides a database layer for storing build
+ information about grml-live builds in a sqlite3 database.
+ More details are available in the provided grml-live-db manpage
+ and /usr/share/doc/grml-live-db/grml-live-db.html
diff --git a/debian/grml-live-db.doc-base b/debian/grml-live-db.doc-base
new file mode 100644 (file)
index 0000000..2eab618
--- /dev/null
@@ -0,0 +1,10 @@
+Document: grml-live-db
+Title: Documentation for the database wrapper of grml-live
+Author: Michael Prokop
+Abstract: grml-live-db provides a database layer for storing build
+ information about grml-live builds in a sqlite3 database.
+Section: Debian
+
+Format: HTML
+Index: /usr/share/doc/grml-live-db/grml-live-db.html
+Files: /usr/share/doc/grml-live-db/grml-live-db.html
diff --git a/debian/grml-live-db.docs b/debian/grml-live-db.docs
new file mode 100644 (file)
index 0000000..1443038
--- /dev/null
@@ -0,0 +1 @@
+docs/grml-live-db.html
diff --git a/debian/grml-live-db.install b/debian/grml-live-db.install
new file mode 100644 (file)
index 0000000..ff4810d
--- /dev/null
@@ -0,0 +1,3 @@
+db/db-to-fai        usr/share/grml-live-db/scripts/
+db/dpkg-to-db       usr/share/grml-live-db/scripts/
+docs/grml-live-db.8 usr/share/man/man8/
diff --git a/debian/overrides.grml-live-db b/debian/overrides.grml-live-db
new file mode 100644 (file)
index 0000000..5946edd
--- /dev/null
@@ -0,0 +1 @@
+grml-live-db: unknown-section grml
index 905916b..a2e847f 100755 (executable)
@@ -78,11 +78,31 @@ grml-live-addons: install
        dh_md5sums           -p$@ -P$(b)/$@
        dh_builddeb          -p$@ -P$(b)/$@
 
+grml-live-db: install
+       @echo "--- Building: $@"
+       dh_installdirs       -p$@ -P$(b)/$@
+       dh_link              -p$@ -P$(b)/$@
+       dh_installdocs       -p$@ -P$(b)/$@
+       dh_installchangelogs -p$@ -P$(b)/$@
+       dh_install           -p$@ -P$(b)/$@
+       dh_strip             -p$@ -P$(b)/$@
+       dh_compress          -p$@ -P$(b)/$@
+       mkdir -p $(b)/$(@)/usr/share/lintian/overrides/
+       cp -av debian/overrides.$(@) $(b)/$(@)/usr/share/lintian/overrides/$(@)
+       dh_fixperms          -p$@ -P$(b)/$@
+       dh_makeshlibs        -p$@ -P$(b)/$@ -V
+       dh_installdeb        -p$@ -P$(b)/$@
+       dh_shlibdeps         -p$@ -P$(b)/$@
+       dh_installdebconf    -p$@ -P$(b)/$@
+       dh_gencontrol        -p$@ -P$(b)/$@
+       dh_md5sums           -p$@ -P$(b)/$@
+       dh_builddeb          -p$@ -P$(b)/$@
+
 # Build architecture-dependent files here.
 binary-all: build install
 
 # Build architecture-independent files here.
-binary-indep: build install grml-live grml-live-addons
+binary-indep: build install grml-live grml-live-addons grml-live-db
 
 binary: binary-indep binary-arch
 .PHONY: build clean binary-indep binary-arch binary install
index 9771ab2..a64b80b 100644 (file)
@@ -4,9 +4,10 @@ doc: doc_man doc_html
 
 doc_html: html-stamp
 
-html-stamp: grml-live.txt grml-live-remaster.txt
+html-stamp: grml-live.txt grml-live-remaster.txt grml-live-db.txt
        asciidoc -b xhtml11 -a icons -a toc -a numbered grml-live.txt
        asciidoc -b xhtml11 -a icons grml-live-remaster.txt
+       asciidoc -b xhtml11 -a icons grml-live-db.txt
        touch html-stamp
 
 doc_man: man-stamp
@@ -16,6 +17,8 @@ man-stamp: grml-live.txt grml-live-remaster.txt
        xsltproc /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl grml-live.xml
        asciidoc -d manpage -b docbook grml-live-remaster.txt
        xsltproc /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl grml-live-remaster.xml
+       asciidoc -d manpage -b docbook grml-live-db.txt
+       xsltproc /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl grml-live-db.xml
        touch man-stamp
 
 online: doc_html
@@ -24,3 +27,4 @@ online: doc_html
 clean:
        rm -rf grml-live-remaster.html grml-live-remaster.xml grml-live-remaster.8
        rm -rf grml-live.html grml-live.xml grml-live.8 html-stamp man-stamp
+       rm -rf grml-live-db.html grml-live-db.xml grml-live-db.8 html-stamp man-stamp
diff --git a/docs/grml-live-db.txt b/docs/grml-live-db.txt
new file mode 100644 (file)
index 0000000..a52e74e
--- /dev/null
@@ -0,0 +1,104 @@
+grml-live-db(8)
+===============
+
+Name
+----
+grml-live-db - log package build information of grml-live to database
+
+Synopsis
+--------
+dpkg-to-db  [ options ] || db-to-fai /path/to/grml-live.db <build-id> |
+
+Introduction
+------------
+
+The grml-live-db Debian package provides a simple way to put build information
+of grml-live into a database. By default you have to do nothing but install
+grml-live-db and during each invocation of grml-live you'll get an additional
+entry in the sqlite3 database /var/log/grml-live.db. If you want to customize
+the database logging check out the following sections in this manpage.
+
+Provided scripts
+----------------
+
+/usr/share/grml-live-db/scripts/dpkg-to-db adds grml-live build information
+(output of 'dpkg --list') and (optionally) a logfile into a sqlite3 database.
+This script is used by default if grml-live-db is installed (no configuration
+needed by default).
+
+/usr/share/grml-live-db/scripts/db-to-fai converts output of grml-live's sqlite
+database for use within FAI. This script is useful if you want to reproduce a
+certain build with specific package versions. Please note that you need the
+according Debian mirrors providing all the specific package versions of course.
+
+Options
+-------
+
+dpkg-to-db supports the following options:
+
+  --help
+
+Brief help message.
+
+  --db <database>
+
+Use specified database file.
+
+  --logfile <logfile>
+
+Logfile thath should be added to the database entry.
+
+  --flavour <flavour>
+
+Name of the grml-live flavour that was being built.
+
+db-to-fai does not support any options but needs to be invoked
+with path to the grml-live database and the build id.
+
+Configuration and using custom database wrapper scripts
+-------------------------------------------------------
+
+The following configuration variables are available and can be adjusted:
+
+  DPKG_DATABASE=/var/log/grml-live.db
+
+Path to the database file that should be used for storing the build information.
+This database is ysed within dpkg-to-db by default.
+
+  DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
+
+The database wrapper script that's used for storing the build information.
+If you do not want to log to the sqlite3 database but instead use your own
+abstraction layer just point this variable to your favourite script.
+
+  DPKG_DBOPTIONS="-d $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME < $DPKG_LIST"
+
+If the database script ($DPKG_DBSCRIPT) requires any command line options
+specifiy it through this variable.
+
+Usage Examples
+--------------
+
+How dpkg-to-db is being used inside grml-live:
+
+  /usr/share/grml-live-db/scripts/dpkg-to-db -d /var/log/grml-live.db --logfile /var/log/grml-live.log --flavour $GRML_NAME < /var/log/fai/$HOSTNAME/last/dpkg.list
+
+Manually insert data to database:
+
+  # /usr/share/grml-live-db/scripts/dpkg-to-db -d ./grml-live.db --logfile /tmp/logfile --flavour grml-full < ./dpkg.list
+
+  # dpkg -l | ./dpkg-to-db --db ./grml-live.db --logfile /tmp/logfile --flavour grml-full
+
+Retrieve build information of a specific build for use within FAI:
+
+  # /usr/share/grml-live-db/scripts/db-to-fai /var/log/grml-live.db 6 > /etc/grml/fai/config/package_config/REPRODUCE
+
+Describe schema of database:
+
+  # echo '.schema' | sqlite3 /var/log/grml-live.db
+
+Query database:
+
+  # echo 'SELECT package,version,status,build.flavour,build.identifier FROM packages, build WHERE build.identifier = "grml-full-20091213012517" AND packages.build = build.id ; ' | sqlite3 /var/log/grml-live.db
+
+  # echo 'SELECT package,version,status,build.flavour,build.identifier FROM packages, build WHERE build.id = 7 AND packages.build = build.id ; ' | sqlite3 /var/log/grml-live.db
index 6a4671b..493bb2d 100644 (file)
 # Where do you want to find the final ISO?
 # ISO_OUTPUT="$OUTPUT/grml_isos"
 
-# Do you want to zero / clean up the logfile on each grml-live execution?
-# Especially useful if you are using an autobuild setup where you want
-# store /var/log/grml-live.log after each invocation of grml-live.
-# Default: unset (so do not zero the logfile)
-# ZERO_LOGFILE='1'
+# Do you want to preserve the logfile from being cleaned after each execution
+# of grml-live? By default the logfile is cleaned so the log doesn't fill up.
+# If you want to store your logs permanently it's recommended to use grml-live-db.
+# PRESERVE_LOGFILE='1'
+
+# If package grml-live-db is installed the package selection and grml-live.log
+# are being logged to to a sqlite database.Defaults to /var/log/grml-live.db
+# DPKG_DATABASE=/var/log/grml-live.db
+
+# Use your own database wrapper script for grml-live-db:
+# DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
+
+# Use your own database script cmdline options for grml-live-db:
+# DPKG_DBOPTIONS="-d $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME < $DPKG_LIST"
 
 # Do you want to zero / clean up / remove the previous logfiles of FAI
 # before executing grml-live? Otherwise keep all the logfiles inside
index 9057b04..7d8bb82 100755 (executable)
--- a/grml-live
+++ b/grml-live
@@ -123,6 +123,8 @@ else
    eerror() { echo "  [!] $*">&2 ;}
    ewarn()  { echo "  [x] $*" ;}
    eend()   { return 0 ;}
+   eindent()  { return 0 ;}
+   eoutdent() { return 0 ;}
 fi
 
 # source main configuration file:
@@ -287,7 +289,9 @@ ISO_OUTPUT="$OUTPUT/grml_isos"
 # }}}
 
 # clean/zero grml-live logfile {{{
-if [ -n "$ZERO_LOGFILE" ] ; then
+if [ -n "$PRESERVE_LOGFILE" ] ; then
+  echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
+else
    echo -n > $LOGFILE
 fi
 # }}}
@@ -1118,10 +1122,56 @@ else
 fi
 # }}}
 
+# log build information to database if grml-live-db is installed and enabled {{{
+dpkg_to_db() {
+if [ -d /usr/share/grml-live-db ] ; then
+
+  # safe defaults
+  DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
+  [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
+  [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
+  [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="-d $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME < $DPKG_LIST"
+
+  if ! [ -x "$DPKG_DBSCRIPT" ] ; then
+    eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
+    bailout 14
+  fi
+
+  # disable by default for now, not sure whether really everyone is using a local db file
+  #if ! touch "$DPKG_DATABASE" ; then
+  #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
+  #  bailout 14
+  #fi
+
+  if ! [ -r "$DPKG_LIST" ] ; then
+     eerror "Error reading $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT" ; eend 1
+     bailout 14
+  else
+     einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
+     eindent
+
+     if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
+       einfo "$DB_INFO"
+       eend 0
+     else
+       eerror "$DB_INFO"
+       eend 1
+     fi
+
+     eoutdent
+  fi
+
+fi
+}
+# }}}
+
 # finalize {{{
 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
-einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
+
+dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
+
+einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
 bailout 0
 # }}}