Zugriffsrechte auf geteilte Dateien und Ordner mit AFP und NAS4Free

FreeNAS 7 wird seit einiger Zeit nicht mehr unter diesem Namen weiterentwickelt. Das Projekt NAS4Free hat sich dem Sourcecode angenommen. Ich hatte zwar zwischenzeitlich einen Sprung auf FreeNAS 8 gewagt. Jedoch war ich von der Administrationsoberfläche und der Stabilität (zumindest auf meiner Hardware) nicht überzeugt.

Daher erfolgte am letzten Wochenende der Sprung zurück auf das ehemals FreeNAS 7 getaufte Projekt. Das Erkennen meines ZFS Pools machte keinerlei Schwierigkeiten. Mittels des Befehls zpool import 1 können spezifische Pools importiert werden. Vorteilhaft ist zuvor das Exportieren des Pools mit zpool export. Das hatte ich vergessen. Hat aber trotzdem funktioniert.

Das eigentliche Problem war im Anschluss das Bereitstellen und Teilen meiner ZFS Datasets über AFP zwischen verschiedenen Benutzern. Legt ein Benutzer A einen Ordner oder eine Datei an, der für das Teilen vorgesehen ist, kann ein zweiter Benutzer B nicht schreibend auf den Ordner zugreifen. Die voreingestellten Zugriffsrechte, die AFP nutzt, sehen dies nicht vor.

Die Dokumentation von netatalk beschreibt, wie man mit Hilfe der Parameter perm, dperm und fperm die Standardzugriffsrechte für neue Dateien und Ordner anpassen kann. Das geschieht in der Datei AppleVolumes.default, die unter NAS4Free unter /var/etc liegt. Leider bietet NAS4Free in der GUI keinerlei Einsellungsmöglichkeiten für die Zugriffsrechte. Ein manuelles Ändern der Zugriffsrechte in der Datei AppleVolumes.default ist möglich. Jedoch werden die Änderungen nach einem Neustart des AFP-Dienstes überschrieben.

Einen Workaround habe ich beim Probieren gefunden. In den Einstellungen eines AFP-Shares können am Ende des Eingabefeldes „Read/Write Access“ die benötigten Parameter angehangen werden. Diese werden in die AFP-Konfiguration übernommen. Wenn also Benutzer A, der einen Ordner oder eine Datei erstellt, und Benutzer B Zugriff auf den Ordner oder die Datei haben sollen, kann dies beispielsweise mit

Read/Write Access: userA,userB perm:0770

erreicht werden. Eine nicht besonders elegante Lösung. Sie funktioniert jedoch.

Homeserver: Backupstrategie #2

Im vorigen Beitrag habe ich meine Idee für ein Backup meiner Daten vorgestellt. Im Folgenden möchte ich die Shell-Skripte vorstellen, die die eigentliche Arbeit machen.

Insgesamt nutze ich vier Shell-Skripte:

  1. backup-rsync.sh
  2. backup-rotate-server.sh
  3. backup-rotate-client.sh
  4. backup-now.sh

Skript 1 wird mit der IP-Adresse meines Servers, dem über FreeNAS auf dem Server angelegtem RSync-Modul sowie dem Pfad auf meinem Macbook, der gesichert werden soll, aufgerufen. Die wichtigsten Zeilen in diesem Skript beziehen sich auf den Aufruf von RSync. Ich nutze RSync von den MacPorts. Diese Version ist neuer und soll mehr Features besitzen als die von Apple gelieferte.

$RSYNC -az --numeric-ids --delete --delete-excluded
      	     --exclude-from="$EXCLUDES" $EXTRAOPT	        
      	     $BACKUP_PATH $SERVER::$MODULE

RSync wird mit den obigen Zeilen mit den Optionen az (archive, compress) aufgerufen. Mit diesen Optionen wird RSync angewiesen möglichst alle Dateiattribute, wie Benutzer und Gruppe, sowie Links zu konservieren. Weiterhin soll der zu sichernde Ordner rekursiv verarbeitet und die Daten während der Übertragung komprimiert werden. Außerdem sollen irrelevante Dateien sowie auszuschließende Dateien (delete, delete-excluded) gelöscht werden. Mittels der Option exclude-from kann eine Datei angegeben werden, die eine Liste von Mustern auszuschließender Dateien und Ordnern enthält. So kann beispielsweise die allseits beliebte .DS_STORE Datei umgangen werden, die Mac OS X so gerne anlegt. Schließlich wird mit der Variable BACKUP_PATH das zu sichernde Verzeichnis und mit SERVER:MODULE der RSync-Server sowie das dort angelegte Modul übergeben.

Für meine Uni-Daten habe ich auf meinem Server mit ZFS ein File System angelegt. Das vereinfacht das sichern der Daten mit ZFS Bordmitteln (Stichwort: Snapshots). Skript 2 wird auf dem Server ausgeführt. Zunächst wird geprüft ob der höchste Snapshot existiert. Dazu nutze ich den Befehl zfs list -t snapshot. Falls er vorhanden ist, wird er gelöscht, denn ich möchte nur eine gewisse Anzahl von Backups halten. Das Löschen wird mit dem Befehl zfs destroy eingeleitet.

SNAP_REG="#$FILE_SYSTEM@weekly.3#!d"
CHECK_SNAP=`zfs list -t snapshot | sed -e "$SNAP_REG"`

if [ "$CHECK_SNAP" ] ; then
  zfs destroy $FILE_SYSTEM@weekly.3
fi

Anschließend werden alle anderen Snapshots um eine Nummer „nach oben geschoben“. Dazu werden sie mit dem Befehl zfs rename umbenannt.

for OLD in 2 1 0 ; do
  SNAP_REG="#$FILE_SYSTEM@weekly.$OLD#!d"
  CHECK_SNAP=`zfs list -t snapshot | sed -e "$SNAP_REG"`

  if [ "$CHECK_SNAP" ] ; then
    NEW=$[ $OLD + 1 ]
    zfs rename $FILE_SYSTEM@weekly.$OLD @weekly.$NEW
  fi
done

Schließlich wird ein aktueller Snapshot angelegt:

SNAP_REG="#$FILE_SYSTEM@weekly.0#!d"
CHECK_SNAP=`zfs list -t snapshot | sed -e "$SNAP_REG"`

if [ -z "$CHECK_SNAP" ] ; then
  zfs snapshot $FILE_SYSTEM@weekly.0
fi

Skript 3 dient dazu Skript 2 auf dem Server über SSH aufzurufen. Dazu werden dem Skript der Benutzer zum Einloggen sowie die IP-Adresse des Servers und das zu sichernde ZFS File System übergeben. Der Rest funktioniert wie auf der Konsole:

SSH_CMD="~/script/backup/backup-rotate-server.sh $ZFS_FILE_SYSTEM"

ssh $SSH_USER@$SSH_HOST "$SSH_CMD"

Den Kennern ist sicherlich aufgefallen, dass ich kein Passwort benötige um den Befehl auf dem Server auszuführen. Darauf gehe ich in einem weiteren Artikel ein.

Skript 4 schließlich ist der Einstiegspunkt für das Backup. In diesem Skript wird zunächst mit dem Befehl ping geprüft ob der Server erreichbar ist. Falls nicht wird sofort abgebrochen. Ansonsten werden nacheinander Skript 3 und Skript 1 aufgerufen.

Sicherlich gibt es an einigen Stellen (wie immer) Verbesserungsbedarf. Trotzdem bin ich mit der jetzigen Lösung zufrieden, lasse mich aber gerne belehren. :)
Für diejenigen, die Interesse haben, sind im Anschluss die Skripte verlinkt.

Homeserver: Backupstrategie #1

In den folgenden Artikeln möchte ich auf die Backuplösung eingehen, die ich mit Hilfe meines Servers umgesetzt habe. Für das Systembackup meines Macbooks nutze ich Timemachine. Mit der aktuellen FreeNAS Version lässt sich ein AFP-Share für Timemachine verfügbar machen. Das klappt bis jetzt wunderbar. Jedoch möchte ich mich gerade bei wirklich wichtigen Daten, wie meinen Daten fürs Studium, nicht auf eine nicht von Apple abgesegnete Lösung verlassen.

Deshalb wollte ich RSync nutzen. FreeNAS bieten einen RSync-Server an, mit dem ein definierbarer Bereich auf der Platte als sogenanntes Module freigegeben werden kann. So muss beim Aufruf von RSync nicht mit Verzeichnissen hantiert werden. Die Angabe des Modules reicht, die Daten landen im richtigen Verzeichnis.

Ein weiterer wichtiger Punkt war die Haltung von mehreren Versionen meiner Daten. Ich wollte jede Woche ein Backup meiner Daten anlegen, einen Monat lang. Danach sollten die vorhandenen Backups rotieren: das Älteste kommt weg, die anderen werden weiter nach hinten geschoben. Natürlich sollte nicht nur einfach kopiert werden, sondern mittels Hardlinks auf Daten verwiesen werden um Plattenplatz zu sparen. Für diesen Einsatz gibt es rsnapshot. Leider kann mit rsnapshot nicht auf einen entfernten (wenn bei mir auch zwei Meter hinter mir stehenden) Server gebackupped werden. Also fiel die Möglichkeit schonmal aus.

Das Rotieren musste nun also „von Hand“ geschehen. Dabei habe ich mich etwas inspirieren lassen. Diese Shell-Skripte backuppen entfernte Server auf einen lokalen Rechner. Dabei werden die Backups rotiert und eine gewisse Anzahl Backups vorgehalten. Also fast, was ich gesucht habe. Die Skripte habe ich großzügig an meine Bedürfnisse angepasst.

Timemachine macht Backups automatisch, wenn das Backup-Volume verfügbar ist. So ungefähr sollte das auch beim Backup meiner Uni-Daten passieren. Unter Linux würde man wohl einen Cronjob anlegen, unter Mac OS X gibt es launchd. Dieser Daemon wird beim Systemstart als zweiter Prozess gestartet (siehe Aktivitätsanzeige) und soll verschiedene bekannte Starter (init, crond, etc.) ablösen und deren Aufgaben vereinheitlichen. Als weiteres Schmankerl wird launchd mit XML-Dateien konfiguriert. Wem das zu unübersichtlich ist, kann sich mit Lingon behelfen. Einen kleinen Einstiegsartikel zu Lingon findet man auf Apfeltalk.

Meine erste Idee war, einen AFP-Share zu nutzen und für jede Version meiner Daten einen Ordner (wie weekly.0, weekly.1 etc.) anzulegen. Beim Rotieren dieser Versionen wollte ich mit cp und Hardlinks arbeiten. Leider funktionierte das auch mit der GNU-Version von cp (über Macports bezogen) nicht. Woran genau es lag, kann ich nicht sagen. Vielleicht war AFP Schuld, vielleicht auch ZFS. Aber Moment… ZFS! Mit ZFS kann man von einem File System ohne großen Aufwand einen Snapshot (also quasi ein zeitliches Abbild eines File Systems) anlegen. Das wollte ich letztendlich tun.

Die Umsetzung dieser Idee und die Probleme, auf die ich gestoßen bin, kommen im nächsten Artikel. Bis dahin schöne Feiertage und so. ;)