分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

下午好,哈布爾!

任務

我的組織使用 Kerio Connect 平台上的郵件伺服器;郵件伺服器安裝在不同的城市來為其使用者提供服務。 最初沒有分散式結構,因為網域在第三層不同,表示站點的城市。 一切順利,每個人都很高興。 在一個晴朗的日子,管理層設定了一項任務,即所有站點之間的活動共同日曆!

最初的想法是建立 Kerio 分散式郵件網域,它會自己完成所有事情。 說完就創建了一個分散式網域,但事實並非如此,伺服器已準備好在位於同一伺服器上的網域之間同步日曆、資料夾、聯絡人,但根本不會在多個網域之間同步資料伺服器。

當然,我沒想到會出現這樣的問題,而且很長一段時間都無法相信我需要的功能缺失了。 後來我找到了這一事實的文獻證據。 我對此感到非常困惑和失望。

任務順利地變成了問題。

有哪些選擇?

  • 在不同的伺服器上建立兩個客戶端,與某些第三方軟體交換必要的資料。 有必要找到可以實現此功能的第三方軟體 - 我不喜歡這樣的耙子,但似乎這是唯一的快速解決方案。
  • 編寫自己的腳本用於伺服器之間的資料同步。 事實上,Kerio 將每個物件儲存為單獨的文件,因此有必要開發一個用於處理文件的腳本,但鑑於來源數量足夠,該任務似乎有些複雜,特別是因為需要執行多個檢查資料的正確性,以防有人在同一時間段創建任務等。

展望未來,我會說,雖然 Kerio 將物件儲存為單獨的文件,但它並沒有愚蠢到每次訪問該物件時都詢問文件系統是如何做到的。

經過深思熟慮,起草了一堆「奪取敵地」計畫的紙片後,我在六點鐘做出了兩個正確的決定:

  • 第一個決定就是做好自己的事情,不要向外界尋求任何事。
  • 第二個解決辦法是去睡覺。

早上我醒來時就帶著一個單一而真實的想法,它被簡化為幾個字母 - DFS

解決方法

解決方案本身看起來像這樣

  • 將所有參與同步的伺服器帶到 Windows 作業系統。 (部分是在Linux上。需要將郵件資料遷移到另一個作業系統)
  • 確定將參與同步的目錄的結構 - 它們必須相同。
  • 使用單一 DFS 空間定義一個網域下的所有郵件伺服器。
  • 建立上述分散式 Kerio 網域,因為在我的例子中需要資料同步,不僅在伺服器之間而且在網域之間;第二個可以由 Kerio 伺服器獨立處理。 (與第一個不同)
  • 將同步目錄設定為DFS空間。
  • 拿出某種拐杖(畢竟,沒有拐杖你就活不下去)

履行

兩個郵件伺服器上的範例(也許更多)

1.Kerio分佈式域

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

Master不參與同步,但這不是前提條件。

如何籌集Kerio分散式網域我就不介紹了,沒什麼複雜的,可以研究一下官方 曼努爾

最終,您應該在管理控制台中看到以下圖像:

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

接下來我對共用資料夾感興趣;在主伺服器上,您可以指定以下選項:

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

具體針對每個域 - 伺服器不會同步網域之間的公用資料夾

所有域通用 - 所有伺服器將放棄每個網域中的現有公用資料夾,並為每個郵件伺服器上的所有網域建立新的單一資料夾。

警告! 儘管此選項更改了所有伺服器上的配置策略,但它與每個伺服器分開同步(即沒有單一公共空間)

管理員仍然能夠在使用者之間分配存取權限。
就我而言,它們都是我的,我需要在每台伺服器上完全同步(在您的情況下,解決方案可能不同),您需要建立需要同步的相同網域集。

2.Kerio資料目錄

現在您需要建立需要在每台伺服器上同步的相同共用目錄。 資料夾、日曆、聯絡人。

建議-用英語創建目錄,如果用拉丁語創建目錄,該目錄的名稱將採用一些難以理解的編碼,這至少不方便。

現在您需要找到每台伺服器上郵件資料夾的實體路徑。

所有域通用 ~DataMailmail#publicСинхронизируемый каталог#msgs
具體針對每個域 ~DataMailmail**Domain**#publicСинхронизируемый каталог#msgs

請注意,我們不會同步整個目錄,只會同步包含資料的容器 #訊息 — 物件本身儲存在這裡,每個伺服器的所有其他資料必須是單獨的。

3.DFS

我不會詳細描述如何配置DFS,關於這個問題已經有足夠的資訊了。

DFS 是 Windows Server 中的角色服務,提供組合位於不同伺服器上的共用資料夾的功能
MS DFS 文檔鏈接

在設定DFS之前,您必須停止所有將參與資料同步的郵件伺服器。

設定完成後,您應該會收到每個同步資料夾的下圖

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

當然,我們不需要發布複製的資料夾。

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

複製發生後(並且沒有什麼特別要複製的地方 - 資料夾是空的),可以啟動郵件伺服器。

接下來,您可以向其中一台郵件伺服器填入數據,並檢查資料是否正確複製。

4.拐杖

反射描述

正如您在資料開始同步(DFS) 後所看到的,如果您在第一台伺服器上創建了某些內容,不知何故,第二台伺服器上什麼也沒有出現,或者它出現了,但不知何故並不總是如此。

不要絕望,當然,它遲早會出現,但早點總比晚點好。 因為6-12小時就太晚了。

問題是,一旦您在第一台伺服器上建立了某些內容,由於 DFS 系統,在第二台及後續伺服器上該檔案當然會立即出現,但如果該郵件目錄之前已被某人讀取過再次請求時,伺服器不會重新讀取#msgs資料夾,而是從自己的索引中吐出數據,這可能不再符合我們的現實。

Kerio 有一個重新讀取索引的機制,但它可以在大約 6 小時內工作,並且在這 XNUMX 小時內,日曆中任務的相關性可能會有所丟失。
為了立即測試同步,可以刪除對應同步目錄下的index.fld文件,重新存取郵件伺服器上的資料夾後,如果該檔案遺失,Kerio會重新讀取該目錄和資料會出現。 看起來這就是解決方案,當資料發生變化時刪除文件,但這並不是每次都有效,而只是第一次,然後Kerio出於某種原因失去了對index.fld的所有興趣
它還開始吐出用戶無法理解的消息 - 關於某種索引並且它已經在那裡做了一些事情。

還有另一種選擇,創建一些東西 - 在創建新物件的那一刻,伺服器突然意識到它想要分配的檔案名稱已經被佔用,但它就像滾雪球一樣,這是一個死胡同的選擇。

怎麼會這樣呢?

如果我們再次關注我們已經熟悉的畫面。

分散式 Kerio Connect 伺服器之間共用資料夾、聯絡人、行事曆的完全同步

但在另一架飛機上,你可以看到我們現在需要的一個非常有趣的按鈕—— 重新索引資料夾

確實如此。 如果我們在不知道同步#msgs 中已發生變更的郵件伺服器上按一下此按鈕,我們將獲得穩定、快速的結果。 一切隱藏的事情都會變得清晰。

在日誌中,您可以看到此過程需要多長時間;在我的情況下,有數千(15)條記錄,大約需要 3-4 分鐘。

我們所要做的就是弄清楚如何在需要時實際按下這個按鈕。

事實證明 安裝Kerio 有你自己的 API

描述
Документация

執行我們任務的函數如下所示:
session = callMethod("Domains.checkPublicFoldersIntegrity",{}, token)

綜上所述,我們需要編寫一個腳本來監視感興趣的資料夾的狀態,如果發生變化,則執行我們需要的功能。

我想說的是,我編寫了幾個不同版本的腳本來執行不同的檢查,並選擇了根據文件數量得出所有結論的版本。

腳本執行

CMD腳本範例及說明

重新索引.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

該腳本的副本在每個郵件伺服器上運行(可以使用服務,不需要 Adm 權限)

腳本讀取文件 Setup%Computername%.List

其中 %Computername% 是目前伺服器的名稱(該目錄可以同時包含所有伺服器的清單。)

檔案%Computername%.List – 包含同步目錄的完整路徑,每個路徑都寫在新行上,且不應包含空白行。

首次啟動後,無論是否有必要,腳本都會執行索引過程,腳本也會建立每個同步目錄中檔案數量的索引。

該腳本的目的是統計指定目錄中的所有檔案。

在對每個目錄進行計數結束時,如果至少有一個目錄中的檔案目前值與前一個目錄不匹配,則腳本會從同步郵件目錄的根目錄中刪除檔案: index.fld, indexlog.fld, search.fld 並啟動共享郵件資料夾的索引程序。

有關任務執行的資訊轉儲到 LOG 目錄中。

索引過程
索引過程歸結為執行 Kerio API 函數
Session = callMethod("Domains.checkPublicFoldersIntegrity",{}, 令牌)

python 中給出了一個範例實現
公共資料夾.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)

http://127.0.0.1:4040 您可以保持原樣,但如果您需要 HTTPS,python 必須信任 Kerio 憑證。

另外,在該檔案中,您必須指定一個有權執行郵件伺服器此功能(Adm - 公共郵件資料夾)的帳戶。

我希望我的文章對 Kerio Connect 管理員有用。

來源: www.habr.com

添加評論