God dag, Habr!
Uppgift
I min organisation anvÀnder vi en e-postserver pÄ plattformen Kerio Connect, i olika stÀder Àr e-postservrar installerade som betjÀnar sina anvÀndare. Det fanns frÄn början ingen distribuerad struktur, eftersom domÀnerna skilde sig Ät pÄ tredje nivÄn med angivelse av staden för platsen. Allt fungerade och alla var nöjda. En vacker dag satte ledningen upp uppgiften: en gemensam kalender för alla platser!
Bakgrund
Ursprungligen var idĂ©n att skapa en distribuerad e-postdomĂ€n med Kerio och den skulle klara allt pĂ„ egen hand. Sagt och gjort, den distribuerade domĂ€nen skapades, men det blev inte som förvĂ€ntat; servern var redo att synkronisera kalendrar, mappar, kontakter â mellan domĂ€ner pĂ„ samma server, men hade ingen avsikt att synkronisera data mellan flera servrar.
Jag förvÀntade mig sÄ klart inte en sÄdan fÀlla och kunde lÀnge inte tro pÄ avsaknaden av den funktionalitet jag behövde. Senare hittade jag dokumentation som bekrÀftade denna fakta. Jag blev mycket tankfull och besviken.
Uppgiften flöt smidigt över till ett problem.
Vilka alternativ fanns?
- Att skapa tvĂ„ klienter pĂ„ olika servrar som genom nĂ„got tredjepartsprogram utbytte nödvĂ€ndig data. Jag behövde hitta detta tredjepartsprogram som skulle förverkliga denna funktionalitet â jag gillar inte sĂ„dana fallgropar, men det verkade vara den enda snabba lösningen.
- Att skriva ett eget skript för att synkronisera data mellan servrar. Grejen Àr att Kerio lagrar varje objekt som en separat fil, sÄ det krÀvdes att utveckla ett skript för att hantera filer, men med tanke pÄ det tillrÀckliga antalet kÀllor verkade uppgiften nÄgot komplex, sÀrskilt eftersom det behövdes flera kontroller av datakorrekthet, ifall nÄgon skapade en uppgift vid samma tidpunkt och sÄ vidare.
Som en förhandssyn sĂ€ger jag att Kerio, Ă€ven om det lagrar objekt som separata filer, Ă€ndĂ„ inte Ă€r sĂ„ dum att frĂ„ga varje gĂ„ng ett objekt anropas â hur stĂ„r det till med filsystemet.
Efter att ha Àgnat mycket tid Ät eftertanke och ritat en massa papper med planer för "att ta över fiendens territorium", tog jag vid sjÀtte timmen tvÄ korrekta beslut:
- Det första beslutet â att göra mitt eget och inte leta efter nĂ„got extern.
- Det andra beslutet â att gĂ„ och lĂ€gga mig.
Redan pĂ„ morgonen vaknade jag med en enda tankegĂ„ng som kondenserades till nĂ„gra bokstĂ€ver â DFS
Lösning
SjÀlva lösningen sÄg ut som följande
- för att föra alla servrar som skulle delta i synkroniseringen till OS Windows. (En del var pÄ Linux. migrering av e-postdata till ett annat OS krÀvdes)
- BestĂ€mma katalogstrukturen för de mappar som ska delta i synkroniseringen â de mĂ„ste vara identiska.
- Definiera alla e-postservrar under en domÀn med ett enhetligt DFS-utrymme.
- Skapa den ovan nÀmnda distribuerade domÀnen Kerio, eftersom det i mitt fall krÀvs synkronisering av data inte bara mellan servrar utan Àven mellan domÀner, vilket den andra kan hantera av Kerio-servern sjÀlv. (till skillnad frÄn den första)
- Rikta de synkroniserade katalogerna mot DFS-utrymmet.
- TÀnka ut nÄgon form av nödlösning (för utan nödlösningar gÄr det inte)
Implementering
Exempel pÄ tvÄ e-postservrar (kan vara fler)
1. Kerio distribuerad domÀn

Master deltar inte i synkroniseringen, men det Àr inget obligatoriskt krav.
Jag kommer inte att gÄ in pÄ hur man sÀtter upp en distribuerad domÀn Kerio, det Àr inget komplicerat, man kan lÀsa officiell
I slutÀndan ska ni i administrationspanelen se följande bild:
![]()

DÀrefter var jag intresserad av gemensamma mappar, pÄ Master-servern kan följande alternativ anges:
![]()

Speciellt för varje domĂ€n â servern kommer inte att synkronisera offentliga mappar mellan domĂ€nerna
Gemensamma för alla domĂ€ner â alla servrar kommer att avstĂ„ frĂ„n befintliga gemensamma mappar i varje domĂ€n och skapa nya gemensamma mappar för alla domĂ€ner pĂ„ varje e-postserver.
Varning! Detta alternativ Ă€ndrar Ă€ven om konfigurationen pĂ„ alla servrar, synkroniseringen sker separat frĂ„n varje server (det vill sĂ€ga â utan ett gemensamt utrymme)
Administratören kvarstÄr möjlighet att fördela Ätkomster mellan anvÀndarna.
i mitt fall â alla mina och jag behöver fullstĂ€ndig synkronisering (i ert fall kan lösningen vara annan) pĂ„ varje server mĂ„ste identiska domĂ€nuppsĂ€ttningar skapats som ska synkroniseras.
2. Kerio datakataloger
Nu Àr det nödvÀndigt att skapa identiska gemensamma kataloger som ska synkroniseras pÄ varje av servrarna. Mappar, Kalendrar, Kontakter.
Tips â create directories in English; if you create them in Latin script, the directory will have a name in an incomprehensible encoding, which is at least inconvenient.
Now it is necessary to find the physical paths of the mail folders on each server.
Gemensamma för alla domÀner ~DataMailmail#publicSynchronized directory#msgs
Speciellt för varje domÀn ~DataMailmail**Domain**#publicSynchronized directory#msgs
Please note that we will synchronize not the entire directory, but only the container with the data. #msgs â here the actual objects are stored, all other data for each of the servers must be individual.
3. DFS
I won't go into detail about how to configure DFS, as there is enough information on this issue.
DFS is a role service in Windows Server that allows for the consolidation of shared folders located on different servers.
Before configuring DFS, all mail servers involved in data synchronization must be stopped.
Upon completion of the setup, you should see the following for each of the synchronized folders.

Naturally, we do not need to publish the replicated folders.

After replication occurs (and there isnât much to replicateâthe folders are empty), the mail servers can be restarted.
Next, you can fill one of the mail servers with data and check if the data replicates correctly.
4. Workaround
Thought process description
As you can see, after the data started synchronizing (DFS), if you create anything on the first serverânothing appears on the second server, or it appears inconsistently.
Do not despair, it will eventually appear, but itâs better sooner than later; late means within 6 to 12 hours.
The thing is, as soon as you create something on the first server, the file on the second and subsequent servers will indeed appear immediately due to the DFS system; however, if the mail folder has been read earlier by someone and is requested again, the server will not re-read the #msgs folder but will spit out data from its own index, which may no longer correspond to our reality.
Kerio har en mekanism för att lÀsa om indexet, men det kan ta upp till sex timmar, och under dessa sex timmar kan relevansen av uppgiften i kalendern ha förlorats nÄgot.
För att kontrollera synkroniseringens funktion just nu kan man ta bort index.fld-filen i den relevanta synkroniserade katalogen, efter att man har Ă„tergĂ„tt till mappen pĂ„ e-postservern. Om denna fil inte finns kommer Kerio att lĂ€sa om katalogen och informationen kommer att dyka upp. Det verkar som en lösning â ta bort filen vid dat förĂ€ndring, men detta fungerar inte varje gĂ„ng, utan bara första gĂ„ngen, dĂ€refter tycks Kerio förlora intresset för index.fld.
Och sĂ„ börjar det spottas ut oförstĂ„eliga meddelanden för anvĂ€ndaren â om nĂ„got index och vad det gör.
Det finns Ă€ven alternativet att skapa nĂ„got â vid skapandet av ett nytt objekt inser servern plötsligt att filnamnet den ville ge redan Ă€r upptaget, men hĂ€r Ă€r det som en snöboll och ett dödlĂ€ge.
Vad ska man dÄ göra?
Om vi tittar en gÄng till pÄ den bekanta bilden.

Men i en annan dimension kan vi se en mycket intressant och nödvĂ€ndig knapp för oss just nu â Reindexera mappar
Och det Àr sant. Om man trycker pÄ denna knapp pÄ e-postservern som inte vet att nÄgot har förÀndrats i den synkroniserade #msgs, fÄr vi ett stabilt och snabbt resultat. Allt dolt blir tydligt.
I loggen kan man se hur lÀnge denna process tar, i mitt fall med flera tusen (15 000) poster tar det omkring 3-4 minuter.
Det gÀller bara att komma pÄ hur man faktiskt trycker pÄ denna knapp nÀr vi behöver det.
Det visar sig att Kerio har sin egen API
funktion som utför vĂ„r uppgift, och den ser ut sĂ„ hĂ€r â
session = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)
UtifrÄn allt ovanstÄende behöver vi skriva ett skript som övervakar tillstÄndet för de intressanta mapparna och i det fall nÄgot har förÀndrats utför vÄr nödvÀndiga funktion.
Jag vill sÀga att jag skrivit flera olika versioner av skript som utför olika kontroller, och jag stannade vid den som baserar alla resultat pÄ antalet filer.
Genomförande av skriptet
Exempel pÄ CMD-skript och beskrivning
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
En kopia av skriptet körs pÄ varje e-postserver (kan köras som en tjÀnst, administrativa rÀttigheter krÀvs inte)
Skriptet lÀser filen Setup%Computername%.List
DÀr %Computername% Àr namnet pÄ den aktuella servern (mappen kan innehÄlla listor för alla servrar.)
Filen %Computername%.List innehÄller fullstÀndiga sökvÀgar för de synkroniserade mapparna, varje sökvÀg Àr skriven pÄ en ny rad, och den ska inte innehÄlla tomma rader.
Efter första körningen kommer skriptet att genomföra en indexeringsprocedur, oavsett om det Àr nödvÀndigt eller inte, och skriptet skapar ocksÄ en index över antalet filer i varje av de synkroniserade mapparna.
MÄlsÀttningen med skriptet Àr att rÀkna alla filer i den angivna mappen.
NÀr rÀkningen av varje mapp Àr klar, om minst ett av vÀrdena för filer i den aktuella mappen inte stÀmmer överens med det tidigare, raderar skriptet filer frÄn rotmappen för den synkroniserade e-postkatalogen: index.fld, indexlog.fld, search.fld och startar indexeringsprocessen för de gemensamma e-postmapparna.
Information om uppgifternas genomförande lagras i LOG-mappen.
Indexeringsprocessen
Indexeringsprocessen innebÀr att man anropar API-funktionen Kerio
Session = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)
Exempelkod ges i python
PublicFolders.py
import json
import urllib.request
import http.cookiejar
""" Cookie-lagring Àr nödvÀndig för sessionshantering """
jar = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
urllib.request.install_opener(opener)
""" VĂ€rdnamn eller IP-adress till din Kerio Control-instans med protokoll, port och autentiseringsuppgifter """
server = "http://127.0.0.1:4040"
username = "user"
password = "password"
def callMethod(method, params, token = None):
"""
Anropar en given metod pÄ distans med angivna parametrar.
:param: method strÀng med fullstÀndigt kvalificerat metodnamn
:param: params dict med parametrar för den anropade metoden
:param: token CSRF-token krÀvs alltid utom vid inloggning. AnvÀnd metoden "Session.login" för att fÄ denna 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)
du kan lÄta det vara som det Àr, men om du behöver HTTPS mÄste python lita pÄ Kerio-certifikatet.
I filen mĂ„ste Ă€ven ett konto anges med behörighet att utföra denna funktion (Admin â allmĂ€nna e-postmappar) pĂ„ e-postservern.
Jag hoppas att min artikel kommer att vara nyttig för administratörer av Kerio Connect.
KĂ€lla: habr.com
