ZFS: Automatische Replikation via ssh

Ich habe das ZYNK-Script von Ben Rockwood dahingehend angepasst, dass es einen ZFS-Dataset vollständig (d. h. rekursiv, inklusive aller abhängigen Dateisysteme und Snapshots) auf einen Backup-Server repliziert. Das Script wird einmal am Tag via crontab aufgerufen, so dass die Daten der letzten Nacht auf dem Backup-Server zur Verfügung stehen. Es kann durchaus häufiger aufgerufen werden (jede Stunde oder auch mehrmals pro Stunde). Hier erst einmal das Skript:

#!/bin/bash
## ZYNK: The Zuper Zimple ZFS Sync (Replication) Tool
## Form: zynk local/dataset root@remote.host destination/dataset

# Please note: The reason this is so simple is because there is no error checking, reporting, or cleanup.
#               In the event that something goes wonkey, you'll manually need to fix the snapshots and
#               modify or remote the /var/run/zynk datafile which contains the most recent snapshot name.
# Furthermore, this absolutely relies on the GNU version of 'date' in order to get epoch time
# Before using, make sure you've distributed your SSH key to the remote host and can ssh without password.

if [ ! $3 ] 
then
        echo "Usage: zynk local/dataset root@remote.host destination/dataset"
        echo "WARNING: The destination is the full path for the remote dataset, not the prefix dataset stub."
        exit
fi

DATE=`date +%s`
if [ $DATE == "%s" ]
then
        echo "Must use GNU Date, please install and modify script."
        exit
fi

if [ -e /var/run/zynk ] 
then
        # Datafile is found, creating incr.
        echo "Incremental started at `date`"
        zfs snapshot -r ${1}@zynk-${DATE}
        zfs send -RI  ${1}@zynk-`cat /var/run/zynk` ${1}@zynk-${DATE} | ssh ${2} zfs recv -Fd ${3}
        zfs destroy -r ${1}@zynk-`cat /var/run/zynk`
        ssh ${2} zfs destroy -r ${3}@zynk-`cat /var/run/zynk`
        echo ${DATE} > /var/run/zynk
        echo "Incremental complete at `date`"
else 
        # Datafile not found, creating full.
        echo "Full started at `date`"
        zfs snapshot -r ${1}@zynk-${DATE}
        zfs send -R     ${1}@zynk-${DATE} | ssh ${2} zfs recv -Fd ${3}
        echo ${DATE} > /var/run/zynk
        echo "Full completed at `date`"
fi

In diesem Szenario soll tank/export vom Server (rubin) nach rpool/export auf dem Backup-Server (onyx) repliziert werden. Beide Systeme laufen mit OpenIndiana build 151a7. Das ZYNK-Skript liegt auf rubin unter /usr/bin/zynk. Der initiale Aufruf sieht wie folgt aus und dauerte hier mehrere Stunden (für 406 GB):

root@rubin:~# rm /var/run/zynk
root@rubin:~# zync tank/export onyx rpool
Full started at 20. November 2012 15:21:09 CET
Full completed at 21. November 2012 04:35:42 CET

Nach diesem ‘Full Backup’ sind die inkrementellen Sicherungen schnell erledigt, da nur noch die Dateisystemänderungen (lies: Snapshots) gesendet werden, die seit dem letzten ZYNK-Aufruf angefallen sind:

root@rubin:~# zynk tank/export onyx rpool
Incremental started at 21. November 2012 13:39:24 CET
Incremental complete at 21. November 2012 13:48:11 CET

Um ZYNK jeden Tag um 2:00 Uhr automatisch aufzurufen, muss schließlich folgende Zeile in die root-crontab (crontab -e) eingetragen werden:

0  2 * * * /usr/bin/zynk tank/export onyx rpool

Das Skript setzt voraus, dass ein passwortloses (ssh-key-basiertes) root-Login möglich ist. Es empfiehlt sich allerdings einen dediziert zynk-Account mit entsprechenden Attributen zu benutzen. Wie schon dem Originalskript von Ben Rockwood, fehlt auch dieser Version jegliche Fehlerprüfung oder -behandlung.

Postfix und zusätzliche Domains

Immer wenn ein Mailserver ausfällt und ein anderer dessen Aufgaben mit übernehmen soll, sitze ich vor dieser doofen Posftfix-Konfigurationsdatei und frage mich, an welchen Stellen ich den zusätzlichen Hostnamen noch eintragen soll. Jetzt schreib’ ich es einmal auf:  ($IP ist die Adresse des ausgefallenen Servers, $NAME ist sein fully qualified domain name (fqdn). Ich habe es mir zu Angewohnheit gemacht, die IP-Adresse des aufgefallenen Servers auf den Backup-Server zu übertragen, bis dieser wieder einsatzbereit ist.)

  1. IP an Interface anhängen
    # ip addr add $IP dev eth0
  2. /etc/postfix/main.cf editieren
    [...]
    inet_interfaces = $myhostname, localhost, $NAME
    [...]
    mydestination = $myhostname, localhost.$mydomain, localhost, $NAME
    [...]
  3. /etc/init.d/postfix stop
  4. /etc/init.d/postfix start

Das stop-start-Prozedere ist wichtig. Ein einfaches reload reicht nicht aus, restart sollte aber auch gehen.

Shadow-Passwords erzeugen

Verschlüsselte Passwörter, wie sie in /etc/shadow gespeichert werden, kann man mit der folgenden Zeile für das Passwort password erzeugen:

# echo "password" | openssl passwd -1 -stdin $1$YFi.APLv$VZiopcJ9udPYifg/4E7vo/ 

Die Option -1 steht für den zu benutzenden MD5-Algorithmus. Die Ausgabe kann via Copy-Paste für den Benutzer USERNAME in die /etc/shadow eingefügt werden.

USERNAME:$1$YFi.APLv$VZiopcJ9udPYifg/4E7vo/:15132::::::

Diese Vorgehensweise ist dann nützlich, wenn man nicht auf Tools wie adduser oder useradd zurückgreifen kann oder will, weil beispielsweise separate passwd/shadow files für einen NIS-Server gepflegt werden. Zum Anlegen eines neuen Benutzers USERNAME muss noch eine Zeile wie die folgende zu /etc/passwd hinzugefügt werden:

USERNAME:x:541:100:Vorname Nachname (Kommentar):/home/USERNAME:/bin/bash

wobei 514 die userID und 100 die groupID des Benutzer sind.

Emacs: Sitzung sichern

Den Zustand des Emacs kann man durch den Aufruf

M-x desktop-save

einfrieren. Hierbei werden alle Buffer, deren Dateinamen, major modes und Positionen gesichert (M-x heißt meistens Alt-x bzw. -x auf dem Mac). Wenn man nach dem Verzeichnis gefragt wird, gibt man am besten sein Home (~/) an. Hier wird eine Datei namens .emacs.desktop.lock angelegt.

Nach einem Neustart des Emacs kann man nun mit

M-x desktop-revert

den vorher gespeicherten Zustand wiederherstellen. Sollte Emacs kein Desktopfile finden kann, muss man mit

M-x desktop-change-dir

das korrekte Verzeichnis angeben. Wer dieses Verhalten grundsätzlich wünscht (also speichern der Sitzung beim beenden und automatisches Laden der letzten Sitzung beim Start von Emacs) trägt ins Initfile (~/.emacs) folgende Zeile ein:

 (desktop-save-mode 1)
Wenn kein Desktop wiederhergestellt werden soll, kann man Emacs mit der Option --no-desktop starten.

Emacs twittering-mode aufhübschen

Hier nur eine kleine Anregung zur Formatierung der Timeline des Emacs twittering-modes: Diese wird über die Variable twittering-status-format kontrolliert. Folgende Zeile in ~/.emacs einfügen und schon wirkt die Timeline aufgeräumter und lesbarer:

(setq twittering-status-format "%i %FACE[bold]{%S} %FACE[shadow]{@%s}\n%FOLD[  ]{%t\n%FACE[shadow]{%RT{Retweeted by @%s} %@}}\n")

%i steht für Avatar-Icon und kann in der Timeline optional mit i ein- und ausgeschaltet werden oder durch setzen von

(setq twittering-icon-mode t)

dauerhaft aktiviert werden. (Ich bevorzuge die Timeline ohne Bilder – siehe Screenshot). Hier noch ein Listing aller Formatierungsanweisungen aus dem Quellcode:

%s - screen_name
%S - name
%i - profile_image
%d - description
%l - location
%L - \" [location]\"
%r - \" sent to user\" (use on direct_messages{,_sent})
%r - \" in reply to user\" (use on other standard timeline)
%R - \" (retweeted by user)\"
%RT{...} - strings rendered only when the tweet is a retweet.
 The braced strings are rendered with the information of the
 retweet itself instead of that of the retweeted original tweet.
 For example, %s for a retweet means who posted the original
 tweet, but %RT{%s} means who retweeted it.
%u - url
%j - user.id
%p - protected?
%c - created_at (raw UTC string)
%C{time-format-str} - created_at (formatted with time-format-str)
%@ - X seconds ago
%T - raw text
%t - text filled as one paragraph
%' - truncated
%FACE[face-name]{...} - strings decorated with the specified face.
%FILL[prefix]{...} - strings filled as a paragraph. The prefix is optional.
You can use any other specifiers in braces.
%FOLD[prefix]{...} - strings folded within the frame width.
 The prefix is optional. This keeps newlines and does not
 squeeze a series of white spaces.
 You can use any other specifiers in braces.
%f - source
%# - id

Emacs twittering-mode

An Twitter-Clients für Linux mangelt es eigentlich nicht. Wer aber schon immer gern einen Command-Line-Client haben wollte, oder beim täglichen arbeiten den Emacs ungern verlässt, dem sei twittering-mode (twmode) empfohlen. Ich will die Installation unter Linux (Scientific Linux 6.2) kurz umreißen (sollte auf dem Mac ähnlich funktionieren; unter Windows muss man auf die mitgelieferten Command-Line-Tools zurückgreifen):

Voraussetzungen:

Als erstes die benötigten Abhängigkeiten (Emacs-23 *lol*, curl, wget, gnutls-utils, openssl, gnupg) installieren. Weiterhin wird ein Webbrowser gebraucht — Auf dem Desktop sicher kein Problem; auf der Konsole empfiehlt sich w3m mit w3m.el. Folgender Befehl installiert die Abhängigkeiten unter RHEL 6

# yum install emacs curl wget gnutls-utils openssl gnupg2

Wenn twittering-mode vom Github-Repository installiert werden soll (was ich empfehle), muss ausserdem Git installiert werden:

# yum install git

Installation

Es empfiehlt sich Emacserweiterungen nach ~/.emacs.d zu installieren, was im folgenden auch beherzigt werden soll.

$ cd ~/.emacs.d
$ git clone git://github.com/hayamiz/twittering-mode.git

Zur Emacs-Konfigurationsdatei ~/.emacs muss folgendes hinzugefügt werden:

(add-to-list 'load-path "~/.emacs.d/twittering-mode")
(require 'twittering-mode)

Jetzt Emacs starten und den Twittering-Mode mit M+x twit[1] starten. TWmode meldet sich mit Authorization via OAuth.

Wer browse-url-generic-program in der Emacskonfiguration gesetzt hat, kann hier y drücken, ansonsten n drücken und den Link unter 1. anklicken oder via Copypaste im Browser der Wahl öffnen. Den angezeigten PIN-Code in den Emacs-Minibuffer eingeben und los geht’s mit Twitter im Emacs:

Dauerhafte Authorisierung:

Um nicht bei jedem Start von twmode erneut gegen Twitter autorisieren zu müssen, kann man folgende Zeilen in die Emacskonfiguration ~/.emacs aufnehmen:

(require 'epa-file)
(epa-file-enable)
(setq twittering-use-master-password t)

Hierzu wird GnuPG und EasyPG benötigt. Zumindest letzteres ist in Emacs 23 standardmäßig integeriert und kann durch die beiden führenden Zeilen im obigen Listing aktiviert werden [Update: Für Emacs 23 werden die zwei führenden Zeilen nicht benötigt — Sie schaden aber auch nicht. Dank an @cvmat]. Der oauth-access-token wird verschlüsselt unter ~/.twittering-mode.gpg gespeichert. Beim Start von twmode fragt pinentry die Passphrase zum Tokenfile ab und erlaubt hiermit die automatische Authorisierung gegen Twitter.

Wichtige Kommandos:

u
Neuer Tweet
d
Neue Direct Message
Enter
Reply
F4
URL Verkürzung via tinyurl
C-c Enter
Retweet mit Zitat
C-u C-c Enter
Retweet
g
Timeline aktualisieren
g
Timeline aktualisieren
f
Timelines durchblättern
V
Beliebige Timeline
L
Timeline beliebiger Liste
C-c C-u
Eigene Timeline
C-c C-f
Following Timeline
C-c C-r
Reply Timeline (Antworten auf eigene Tweets)
C-c C-d
Direct Messages Timeline

C bedeutet Control. Zum Suchen von Begriffen in Tweets öffnet man eine neue Timeline (V) mit :search/SUCHBEGRIFF/.

[1] M+x bedeutet Meta und x gleichzeitig drücken. Meta ist auf PC-Tastaturen meistens auf der Alt und auf Mac-Tastauren auf cmd. In jedem Fall sollte die Tastenfolge Esc, x (nacheinander) funktionieren.

Automatischer Neustart eines Jobs bei Absturz

Manchmal hat man Jobs die einfach nur laufen müssen (z. b. NIS Server, Name Server). Und wenn sie einmal abstürzen, interessiert mich erst einmal gar nicht das Warum. Vielmehr möchte ich das der Jobs einfach wieder los läuft – Am besten von allein. Die näheren Umstände des Absturzes kann ich ja später noch anhand des Logfiles untersuchen. Unter Solaris gibt es hierzu die Service Management Facility (SMF), die sicher stellt, dass Systemdienste laufen und nötigenfalls auch einen (oder mehrere) Neustart(s) des Dienstes versucht, falls dieser abstürzen sollte. Unter Linux habe ich noch kein Äquivalent dazu gefunden. Eine brutale Methode einen Job bei gelegentlichen Abstürzen automatisch erneut zu starten, ist, ihn in einer Endlosschleife aufzurufen:

while true; do ./jobs.sh; done

Diese Methode geht allerdings nach hinten los, falls jobs.sh ein ernsthaftes Problem hat und sofort nach dem Start wieder terminiert. Zur Sicherheit sollte man also die Neustartorgie durch einen Zähler begrenzen, z. B. auf 1000 Versuche:

for i in {1..1000}; do ./jobs.sh; done

Das ist nicht elegant, hilft aber gelegentlich abstürzende Programme am Laufen zu halten.  Ist der kritische Zählerstand erreicht, wird nicht weiter versucht den Job neu zu starten. Man kann sich hierüber z. B. per Mail an root an  informieren lassen:

for i in {1..1000}; do ./jobs.sh; done ; echo "Message" | mail -s "Job died." root

Natürliche Mausrad-Scroll-Richtung unter Xorg

Apple hat ja mit der Einführung von Mac OS X 10.7 Lion die Scroll-Richtung der Maus kurzerhand umgekehrt. Nach anfänglichem Schock habe ich dieses Verhalten mittlerweile liebgewonnen; Möglicherweise beeinflusst durch Mobilgeräte mit der selben Scroll-Logik. Das Problem stellte jetzt der Linuxrechner dar, dessen XServer standardgemäß der alten Logik gehorcht. Es gibt (wie immer) mehrere Möglichkeiten dieses Verhalten zu beeinflussen, wie z. B. die xorg.conf editieren. Dies hätte allerdings Einfluss auf alle Nutzer eines Rechners und ist meistens nicht gewünscht. Am Einfachsten scheint es mir, folgende Zeile

pointer = 1 2 3 5 4

in die Datei ~/.Xmodmap im Homeverzeichnis des Nutzers einzutragen. Hierbei wird die Standardzuordnung des Mausrades (Button 4: nach oben, Button 5: nach unten) umgekehrt. Anschließend xmodmap ~/.Xmodmap ausführen und die neue Scroll-Logik genießen. Alternatives ab- und wieder anmelden lädt die Konfiguration ebenfalls neu.

Wem dieses Verhalten unter Mac OS X Lion nicht gefällt, kann es unter Systemeinstellungen»Maus ändern: bei Verwendung einer Magic Mouse das Häkchen bei „Scrollrichtung: Natürlich“ entfernen oder bei Verwendung einer generischen Maus „Beim Scrollen oder Navigieren in Bewegungsrichtung der Finger bewegen“ deaktivieren.

Umlaute und US-Tastaturlayout

Ich liebe das US-Tastaturlayout, weil es das Programmieren durch intelligente Anordnung der Klammern ([], {}, <>) enorm erleichtert. Außerdem gibt es hier keine Tottasten. (Wozu sind die überhaupt gut?) Andererseits vermisse ich beim Verfassen deutscher Texte die Umlaute und das ß. Die ausgeschriebenen Ligaturen ae, oe, ue finde ich nicht besondern attraktiv und &uuml; im HTML-Code bzw. \"u im LaTeX-Code erschweren die Lesbarkeit beim schreiben und behindern die automatische Rechtschreibkontrolle.

Die Firma Apple hat für seine Mac OS X-Systeme einen eleganten Weg gefunden Umlaute einzugeben: Die Tastenkombination alt+u gefolgt von {a,o,u,A,O,U} erzeugt den entsprechenden deutschen Umlaut und alt+s erzeugt ein ß.

Auf Linux-Systemen mit Xorg kann man ein ähnliches Verhalten erreichen, indem man z. B. die linke Windowstaste zusammen mit einem Buchstaben den Umlauten oder dem ß zuordnet. Man kann statt der linken Windowstaste auch jeden anderen modifier benutzen, den man im Normalfall nicht braucht. Mit dem kleinen Programm xev kann man die Keycodes der gewünschten Tasten ermitteln. Im unteren Code-Snippet habe ich die Konfiguration super_L+{a,A,o,O,u,U,s} festgehalten, die in die Datei .Xmodmap im Homeverzeichnis eingefügt werden muss. super_L ist die Bezeichnung für die linke Windowstaste unter Linux..

# ~/.Xmodmap
 keycode 133 = Mode_switch
 keycode 38 = a A adiaeresis Adiaeresis
 keycode 30 = u U udiaeresis Udiaeresis
 keycode 32 = o O odiaeresis Odiaeresis
 keycode 39 = s S ssharp

Um die Konfiguration zu laden muss noch xmodmap ~/.Xmodmap ausgeführt werden oder einfach vom System abmelden und wieder anmelden. Die Tastenkombinationen können zusätzlich mit gedrückter Shift-Taste verwendet werden, um große Umlaute zu erzeugen.

Zimbra LDAP error

Beim Start von Zimbra 7.1.1 unter CentOS 5.7 kommt es bisweilen zu Fehlern mit dem LDAP, die verhindern, dass Zimbra startet:

[root@zimbra ~]# /etc/init.d/zimbra restart
Host zimbra.frdom.local
Stopping stats...Done.
Stopping mta...Done.
Stopping spell...Done.
Stopping snmp...Done.
Stopping cbpolicyd...Done.
Stopping archiving...Done.
Stopping antivirus...Done.
Stopping antispam...Done.
Stopping imapproxy...Done.
Stopping memcached...Done.
Stopping mailbox...Done.
Stopping logger...Done.
Stopping zmconfigd...Done.
Stopping ldap...Done.
Host zimbra.frdom.local
Starting ldap...Done.
Failed.
Failed to start slapd. Attempting debug start to determine error.
bdb(): PANIC: fatal region error detected; run recovery
bdb_db_close: database "": txn_checkpoint failed: Invalid argument (22).
backend_startup_one (type=hdb, suffix=""): bi_db_open failed! (-30974)
bdb_db_close: database "": alock_close failed

Ich vermute, dass das mit Inkonsistenzen im LDAP zusammenhängt. Die Zimbra-Instanz läuft in einer VirtualBox auf OpenIndiana 151a und ich denke, dass der Fehler durch die Virtualisierung verursacht wird (möglicherweise Dateisystemprobleme auf dem Host oder Gastsystem oder Problem beim “sauberen” hoch- und runterfahren der VM). Ich hatte bisher nicht die Energie, die Zeit und den nötigen Durchblick, dass Problem zu analysieren. Deshalb hier erst einmal der Fix, der den LDAP repariert. Hat bis jetzt immer gut funktioniert (heilt evtl. auch andere LDAP-Datenbankfehler):

[root@zimbra ~]# su - zimbra
[zimbra@zimbra ~]$ cd /opt/zimbra/data/ldap/hdb/db
[zimbra@zimbra db]$ db_recover -v
Finding last valid log LSN: file: 4 offset 6038659
Recovery starting from [4][6038514]
Recovery complete at Tue Mar 6 16:43:08 2012
Maximum transaction ID 80000015 Recovery checkpoint [4][6038659]
[zimbra@zimbra db]$ logout

Wenn das geklappt hat kann Zimbra gestartet werden (habe hier restart benutzt):

root@zimbra ~]# /etc/init.d/zimbra restart
Host zimbra.frdom.local
Stopping stats...Done.
Stopping mta...Done.
Stopping spell...Done.
Stopping snmp...Done.
Stopping cbpolicyd...Done.
Stopping archiving...Done.
Stopping antivirus...Done.
Stopping antispam...Done.
Stopping imapproxy...Done.
Stopping memcached...Done.
Stopping mailbox...Done.
Stopping logger...Done.
Stopping zmconfigd...Done.
Stopping ldap...Done.
Host zimbra.frdom.local
Starting ldap...Done.
WARNING: Disk space below threshold for /opt/zimbra.
Starting zmconfigd...Done.
Starting logger...Done.
Starting mailbox...Done.
Starting memcached...Done.
Starting antispam...Done.
Starting antivirus...Done.
Starting snmp...Done.
Starting spell...Done.
Starting mta...Done.
Starting stats...Done.
[root@zimbra ~]# 

Et voila.