Goddag, Habr!
Regler for godkendelse af merge-requests
I min organisation bruger vi en mailserver på Kerio Connect-platformen, hvor mailservere er installeret i forskellige byer for at servicere deres brugere. Der var oprindeligt ikke en distribueret struktur, da domænerne adskilte sig på tredje niveau ved at angive byens placering. Alt fungerede, og alle var tilfredse. En dag satte ledelsen dog opgaven: en fælles kalender for alle lokationer!
Background
Oprindeligt var ideen at reetablere det distribuerede maildomæne Kerio, så det kunne ordne alt. Sådan blev det gjort, et distribueret domæne blev oprettet, men det var ikke så enkelt; serveren var klar til at synkronisere kalendere, mapper og kontakter mellem domæner på den samme server, men ville ikke synkronisere data mellem flere servere.
Jeg forventede selvfølgelig ikke et sådant twist og kunne længe ikke tro, at den nødvendige funktionalitet manglede. Senere fandt jeg dokumentation, der bekræftede dette, hvilket gjorde mig meget urolig og skuffet.
Opgaven glidede langsomt over i et problem.
Hvilke muligheder havde vi?
- At oprette to klienter på forskellige servere, som skulle udveksle de nødvendige data via noget tredjepartssoftware. Jeg skulle finde denne tredjepartssoftware, der kunne implementere denne funktionalitet – jeg er ikke fan af sådanne forhindringer, men det virkede som den eneste hurtige løsning.
- At skrive mit eget skript til at synkronisere data mellem serverne. Problemet er, at Kerio gemmer hvert objekt som en separat fil, så jeg skulle udvikle et skript til filhåndtering, men på grund af det tilstrækkelige antal kilder virkede opgaven temmelig kompleks, især fordi der skulle udføres flere datavalideringskontroller, i tilfælde af at nogen oprettede en opgave på samme tid etc.
For at springe frem til slutningen, så kan jeg sige, at selvom Kerio gemmer objekter som separate filer, er det ikke så dumt at spørge – hvordan står det til med filsystemet ved hvert opkald til et objekt.
Efter at have brugt en lang tid på overvejelser og fyldt en masse papir med planer om ”at tage fjendens territorium”, tog jeg kl. 18 to rigtige beslutninger:
- Den første beslutning – at lave det selv og ikke lede efter noget tredjepart.
- Den anden beslutning – at gå i seng.
Allerede om morgenen vågnede jeg med én eneste og rigtige tanke, som blev forkortet til et par bogstaver – DFS
Løsning
Selve løsningen så sådan ud
- at bringe alle servere, der vil være involveret i synkroniseringen, til OS Windows. (En del var på Linux. der var behov for migration af maildata til et andet OS)
- Bestemme strukturen af de mapper, der vil være involveret i synkroniseringen – de skal være identiske.
- Identificere alle mailservere under én domæne med et fælles DFS-område.
- Oprette den ovennævnte distribuerede Kerio-domæne, da jeg i mit tilfælde har brug for synkronisering af data, ikke kun mellem servere, men også mellem domæner, som den anden kan håndteres af Kerio-serveren selv. (i modsætning til den første)
- Pointe synkroniserede mapper mod DFS-området.
- Find på et eller andet arbejde omkring (for der kan ikke være noget uden et arbejde)
Implementering
Eksempel på to mailservere (der kan være flere)
1. Kerio Distributed domain

Master deltager ikke i synkroniseringen, men det er ikke et krav.
Jeg vil ikke beskrive, hvordan man opsætter den distribuerede Kerio-domæne, det er ikke svært, man kan studere den officielle
I sidste ende skal du i administrationskonsollen se følgende billede:
![]()

Derefter var jeg interesseret i de delte mapper, på Master-serveren kan du angive følgende muligheder:
![]()

Speciel for hvert domæne — serveren vil ikke synkronisere offentlige mapper mellem domæner
Fælles for alle domæner — alle servere vil opgive eksisterende offentlige mapper i hvert domæne og oprette nye enhedsmappen for alle domæner på hver af mailserverne.
Opmærksomhed! Denne mulighed ændrer selvom politikken for opsætningen på alle servere, udfører synkroniseringen separat fra hver server (dvs. — uden et fælles område)
Administrator vil stadig have mulighed for at distribuere adgangene mellem brugerne.
i mit tilfælde — alle mine og jeg har brug for fuld synkronisering (I dit tilfælde kan løsningen være anderledes) på hver server skal de samme sæt domæner, der skal synkroniseres, oprettes.
2. Kerio data mapper
Nu er det nødvendigt at oprette identiske fælles mapper, der skal synkroniseres på hver af serverne. Mapper, Kalendere, Kontakter.
Råd – opret kataloger på engelsk, da de vil have navne i en uforståelig kodning, hvis du opretter dem med latinske bogstaver. Det er i hvert fald ubelejligt.
Nu er det nødvendigt at finde de fysiske stier til postmapperne på hver server.
Fælles for alle domæner ~DataMailmail#publicSynkroniseret katalog#msgs
Speciel for hvert domæne ~DataMailmail**Domain**#publicSynkroniseret katalog#msgs
Vær opmærksom på, at vi ikke vil synkronisere hele kataloget, men kun containeren med data. #msgs — her gemmes selve objekterne, alle andre data for hver server skal være individuelle.
3. DFS
Jeg vil heller ikke beskrive i detaljer, hvordan man konfigurerer DFS, der er nok information om dette emne.
DFS er en rolle i Windows Server, der giver mulighed for at sammenkæde delte mapper, som ligger på forskellige servere.
Før du konfigurerer DFS, er det nødvendigt at stoppe alle postservere, der vil deltage i datasykroniseringen.
Når konfigurationen er afsluttet, skal du have følgende billede for hver af de synkroniserede mapper.

Vi har naturligvis ikke brug for at offentliggøre replikerede mapper.

Når replikationen finder sted (og der er ikke meget at replikere – mapperne er tomme), kan postserverne genstartes.
Dernæst kan du fylde en af postserverne med data og kontrollere, at dataene bliver replikeret korrekt.
4. Workaround
Beskrivelse af overvejelser
Som du kan se, efter at dataene begyndte at synkronisere (DFS), hvis du opretter noget på den første server – så sker der ikke altid noget på den anden server, eller det dukker op, men ikke altid.
Der er ingen grund til at fortvivle; det vil selvfølgelig dukke op på et eller andet tidspunkt, men hellere tidligt end sent. For sent kan være om 6-12 timer.
Det hele handler om, at så snart du opretter noget på den første server, vil filen straks dukke op på de følgende servere takket være DFS-systemet. Men hvis den pågældende postkatalog tidligere allerede er blevet læst af nogen, og det anmodes om igen, vil serveren ikke læse mappen #msgs igen, men vil udspytte data fra sin egen indkatalogering, der muligvis ikke længere stemmer overens med vores virkelighed.
Kerio har en mekanisme til at genlæse indekset, men den kan tage omkring seks timer, og i løbet af disse seks timer kan opgavens relevans i kalenderen være et par gange tabt.
For at kontrollere synkroniseringens funktionalitet lige nu, kan man slette filen index.fld i den tilsvarende synkroniserede mappe, og efter at have genåbnet mappen på mailserveren, vil Kerio genlæse mappen, og data vil dukke op. Det kunne synes at være løsningen, at man sletter filen ved ændring af data, men det virker ikke hver gang, kun første gang, dernæst mister Kerio pludselig interessen for index.fld.
Og så begynder den at spytte ukendte meddelelser ud til brugeren — om et eller andet indeks og at det allerede laver noget.
Der er en anden mulighed, at skabe noget — i det øjeblik et nyt objekt oprettes, kan serveren pludselig indse, at filnavnet, den ville have givet, allerede er blevet taget, men her er det en sneboldseffekt, og det er en blindgyde.
Hvad skal man så gøre?
Hvis vi ser nærmere på det allerede kendte billede.

Men på en anden plan kan man bemærke en meget interessant og nødvendig knap for os lige nu — Genindekser mapper
Og faktisk. Hvis man trykker på denne knap på mailserveren, som ikke er klar over, at noget allerede er ændret i den synkroniserede #msgs, får vi et stabilt, hurtigt resultat. Alt skjult vil blive tydeligt.
I loggen kan man se, hvor lang tid denne proces tager; i mit tilfælde med flere tusinde (15.000) poster tager det omkring 3-4 minutter.
Det eneste der er tilbage, er at finde ud af, hvordan man faktisk trykker på denne knap, når vi har brug for det.
Det viser sig, at Kerio har sin egen API
funktion, der udfører vores opgave, som ser således ud –
session = callMethod("Domains.checkPublicFoldersIntegrity", {}, token)
Ud fra alt det ovenstående skal vi skrive et script, der overvåger tilstanden af de interesserede mapper, og i tilfælde af ændringer udfører den funktion, vi har brug for.
Jeg vil sige, at jeg har skrevet flere forskellige versioner af scripts, der udfører forskellige kontroller, og jeg stoppede ved den, der bygger alle output ud fra antallet af filer.
Implementering af scriptet
Eksempel på CMD-script og beskrivelse
Re-index.bat
@echo off
set dir=%~dp0
%dir:~0,2%
CD "%~dp0"
md "%LOG"
md "%Setup"
ECHO -Start- >> "%LOG%Computername%.log"
ECHO Start -> %Computername% te% %Time% >> "%LOG%Computername%.log"
SetLocal EnableDelayedExpansion
for /f "UseBackQ Delims=" %%A IN ("%Setup%Computername%.List") do (
set /a c+=1
set "m!c!=%%A"
)
set d=%c%
Echo Folder = %c%
ECHO Folder = %c% >> "%LOG%Computername%.log"
ECHO.
ECHO. >> "%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 te% %Time% - Delete !m%id%! >> "%LOG%Computername%.log"
set 1DirSize!id!=!2DirSize%id%!
ECHO.
ECHO.
set /a id+=1
goto Find
:Reindex
ECHO. >> "%LOG%Computername%.log"
ECHO --- RE-INDEX - Start - te% %Time% --- >> "%LOG%Computername%.log"
ECHO. >> ----------------------------------- >> "%LOG%Computername%.log"
call PublicFolders.py
timeout 60
goto start
exit
Et skript startes på hver mailserver (kan som en tjeneste, administratorrettigheder er ikke nødvendige)
Skriptet læser filen Setup%Computername%.List
Hvor %Computername% er navnet på den nuværende server (direktoriet kan indeholde lister af alle servere.)
Fil %Computername%.List indeholder de fulde stier til de synkroniserede mapper, hver sti er skrevet i en ny linje og må ikke indeholde tomme linjer.
Efter den første kørsel udfører skriptet en indeksningsprocedure, uanset om det er nødvendigt eller ej, skriptet opretter også et indeks over antallet af filer i hver af de synkroniserede mapper.
Opgaven for skriptet er at tælle alle filer i den angivne mappe.
Ved afslutningen af tællingen af hver mappe, hvis den aktuelle filværdi i en hvilken som helst mappe ikke stemmer overens med den tidligere, sletter skriptet filer fra roden af den synkroniserede mailkatalogmappe: index.fld, indexlog.fld, search.fld og starter indeksningsprocessen — af de fælles mailmapper.
Information om udførelsen af opgaverne gemmes i LOG-mappen.
Indeksningsprocessen
Indeksningsprocessen består i at udføre API-funktionen Kerio
Session = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)
Et eksempel på udførelsen er givet i python
PublicFolders.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)
Det kan være, som det er, men hvis du har brug for HTTPS — python skal stole på Kerios certifikat.
Du skal også angive en konto med rettigheder til at udføre denne funktion (Admin – delte postmapper) på mailsystemet.
Jeg håber, at min artikel vil være nyttig for administratorer af Kerio Connect.
Kilde: habr.com
