Guten Tag, Habr!
Aufgabe
Meine Organisation verwendet einen Mailserver auf der Kerio Connect-Plattform. In verschiedenen Städten werden Mailserver installiert, um die Benutzer zu bedienen. Eine verteilte Struktur gab es zunächst nicht, da sich die Domänen bereits auf der dritten Ebene unterschieden und die Stadt des Standortes angeben. Alles hat geklappt und alle waren zufrieden. Eines schönen Tages stellte das Management eine Aufgabe: einen gemeinsamen Aktivitätenkalender für alle Standorte!
Vorgeschichte
Ursprünglich bestand die Idee darin, eine Kerio Distributed Mail Domain einzurichten, die alles selbst erledigen würde. Gesagt, getan: Die verteilte Domäne wurde erstellt, aber sie war nicht vorhanden. Der Server war bereit, Kalender, Ordner und Kontakte zwischen Domänen auf einem Server zu synchronisieren, aber er hatte überhaupt nicht vor, Daten zwischen mehreren Servern zu synchronisieren.
Natürlich hatte ich mit einem solchen Haken nicht gerechnet und konnte lange Zeit nicht glauben, dass die Funktionalität, die ich brauchte, fehlte. Später fand ich dokumentarische Beweise für diese Tatsache. Das hat mich sehr verwirrt und enttäuscht.
Aus der Aufgabe wurde schnell ein Problem.
Welche Möglichkeiten gab es?
- Erstellen Sie zwei Clients auf unterschiedlichen Servern, die die erforderlichen Daten mithilfe von Drittanbietersoftware austauschen. Es war notwendig, diese Drittanbietersoftware zu finden, die diese Funktionalität implementieren würde – ich mag solche Rechen nicht, aber es schien, dass dies die einzige schnelle Lösung war.
- Schreiben Sie Ihr eigenes Skript, um Daten zwischen Servern zu synchronisieren. Die Sache ist, dass Kerio jedes Objekt als separate Datei speichert, sodass es notwendig war, ein Skript für die Arbeit mit Dateien zu entwickeln, aber angesichts der ausreichenden Anzahl von Quellen schien die Aufgabe etwas kompliziert, insbesondere da es notwendig war, mehrere Prüfungen der Richtigkeit der Daten durchzuführen, plötzlich würde jemand im gleichen Zeitraum eine Aufgabe erstellen usw.
Mit Blick auf die Zukunft möchte ich sagen, dass Kerio das Objekt zwar als separate Datei speichert, aber nicht so dumm ist, bei jedem Zugriff auf das Objekt nachzufragen, wie es dem Dateisystem geht.
Nachdem ich lange nachgedacht und einen Stapel Papiere mit Plänen zur „Eroberung feindlichen Territoriums“ erstellt hatte, traf ich um 6 Uhr morgens zwei richtige Entscheidungen:
- Die erste Entscheidung besteht darin, Ihr eigenes Ding zu machen und nicht nach etwas anderem zu suchen.
- Die zweite Lösung besteht darin, ins Bett zu gehen.
Schon am Morgen wachte ich mit einem einzigen und wahren Gedanken auf, der auf ein paar Buchstaben reduziert war - DFS
Lösung
Die Lösung selbst sah folgendermaßen aus:
- Bringen Sie alle Server, die an der Synchronisierung teilnehmen sollen, zum Betriebssystem. Windows(Teil war auf Linux(Die Migration der E-Mail-Daten auf ein anderes Betriebssystem war erforderlich.)
- Entscheiden Sie sich für die Struktur der Verzeichnisse, die an der Synchronisierung teilnehmen sollen – sie müssen identisch sein.
- Definieren Sie alle Mailserver unter einer Domäne mit einem einzigen DFS-Bereich.
- Erstellen Sie die oben erwähnte verteilte Kerio-Domäne, da in meinem Fall eine Datensynchronisierung erforderlich ist, nicht nur zwischen Servern, sondern auch zwischen Domänen. Letzteres kann vom Kerio-Server selbst übernommen werden. (im Gegensatz zum ersten)
- Stellen Sie synchronisierte Verzeichnisse auf den DFS-Speicherplatz ein.
- Überlegen Sie sich eine Art Krücke (schließlich geht es nicht ohne Krücke)
Implementierung
Beispiel auf zwei Mailservern (vielleicht mehr)
1. Kerio Verteilte Domäne

Der Master nimmt nicht an der Synchronisierung teil, dies ist jedoch keine zwingende Voraussetzung.
Ich werde nicht beschreiben, wie man eine verteilte Kerio-Domäne einrichtet, es ist nichts Kompliziertes daran, Sie können die offizielle
Abschließend sollten Sie folgendes Bild in der Administrationskonsole sehen:
![]()

Als nächstes interessierte ich mich für freigegebene Ordner; Auf dem Masterserver können Sie die folgenden Optionen angeben:
![]()

Spezifisch für jede Domäne - Der Server synchronisiert keine öffentlichen Ordner zwischen Domänen
Gemeinsam für alle Domänen - Alle Server geben vorhandene öffentliche Ordner in jeder Domäne auf und erstellen auf jedem Mailserver neue einheitliche Ordner für alle Domänen.
Achtung! Obwohl diese Option die Einstellungsrichtlinie auf allen Servern ändert, führt sie die Synchronisierung separat von jedem Server aus (d. h. ohne einen einzigen gemeinsamen Bereich).
Der Administrator hat weiterhin die Möglichkeit, den Zugriff zwischen Benutzern zu verteilen.
in meinem Fall – alle meine und ich benötigen eine vollständige Synchronisierung (in Ihrem Fall kann die Lösung anders sein). Auf jedem Server müssen Sie dieselben Domänensätze erstellen, die synchronisiert werden müssen.
2. Kerio-Datenverzeichnisse
Jetzt müssen Sie identische freigegebene Verzeichnisse erstellen, die auf jedem Server synchronisiert werden müssen. Ordner, Kalender, Kontakte.
Tipp: Erstellen Sie Verzeichnisse auf Englisch. Wenn Sie sie auf Latein erstellen, hat das Verzeichnis einen Namen in einer unverständlichen Kodierung, was zumindest unpraktisch ist.
Jetzt müssen wir die physischen Pfade der E-Mail-Ordner auf jedem Server finden.
Gemeinsam für alle Domänen ~DataMailmail#publicСинхронизируемый каталог#msgs
Spezifisch für jede Domäne ~DataMailmail**Domain**#publicСинхронизируемый каталог#msgs
Bitte beachten Sie, dass wir nicht das gesamte Verzeichnis synchronisieren, sondern nur den Container mit Daten. #Nachrichten — die Objekte selbst werden hier gespeichert, alle anderen Daten müssen für jeden Server eigene sein.
3. DFS
Ich werde nicht im Detail beschreiben, wie DFS konfiguriert wird, es gibt zu diesem Thema genügend Informationen.
DFS ist ein Rollendienst in Windows Server, wodurch die Möglichkeit geboten wird, freigegebene Ordner auf verschiedenen Servern zusammenzuführen.
Bevor Sie DFS einrichten, müssen Sie alle Mailserver stoppen, die an der Datensynchronisierung teilnehmen.
Sobald die Einrichtung abgeschlossen ist, sollten Sie für jeden der synchronisierten Ordner das folgende Bild erhalten.

Natürlich müssen wir replizierte Ordner nicht veröffentlichen.

Nachdem die Replikation erfolgt ist (und es dort nicht viel zu replizieren gibt – die Ordner sind leer), können die Mailserver gestartet werden.
Als nächstes können Sie einen der Mailserver mit Daten füllen und überprüfen, ob die Daten korrekt repliziert werden.
4. Krücke
Beschreibung der Reflexion
Wie Sie sehen, wird nach dem Start der Datensynchronisierung (DFS) auf dem zweiten Server etwas, das Sie auf dem ersten Server erstellt haben, irgendwie nicht angezeigt oder es wird angezeigt, aber irgendwie nicht immer.
Es besteht kein Grund zur Verzweiflung, natürlich wird es früher oder später dort erscheinen, aber besser früher als zu spät. Denn spät ist nach 6-12 Stunden.
Der springende Punkt ist, dass sobald man auf dem ersten Server etwas anlegt, die Datei dank des DFS-Systems natürlich sofort auch auf dem zweiten und den weiteren Servern erscheint, aber wenn dieses Mailverzeichnis schon einmal von jemandem gelesen wurde und es erneut angefordert wird, liest der Server den Ordner #msgs nicht erneut, sondern spuckt Daten aus seinem eigenen Index aus, die dann möglicherweise nicht mehr unserer Realität entsprechen.
Kerio verfügt über einen Mechanismus zum erneuten Lesen des Index, es kann jedoch bis zu sechs Stunden dauern, bis dieser funktioniert, und während dieser sechs Stunden kann die Relevanz der Aufgabe im Kalender etwas verloren gehen.
Um die Synchronisierung gleich zu überprüfen, können Sie die Datei index.fld im entsprechenden synchronisierten Verzeichnis löschen. Nach einem erneuten Zugriff auf den Ordner auf dem Mailserver und bei Fehlen dieser Datei liest Kerio das Verzeichnis erneut ein und die Daten werden angezeigt. Es scheint, dass dies die Lösung ist: Löschen Sie die Datei, wenn sich die Daten ändern. Dies funktioniert jedoch nicht jedes Mal, nur beim ersten Mal. Dann verliert Kerio aus irgendeinem Grund jegliches Interesse an index.fld
Und es fängt auch an, für den Benutzer unverständliche Nachrichten auszuspucken – über irgendeinen Index und dass er dort bereits etwas tut.
Es gibt noch eine andere Möglichkeit, etwas zu erstellen: Beim Erstellen eines neuen Objekts erkennt der Server plötzlich, dass der Dateiname, den er zuweisen wollte, bereits vergeben ist. Doch dann kommt es zu einem Lawinenausbruch, und dies ist eine Sackgasse.
Wie kann das sein?
Schauen wir uns das uns bereits bekannte Bild noch einmal an.

Aber auf einer anderen Ebene können Sie jetzt einen sehr interessanten und notwendigen Knopf für uns bemerken - Ordner neu indizieren
Und tatsächlich. Wenn wir auf einem Mailserver, der nicht weiß, dass sich in den synchronisierten #msgs bereits etwas geändert hat, auf diese Schaltfläche klicken, erhalten wir ein stabiles, schnelles Ergebnis. Alles Verborgene wird klar.
Im Log kannst Du sehen wie lange dieser Vorgang dauert, bei mir mit mehreren tausend (15 Tausend) Datensätzen ca. 3-4 Minuten.
Jetzt müssen wir nur noch herausfinden, wie wir diesen Knopf tatsächlich drücken können, wenn wir ihn brauchen.
Es stellt sich heraus, dass Kerio haben ihr eigenes API
Die Funktion, die unsere Aufgabe ausführt, sieht folgendermaßen aus –
session = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)
Aus all dem oben Genannten müssen wir ein Skript schreiben, das den Status der betreffenden Ordner überwacht und, falls sich etwas geändert hat, die von uns benötigte Funktion ausführt.
Ich möchte sagen, dass ich mehrere verschiedene Versionen von Skripten geschrieben habe, die unterschiedliche Prüfungen durchführen, und mich für die Version entschieden habe, die alle Schlussfolgerungen auf der Grundlage der Anzahl der Dateien erstellt.
Skriptimplementierung
CMD-Skriptbeispiel und Beschreibung
Re-index.bat
@echo off
set dir=%~dp0
%dir:~0,2%
CD "%~dp0"
md "%CD%LOG"
md "%CD%Setup"
ECHO -Start- >> "%CD%LOG%Computername%.log"
ECHO Start -> %Computername% %Date% %Time% >> "%CD%LOG%Computername%.log"
SetLocal EnableDelayedExpansion
for /f "UseBackQ Delims=" %%A IN ("%CD%Setup%Computername%.List") do (
set /a c+=1
set "m!c!=%%A"
)
set d=%c%
Echo Folder = %c%
ECHO Folder = %c% >> "%CD%LOG%Computername%.log"
ECHO.
ECHO. >> "%CD%LOG%Computername%.log"
:start
cls
if %c% LSS 1 exit
set /a id=1
set R=0
:Find
REM PF-Start
if "%id%" gtr "%c%" if %R% == 1 Goto Reindex
if "%id%" gtr "%c%" timeout 60 && Goto start
For /F "tokens=1-3" %%a IN ('Dir "!m%id%!#msgs" /-C/S/A:-D') Do Set 2DirSize!id!=!DS!& Set DS=%%c
if "2DirSize!id!" == "" set 1DirSize!id!=!2DirSize%id%!
echo %id%
ECHO !m%id%!
echo Count [ !1DirSize%id%! -- !2DirSize%id%! ]
if "!1DirSize%id%!" == "!2DirSize%id%!" ECHO Synk
REM DEL index.fld
if "!1DirSize%id%!" NEQ "!2DirSize%id%!" del /f /q !m%id%!index.fld && del /f /q !m%id%!indexlog.fld && del /f /q !m%id%!search.fld && set R=1 && ECHO RE-index Count && ECHO RE-index Count %Date% %Time% - Delete !m%id%! >> "%CD%LOG%Computername%.log"
set 1DirSize!id!=!2DirSize%id%!
ECHO.
ECHO.
set /a id+=1
goto Find
:Reindex
ECHO. >> "%CD%LOG%Computername%.log"
ECHO --- RE-INDEX - Start - %Date% %Time% --- >> "%CD%LOG%Computername%.log"
ECHO. >> ----------------------------------- >> "%CD%LOG%Computername%.log"
call PublicFolders.py
timeout 60
goto start
exit
Auf jedem Mailserver wird eine Kopie des Skripts gestartet (kann als Dienst erfolgen, Administratorrechte sind nicht erforderlich)
Das Skript liest die Datei Setup%Computername%.List
Dabei ist %Computername% der Name des aktuellen Servers (Das Verzeichnis kann Listen aller Server gleichzeitig enthalten.)
Die Datei %Computername%.List enthält die vollständigen Pfade der synchronisierten Verzeichnisse. Jeder Pfad wird in eine neue Zeile geschrieben und sollte keine Leerzeilen enthalten.
Nach dem ersten Start führt das Skript den Indizierungsvorgang durch, unabhängig davon, ob dies erforderlich ist oder nicht, und das Skript erstellt auch einen Index der Anzahl der Dateien in jedem synchronisierten Verzeichnis.
Die Aufgabe des Skripts besteht darin, alle Dateien im angegebenen Verzeichnis zu zählen.
Wenn am Ende der Zählung jedes Verzeichnisses mindestens in einem Verzeichnis der aktuelle Dateiwert nicht mit dem vorherigen übereinstimmt, löscht das Skript Dateien aus dem Stammverzeichnis des synchronisierten E-Mail-Verzeichnisses: index.fld, indexlog.fld, search.fld und startet den Indizierungsprozess – freigegebene E-Mail-Ordner.
Informationen zur Aufgabenausführung werden in das LOG-Verzeichnis geschrieben.
Indexierungsprozess
Der Indizierungsprozess wird auf die Ausführung der Kerio-API-Funktion reduziert
Sitzung = Aufrufmethode("Domains.checkPublicFoldersIntegrity",{}, Token)
Ein Beispiel für die Ausführung finden Sie in – Python
Öffentliche Ordner.py
import json
import urllib.request
import http.cookiejar
""" Cookie storage is necessary for session handling """
jar = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
urllib.request.install_opener(opener)
""" Hostname or ip address of your Kerio Control instance with protocol, port and credentials """
server = "http://127.0.0.1:4040"
username = "user"
password = "password"
def callMethod(method, params, token = None):
"""
Remotely calls given method with given params.
:param: method string with fully qualified method name
:param: params dict with parameters of remotely called method
:param: token CSRF token is always required except login method. Use method "Session.login" to obtain this token.
"""
data = {"method": method ,"id":1, "jsonrpc":"2.0", "params": params}
req = urllib.request.Request(url = server + '/admin/api/jsonrpc/')
req.add_header('Content-Type', 'application/json')
if (token is not None):
req.add_header('X-Token', token)
httpResponse = urllib.request.urlopen(req, json.dumps(data).encode())
if (httpResponse.status == 200):
body = httpResponse.read().decode()
return json.loads(body)
session = callMethod("Session.login", {"userName":username, "password":password, "application":{"vendor":"Kerio", "name":"Control Api-Local", "version":"Python"}})
token = session["result"]["token"]
print (session)
session = callMethod("Domains.checkPublicFoldersIntegrity",{"domainId": "test2.local"}, token)
print (session)
callMethod("Session.logout",{}, token)
Sie können es so lassen, wie es ist, aber wenn Sie HTTPS benötigen, muss Python dem Kerio-Zertifikat vertrauen.
Außerdem muss in der Datei ein Konto mit Rechten zum Ausführen dieser Funktion (Adm – gemeinsame E-Mail-Ordner) des Mailservers angegeben werden.
Ich hoffe, dass mein Artikel für Kerio Connect-Administratoren nützlich ist.
Source: habr.com
