Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Dzień dobry, Habr!

Zadanie

W mojej organizacji używamy serwera pocztowego na platformie Kerio Connect, w różnych miastach zainstalowane są serwery pocztowe obsługujące swoich użytkowników. Początkowo nie było struktury rozproszonej, ponieważ domeny różniły się na trzecim poziomie, wskazując na miasto lokalizacji. Wszystko działało i wszystkich to satysfakcjonowało. Pewnego pięknego dnia — kierownictwo postawiło zadanie, wspólny kalendarz spraw biznesowych dla wszystkich lokalizacji!

Tło

Początkowo idea była taka — uruchomić rozproszoną domenę pocztową Kerio i on sam wszystko zrobi. Powiedziano, zrobione, rozproszona domena została stworzona, ale nie było to takie proste, serwer był gotowy do synchronizacji kalendarzy, folderów, kontaktów — między domenami znajdującymi się na jednym serwerze, ale wcale nie zamierzał synchronizować danych między wieloma serwerami.

Tego zwrotu akcji się spodziewałem, oczywiście nie mogłem uwierzyć w brak potrzebnej mi funkcjonalności. Później znalazłem dokumentacyjne potwierdzenie tego faktu. Czym byłem bardzo mocno zmartwiony i rozczarowany.

Zadanie płynnie przekształciło się w problem.

Jakie były opcje

  • Stworzyć dwóch klientów na różnych serwerach, którzy wymienialiby niezbędne dane za pomocą jakiegoś zewnętrznego oprogramowania. Trzeba było znaleźć to zewnętrzne oprogramowanie, które realizowałoby tę funkcjonalność – nie lubię takich pułapek, ale wydawało się, że to jedyne szybkie rozwiązanie.
  • Napisanie własnego skryptu synchronizacji danych między serwerami. Rzecz w tym, że Kerio przechowuje każdy obiekt jako oddzielny plik, odpowiednio trzeba było opracować skrypt do pracy z plikami, ale z uwagi na dosyć dużą ilość źródeł zadanie wydawało się nieco trudne, tym bardziej, że trzeba było przeprowadzać wiele kontroli poprawności danych, czy przypadkiem ktoś nie stworzy zadania w tym samym czasie itd.

Wyprzedzając wydarzenia powiem, że Kerio, choć przechowuje obiekt jako oddzielny plik, nie jest na tyle głupi, by przy każdym dostępie do obiektu pytać — jak się ma system plików.

Spędziwszy dużo czasu na przemyśleniach, zarysywując mnóstwo kartek z planami „zdobycia wrogiej terytorium”, o szóstej godzinie przyjąłem dwie słuszne decyzje:

  • Pierwszym rozwiązaniem jest stworzenie swojego i nie szukanie niczego zewnętrznego.
  • Drugim rozwiązaniem jest pójście spać.

Już rano obudziłem się z jedną, jedyną i właściwą myślą, która sprowadziła się do kilku liter – DFS

Rozwiązanie

Rozwiązanie wyglądało następująco

  • Wszystkie serwery uczestniczące w synchronizacji należy ustawić na systemie operacyjnym Windows. (Część była na Linuxie. Wymagana była migracja danych pocztowych na inny system operacyjny)
  • Należy określić strukturę katalogów, które będą brały udział w synchronizacji – muszą być identyczne.
  • Określić wszystkie serwery pocztowe pod jedną domeną w ramach jednego przestrzeni DFS.
  • Utworzyć wcześniej wspomnianą rozproszoną domenę Kerio, ponieważ w moim przypadku wymagana jest synchronizacja danych nie tylko między serwerami, ale także między domenami, drugą może obsługiwać serwer Kerio samodzielnie. (w przeciwieństwie do pierwszej)
  • Nakierować synchronizowane katalogi na przestrzeń DFS.
  • Wymyślić jakiś obejście (bo bez obejścia się nie obejdzie)

Realizacja

Przykład na dwóch serwerach pocztowych (może być więcej)

1. Rozproszona domena Kerio

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Master nie bierze udziału w synchronizacji, ale to nie jest warunek obowiązkowy.

Nie będę opisywał, jak uruchomić rozproszoną domenę Kerio, nie ma w tym nic trudnego, można zapoznać się z oficjalnym podręcznikiem

Ostatecznie w konsoli administracyjnej powinieneś zobaczyć następujący obrazek:

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Następnie interesowały mnie ogólne foldery, na serwerze Master można wskazać następujące opcje:

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Specjalny dla każdej domeny — serwer nie będzie synchronizował ogólnodostępnych folderów między domenami

Wspólne dla wszystkich domen — wszystkie serwery zrezygnują z istniejących ogólnych folderów w każdej domenie i utworzą nowe, jednorodne foldery dla wszystkich domen na każdym serwerze pocztowym.

Uwaga! Ta opcja, mimo że zmienia politykę ustawień na wszystkich serwerach, dokonuje synchronizacji oddzielnie na każdym z serwerów (to znaczy — bez jednego wspólnego przestrzeni)

Administratorowi pozostaje możliwość dzielenia dostępu między użytkownikami.
W moim przypadku - wszystko moje i potrzebuję pełnej synchronizacji (w Twoim przypadku rozwiązanie może być inne) na każdym serwerze należy stworzyć identyczne zestawy domen, które należy synchronizować.

2. Katalogi danych Kerio

Teraz należy utworzyć identyczne ogólne katalogi, które będą synchronizowane na każdym z serwerów. Foldery, Kalendarze, Kontakty.

Porada – twórz katalogi w języku angielskim, ponieważ jeśli stworzysz je w łacinie, katalog będzie miał nazwę w jakimś nieczytelnym kodowaniu, co jest co najmniej niewygodne.

Teraz musisz znaleźć fizyczne ścieżki folderów pocztowych na każdym serwerze.

Wspólne dla wszystkich domen ~DataMailmail#publicSynchronizowany katalog#msgs
Specjalny dla każdej domeny ~DataMailmail**Domain**#publicSynchronizowany katalog#msgs

Zwróć uwagę, że nie będziemy synchronizować całego katalogu, a tylko kontener z danymi. #msgs — tutaj przechowywane są same obiekty, wszystkie pozostałe dane dla każdego z serwerów powinny być własne.

3. DFS

Szczegółowo jak skonfigurować DFS, nie będę również opisywać, informacji na ten temat jest wystarczająco dużo.

DFS to usługa roli w Windows Server, która umożliwia łączenie wspólnych folderów znajdujących się na różnych serwerach.
Link do dokumentu MS DFS

Przed skonfigurowaniem DFS – należy zatrzymać wszystkie serwery pocztowe, które będą brały udział w synchronizacji danych.

Po zakończeniu konfiguracji powinieneś uzyskać następujący obraz dla każdego z synchronizowanych folderów.

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Nie musimy oczywiście publikować replikowanych folderów.

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Po tym jak zajdzie replikacja (a w replikacji nie jest szczególnie dużo — foldery są puste), można uruchomić serwery pocztowe.

Następnie można załadować dane na jeden z serwerów pocztowych i sprawdzić, czy dane są poprawnie replikowane.

4. Sposób na obejście

Opis rozważań

Jak możesz się przekonać, po rozpoczęciu synchronizacji danych (DFS), jeśli coś stworzysz na pierwszym serwerze — na drugim serwerze nic się nie pojawia, albo pojawia się, ale nie zawsze.

Nie warto się zniechęcać, bo prędzej czy później tam się pojawi, ale lepiej wcześniej niż później. Ponieważ późno to znaczy za 6 – 12 godzin.

Chodzi o to, że gdy tylko stworzysz coś na pierwszym serwerze, na drugim oraz następnych plik oczywiście natychmiast pojawi się dzięki systemowi DFS, jednak w przypadku, gdy ten katalog pocztowy był już wcześniej przeczytany przez kogoś i zostanie ponownie zażądany, serwer nie będzie ponownie czytał folderu #msgs tylko wyrzuci dane z własnego indeksu, który może już od dawna nie odpowiadać naszej rzeczywistości.

Kerio ma mechanizm ponownego odczytu indeksu, ale może on zadziałać dopiero po około sześciu godzinach, a w tym czasie aktualność zadania w kalendarzu może być już nieco stracona.
Aby teraz sprawdzić działanie synchronizacji, można usunąć plik w odpowiednim synchronizowanym katalogu index.fld, po ponownym dostępie do folderu na serwerze pocztowym i przy braku tego pliku Kerio ponownie odczyta katalog i dane się pojawią. Wydawałoby się, że to rozwiązanie — usuwaj plik przy zmianie danych, ale to działa tylko za pierwszym razem, potem Kerio z jakiegoś powodu traci zainteresowanie index.fld.
I zaczyna wyrzucać niejasne dla użytkownika komunikaty — o jakimś indeksie i co on tam już robi.

Jest jeszcze opcja, żeby coś stworzyć — w momencie tworzenia nowego obiektu serwer nagle zrozumie, że nazwa pliku, którą chciałby przypisać, jest już zajęta, ale to jest śnieżna kula i to błędne koło.

Co robić?

Jeśli jeszcze raz zwrócić uwagę na już znany nam obrazek.

Pełna synchronizacja wspólnych folderów, kontaktów, kalendarzy między rozproszonymi serwerami Kerio Connect

Ale w innym układzie, można zauważyć bardzo interesujący i potrzebny nam teraz przycisk — Ponownie zindeksuj foldery

I rzeczywiście. Jeśli naciśniesz ten przycisk na serwerze pocztowym, który nie wie, że już coś się zmieniło w synchronizowanym #msgs, uzyskamy stabilny, szybki wynik. Wszystko, co ukryte, stanie się jawne.

W dzienniku można zobaczyć, ile czasu zajmuje ten proces, w moim przypadku z kilku tysiącami (15 tys.) rekordów trwa to około 3-4 minut.

Pozostaje tylko wymyślić, jak w ogóle nacisnąć ten przycisk, gdy tego potrzebujemy.

Okazuje się, że Kerio ma swoją API

Opis
Dokumentacja

Funkcję, która realizuje nasze zadanie, wygląda tak –
session = callMethod("Domains.checkPublicFoldersIntegrity", {}, token)

Na podstawie powyższego musimy napisać skrypt, który będzie monitorował stan interesujących folderów i w przypadku, gdy coś się zmieni, wykona dla nas potrzebną funkcję.

Chcę powiedzieć, że napisałem kilka różnych wersji skryptów, które wykonują różne kontrole, zatrzymałem się na tym, który wszystkie wyniki buduje na podstawie liczby plików.

Implementacja skryptu

Przykład skryptu CMD i opis

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

Kopia skryptu jest uruchamiana na każdym serwerze pocztowym (można jako usługa, nie są wymagane prawa administracyjne)

Skrypt odczytuje plik Setup%Computername%.List

Gdzie %Computername% to nazwa bieżącego serwera (katalog może zawierać od razu listy wszystkich serwerów.)

Plik %Computername%.List zawiera pełne ścieżki synchronizowanych katalogów, każda ścieżka zapisana jest w nowej linii, nie powinien zawierać pustych linii.

Po pierwszym uruchomieniu skrypt wykonuje procedurę indeksacji, niezależnie od tego, czy jest ona potrzebna, skrypt również tworzy indeks liczby plików w każdym z synchronizowanych katalogów.

Zadanie skryptu polega na zliczeniu wszystkich plików w wskazanym katalogu.

Po zakończeniu zliczania w każdym katalogu, jeśli w przynajmniej jednym katalogu bieżąca liczba plików nie zgadza się z poprzednią, skrypt usuwa pliki z głównego katalogu synchronizowanego katalogu pocztowego: index.fld, indexlog.fld, search.fld i uruchamia proces indeksacji — wspólnych folderów pocztowych.

Do katalogu LOG trafiają informacje o wykonaniu zadań.

Proces indeksacji
Proces indeksacji sprowadza się do wykonania funkcji API Kerio
Session = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)

Przykład wykonania przedstawiony jest w – python
PublicFolders.py

import json
import urllib.request
import http.cookiejar
""" Przechowywanie ciasteczek jest konieczne do obsługi sesji """
jar = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(jar))
urllib.request.install_opener(opener)
""" Nazwa hosta lub adres IP twojej instancji Kerio Control wraz z protokołem, portem i danymi uwierzytelniającymi """

server = "http://127.0.0.1:4040"
username = "user"
password = "password"

def callMethod(method, params, token = None):
    """
    Zdalnie wywołuje określoną metodę z podanymi parametrami.
    :param: method ciąg znaków z w pełni kwalifikowaną nazwą metody
    :param: params słownik z parametrami zdalnie wywoływanej metody
    :param: token token CSRF jest zawsze wymagany, z wyjątkiem metody logowania. Użyj metody "Session.login", aby uzyskać ten 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)

http://127.0.0.1:4040 można pozostawić tak jak jest, jednak jeśli potrzebujesz HTTPS — python musi ufać certyfikatowi Kerio.

W pliku należy również wskazać konto z uprawnieniami do wykonania tej funkcji (Administrator – wspólnych folderów pocztowych) serwera pocztowego.

Mam nadzieję, że mój artykuł będzie przydatny administratorom Kerio Connect.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster