Dzień dobry, Habro!
Zadanie
Moja organizacja korzysta z serwera pocztowego na platformie Kerio Connect; serwery pocztowe są zainstalowane w różnych miastach, aby służyć swoim użytkownikom. Początkowo nie było rozproszonej struktury, ponieważ domeny różnią się na trzecim poziomie, wskazując miasto witryny. Wszystko zadziałało i wszyscy byli zadowoleni. Pewnego pięknego dnia kierownictwo ustaliło zadanie, wspólny kalendarz działań dla wszystkich lokalizacji!
prehistoria
Początkowo pomysł polegał na stworzeniu domeny poczty rozproszonej Kerio, która miałaby wszystko zrobić sama. Ledwo powiedziane, zrobione, utworzono domenę rozproszoną, ale tak się nie stało, serwer był gotowy do synchronizacji kalendarzy, folderów, kontaktów - między domenami znajdującymi się na tym samym serwerze, ale w ogóle nie miał zamiaru synchronizować danych między kilkoma serwery.
Ja oczywiście nie spodziewałem się takiego haczyka i długo nie mogłem uwierzyć, że brakuje mi potrzebnej funkcjonalności. Później znalazłem dokumenty potwierdzające ten fakt. Bardzo mnie to zdziwiło i rozczarowało.
Zadanie płynnie zamieniło się w problem.
Jakie były opcje?
- Utwórz dwóch klientów na różnych serwerach, którzy wymieniają niezbędne dane z oprogramowaniem innych firm. Należało znaleźć oprogramowanie innej firmy, które zaimplementowałoby tę funkcjonalność – nie lubię takich rake’ów, ale wydawało mi się, że to jedyne szybkie rozwiązanie.
- Napisz własny skrypt do synchronizacji danych pomiędzy serwerami. Faktem jest, że Kerio przechowuje każdy obiekt jako osobny plik, dlatego konieczne było opracowanie skryptu do pracy z plikami, jednak przy wystarczającej liczbie źródeł zadanie wydawało się nieco skomplikowane, zwłaszcza że konieczne było wykonanie wielu sprawdza poprawność danych, w przypadku, gdy ktoś utworzy zadanie w tym samym przedziale czasu, itp., itp.
Patrząc w przyszłość, powiem, że chociaż Kerio przechowuje obiekt jako oddzielny plik, nie jest na tyle głupi, aby pytać, jak radzi sobie system plików za każdym razem, gdy uzyskujesz dostęp do obiektu.
Spędziwszy dużo czasu na rozmyślaniach, sporządzając plik kartek z planami „zajęcia terytorium wroga”, o godzinie 6:XNUMX podjąłem dwie właściwe decyzje:
- Pierwsza decyzja to robić swoje i nie szukać niczego z zewnątrz.
- Drugie rozwiązanie to iść spać.
Już rano obudziłam się z jedną jedyną i prawdziwą myślą, która została zredukowana do kilku liter – DFS
decyzja
Samo rozwiązanie wyglądało tak
- sprowadź wszystkie serwery, które będą uczestniczyć w synchronizacji z systemem operacyjnym Windows. (Część była na Linuksie. Wymagana była migracja danych poczty do innego systemu operacyjnego)
- Określ strukturę katalogów, które będą brały udział w synchronizacji - muszą być identyczne.
- Zdefiniuj wszystkie serwery pocztowe w ramach jednej domeny z pojedynczą przestrzenią DFS.
- Utwórz wspomnianą wyżej rozproszoną domenę Kerio, ponieważ w moim przypadku wymagana jest synchronizacja danych nie tylko między serwerami, ale także między domenami, ta druga może być obsługiwana przez serwer Kerio niezależnie. (w odróżnieniu od pierwszego)
- Ustaw zsynchronizowane katalogi na przestrzeń DFS.
- Wymyśl jakąś kulę (w końcu bez kuli nie da się żyć)
realizacja
Przykład na dwóch serwerach pocztowych (może więcej)
1. Domena rozproszona Kerio
Master nie uczestniczy w synchronizacji, ale nie jest to warunek konieczny.
Nie będę opisywał jak podnieść domenę rozproszoną Kerio, nie ma w tym nic skomplikowanego, możesz przestudiować oficjalną stronę
Ostatecznie w konsoli administracyjnej powinieneś zobaczyć następujący obraz:
Następnie zainteresowały mnie foldery współdzielone, na serwerze Master możesz określić następujące opcje:
Specyficzne dla każdej domeny - serwer nie będzie synchronizował folderów publicznych pomiędzy domenami
Wspólne dla wszystkich domen - wszystkie serwery porzucą istniejące foldery publiczne w każdej domenie i utworzą nowe, pojedyncze foldery dla wszystkich domen na każdym serwerze pocztowym.
Ostrzeżenie! Chociaż ta opcja zmienia zasady konfiguracji na wszystkich serwerach, synchronizuje się oddzielnie z każdym serwerem (to znaczy bez jednej wspólnej przestrzeni)
Administrator nadal będzie mógł rozdzielać dostęp pomiędzy użytkownikami.
w moim przypadku wszystkie są moje i potrzebuję pełnej synchronizacji (w Twoim przypadku rozwiązanie może być inne) na każdym serwerze musisz utworzyć identyczne zestawy domen, które wymagają synchronizacji.
2. Katalogi danych Kerio
Teraz musisz utworzyć identyczne katalogi współdzielone, które należy zsynchronizować na każdym z serwerów. Foldery, kalendarze, kontakty.
Rada - twórz katalogi po angielsku, jeśli utworzysz je po łacinie, katalog będzie miał nazwę w jakimś niezrozumiałym kodowaniu, jest to co najmniej niewygodne.
Teraz musisz znaleźć fizyczne ścieżki folderów pocztowych na każdym serwerze.
Wspólne dla wszystkich domen ~DataMailmail#publicСинхронизируемый каталог#msgs
Specyficzne dla każdej domeny ~DataMailmail**Domain**#publicСинхронизируемый каталог#msgs
Pamiętaj, że nie będziemy synchronizować całego katalogu, a jedynie kontener z danymi #wiadomości — tutaj przechowywane są same obiekty, wszystkie pozostałe dane muszą być osobne dla każdego serwera.
3.DFS
Nie będę szczegółowo opisywał, jak skonfigurować DFS, jest wystarczająco dużo informacji na ten temat.
DFS to usługa roli w systemie Windows Server, która umożliwia łączenie folderów współdzielonych znajdujących się na różnych serwerach
Przed skonfigurowaniem systemu DFS należy zatrzymać wszystkie serwery pocztowe, które będą uczestniczyć w synchronizacji danych.
Po zakończeniu konfiguracji powinieneś otrzymać następujący obraz dla każdego zsynchronizowanych folderów
Naturalnie nie musimy publikować zreplikowanych folderów.
Po zakończeniu replikacji (a nie ma tam nic specjalnego do replikowania - foldery są puste) można uruchomić serwery pocztowe.
Następnie możesz wypełnić jeden z serwerów pocztowych danymi i sprawdzić, czy dane są poprawnie replikowane.
4. Kula
Opis odbicia
Jak widać po rozpoczęciu synchronizacji danych (DFS), jeśli albo utworzyłeś coś na pierwszym serwerze, w jakiś sposób nic nie pojawia się na drugim serwerze, albo pojawia się, ale jakoś nie zawsze.
Nie rozpaczaj, oczywiście prędzej czy później się tam pojawi, ale lepiej wcześniej niż później. Ponieważ za 6 – 12 godzin jest już za późno.
Rzecz w tym, że gdy tylko utworzysz coś na pierwszym serwerze, na drugim i kolejnych serwerach plik oczywiście od razu się pojawi dzięki systemowi DFS, ale w przypadku, gdy ten katalog pocztowy był już przez kogoś czytany i zostanie ponownie zażądany, serwer nie będzie już ponownie czytał folderu #msgs, ale wypluł dane z własnego indeksu, które mogą już nie odpowiadać naszej rzeczywistości.
Kerio posiada mechanizm ponownego odczytania indeksu, ale może on zadziałać w około sześć godzin i w ciągu tych 6 godzin aktualność zadania w kalendarzu może zostać nieco utracona.
Aby przetestować synchronizację już teraz, możesz usunąć plik w odpowiednim zsynchronizowanym katalogu indeks.fld, po ponownym uzyskaniu dostępu do folderu na serwerze pocztowym i jeśli tego pliku brakuje, Kerio ponownie odczyta katalog i dane pojawi się. Wydawałoby się, że to jest rozwiązanie, usuń plik przy zmianie danych, ale nie działa to za każdym razem, ale tylko za pierwszym razem, wtedy Kerio z jakiegoś powodu traci całe zainteresowanie indeksem.fld
Zaczyna też wypluwać niezrozumiałe dla użytkownika komunikaty - o jakimś indeksie i o tym, że już coś tam robi.
Jest jeszcze jedna opcja, żeby coś stworzyć - w momencie tworzenia nowego obiektu serwer nagle orientuje się, że nazwa pliku, który chciał przypisać jest już zajęta, ale to kula śnieżna i jest to opcja ślepa.
Jak to może być?
Jeśli jeszcze raz zwrócimy uwagę na obraz, który jest nam już znany.
Ale w innym samolocie widać bardzo interesujący przycisk, którego teraz potrzebujemy - Ponowne indeksowanie folderów
I rzeczywiście. Jeśli klikniemy ten przycisk na serwerze pocztowym, który nie wie, że coś się już zmieniło w zsynchronizowanych #msgs, otrzymamy stabilny, szybki wynik. Wszystko, co ukryte, stanie się jasne.
W logu widać jak długo trwa ten proces, w moim przypadku przy kilku tysiącach (15 tysiącach) rekordów zajmuje to około 3-4 minut.
Musimy tylko wymyślić, jak nacisnąć ten przycisk, kiedy go potrzebujemy.
Okazało się Kerio mieć własne API
Funkcja realizująca nasze zadanie wygląda następująco:
session = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)
Z tego wszystkiego musimy napisać skrypt, który będzie monitorował stan interesujących nas folderów i jeśli coś się zmieniło, wykona potrzebną nam funkcję.
Chcę powiedzieć, że napisałem kilka różnych wersji skryptów, które wykonują różne kontrole i zdecydowałem się na tę, która wyciąga wszystkie wnioski na podstawie liczby plików.
Implementacja skryptu
Przykład i opis skryptu CMD
Ponownie zaindeksuj.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
Kopia skryptu działa na każdym serwerze pocztowym (można go używać jako usługi, nie są wymagane uprawnienia Adm)
Skrypt odczytuje plik Setup%Computername%.List
Gdzie %NazwaKomputera% to nazwa bieżącego serwera (Katalog może zawierać listę wszystkich serwerów jednocześnie.)
Plik %Computername%.List – zawiera pełne ścieżki synchronizowanych katalogów, każda ścieżka jest zapisana w nowej linii i nie powinna zawierać pustych linii.
Po pierwszym uruchomieniu skrypt wykonuje procedurę indeksowania, niezależnie od tego, czy jest to konieczne, czy nie, a także tworzy indeks ilości plików w każdym synchronizowanym katalogu.
Celem skryptu jest zliczenie wszystkich plików w określonym katalogu.
Na koniec zliczania każdego katalogu, jeśli w przynajmniej jednym katalogu bieżąca wartość plików nie jest zgodna z poprzednią, skrypt usuwa pliki z katalogu głównego synchronizowanego katalogu poczty: index.fld, indexlog.fld, search.fld
i rozpoczyna proces indeksowania udostępnionych folderów poczty.
Informacje o wykonaniu zadania są zrzucane do katalogu LOG.
Proces indeksowania
Proces indeksowania sprowadza się do wykonania funkcji Kerio API
Sesja = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)
Przykładową implementację podano w – 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)
Również w pliku należy podać konto z uprawnieniami do wykonywania tej funkcji (Adm - publiczne foldery poczty) serwera pocztowego.
Mam nadzieję, że mój artykuł będzie przydatny dla administratorów Kerio Connect.
Źródło: www.habr.com