Kurz-Howto: Baculas Konfiguration stark vereinfachen

(2007-12-16)

Mit Baculas hoher Flexibilität einher geht auch eine hohe Komplexität bei den Konfigurationsdateien. Letztendlich landet man aber, nachdem man sich mal damit befasst hat, bei einer Konfiguration, die für jeden Rechner weitestgehend gleich ist. Bei einigen Resourcen muss man sogar nur den Namen austauschen.

In meinem Setup habe ich 10 Rechner, die gesichert werden sollen. Mit dem normalen Ansatz müsste ich nun 10 Mal die komplette Konfiguration durchführen, die weitestgehend gleich ist.

Als Alternative würde schon eine Direktive genügen, mit der ich in der Konfiguration, die ja das Einbinden von anderen Dateien erlaubt, Variablen angeben könnte, die ersetzt würden, dachte ich mir. Nachdem ich mir anschaute, wie man das am besten implementieren könnte, bemerkte ich, dass Bacula auch mit Pipes umgehen kann beim Laden von Konfigurationsdateien, sprich man kann andere Programme ausführen und deren Ausgabe verwenden.

In bester UNIX-Manier kann man also sed und Shell-Scripts verwenden, um sich die Konfiguration zu abstrahieren. Jedoch gab es zwei kleine Probleme:

  • Ein Bug verhinderte, dass Pipes richtig ausgeführt werden, denn das Pipe-Zeichen wurde nicht übersprungen und somit wurde das auszuführende Programm nicht gefunden.
  • Der Parser behandelte Anführungszeichen bei Include-Direktiven als Trennzeichen und erlaubte keine Angabe eines Befehls, der Leerzeichen enthielt und daher in Anführungszeichen eingeschlossen werden muss. Somit könnte man zwar ein Shellscript ausführen, ihm jedoch keine Parameter mitgeben, wodurch man nichts gewonnen hätte.

Beide Fehler konnte ich für Version 2.2.7 von Bacula beheben.

Templates

Wie die Templates nun aussehen, die man sich selbst macht, ist weitestgehend beliebig. Ich habe als Variable zum Beispiel %name verwendet. Mit sed wird diese Variable dann ersetzt.

Template-Datei default-pool.inc

Pool {
    Name = %name
    Pool Type = Backup
    Maximum Volume Jobs = 1
    Volume Retention = %ret
    Maximum Volume Bytes = 0
    Volume Use Duration = 0
}

Einbindung in bacula-dir.conf

@"|sed 's/%name/codebox/g;s/%ret/2 weeks/g' /etc/bacula/default-pool.inc"

Hier wurde also %name durch „codebox” ersetzt und die Volume Retention-Variable %ret durch „2 weeks”. Nach diesem Schema kann man nun mehrere Rechner sehr einfach einbinden:

@"|sed 's/%name/codebox/g;s/%ret/2 weeks/g' /etc/bacula/default-pool.inc"
@"|sed 's/%name/ibook/g;s/%ret/4 weeks/g' /etc/bacula/default-pool.inc"
@"|sed 's/%name/macbook/g;s/%ret/4 weeks/g' /etc/bacula/default-pool.inc"

Das macht dann 3 Zeilen im Vergleich zu 24 Zeilen Konfigurationsaufwand…

Template-Datei default-client.inc

Client {
    Name = %name-fd
    Address = %address
    FDPort = 9102
    Catalog = MyCatalog
    Password = "%pass"
    File Retention = %ret
    Job Retention = %ret
    AutoPrune = yes
}

Hierbei ist darauf zu achten, dass man – da sed manche Zeichen anders interpretiert – manche Zeichen escapen muss. Da der Parser von Bacula jedoch auch escaped, muss man sogar doppeltes Escaping vornehmen:

@"|sed 's/%name/codebox/g;s/%address/codebox/g;s/%ret/2 weeks/g;s/%pass/password mit \/ slash/g' /etc/bacula/default-client.inc"

Dieser Aufruf entspricht dem Passwort „password mit / slash”.

Template-Datei default-device.inc

Device {
    Name = %name-files
    Media Type = File
    Archive Device = /raid/%name
    LabelMedia = yes
    Random Access = Yes
    AutomaticMount = no
    RemovableMedia = no
    AlwaysOpen = no
}

Natürlich klappt diese Technik auch beim Storage Daemon, sodass man sich hier – je nach Setup – auch wieder enorm viele Zeilen sparen kann.

Include-Datei default-fs-exclude-linux.inc

Wenn wir gerade beim Einbinden von Dateien sind, ist es auch sinnvoll, die standardmäß auszulassenden Files auszulagern:

File = /proc
File = /tmp
File = /.journal
File = /.fsck
File = /media
File = /mnt
File = /sys
File = /lost+found

Include-Datei default-fs-exclude-mac.inc

File = /Volumes
File = /tmp
File = /private/tmp
File = /cdrom
File = /automount
File = /Network
File = /.vol

Template-Datei default-job.inc

Job {
    Name = "%name"
    Type = Backup
    Client = %name-fd
    FileSet = "%name-set"
    Schedule = "%name-sched"
    Storage = %name-storage
    Messages = Standard
    Priority = 10
    Write Bootstrap = "/raid/%name/bootstrap"
    Pool = %name
}

Diese Datei fügt quasi die anderen Dateien zusammen und hat die größte Ausbeute, was Zeilen und Ersetzungen angeht.

Template-Datei default-storage.inc

Storage {
    Name = %name-storage
    # Use VPN address here to enable clients connecting via VPN to back up
    Address = fs.vpn
    SDPort = 9103
    Password = "secret"
    Device = %name-files
    Media Type = File
}

Template-Datei/Script default-fs.inc/default-fs.sh

# Variable FileSet-Definition
#

Parameters:

%name - name of the machine to be backed up

%compression - leave blank or set to 'compression = gzip'

%mac - leave blank or set to 'hfsplussupport = yes'

%os - set mac or linux or windows

FileSet { Name = "%name-set" Include { Options { signature = MD5 %compression %mac } File = / %extrafiles } Exclude { @/etc/bacula/default-fs-excludes-%os.inc } }

Da die Konfiguration des Filesets etwas umfangreicher werden kann, habe ich sie in den meisten Fällen im gewohnten Format gelassen. Allerdings konnte ich die Hälfte der Konfigurationen abstrahieren, auch wenn das aufwändiger ist als bisher. Damit die Zeilen nicht so lang werden, habe ich folgendes Script dazu gebaut:

#!/bin/sh

Returns a default FileSet-resource

Syntax: default-fs.sh <name> <os> [compression] [extra-files]

[ "${2}" = "mac" ] && mac="hfsplussupport = yes" [ ! -z "${3}" -a "${3}" = "yes" ] && comp="compression = gzip" extra=${@:4} sed "s/%name/${1}/g;s/%compression/${comp}/g;s/%mac/${mac}/g;s/%os/${2}/g;s/%extrafiles/${extra}/g" /etc/bacula/default-fs.inc

Eingebunden wird das Script folgendermaßen:

@"|/etc/bacula/default-fs.sh ibook mac yes"
@"|/etc/bacula/default-fs.sh tv linux yes"
@"|/etc/bacula/default-fs.sh fs linux"