Python 提供了便捷的工具與 Citrix Netscaler 負載平衡器的 SOAP API 進行整合。首先,需定義明確的需求,例如蒐集 CPU、記憶體使用率、系統概覽、虛擬伺服器狀態等資訊,以及啟用/停用服務等控制功能。程式碼結構上,建議建立一個名為 NSLib.py 的函式庫,包含 NSSoapApi、NSStatApi、NSConfigApi 等類別,分別處理 API 連線、統計資訊和組態管理。組態檔案 ns_config.py 則用於儲存負載平衡器的連線資訊,例如 IP 位址、帳號密碼等。由於 Citrix Netscaler 的 WSDL 檔案可能存在預設 IP 位址錯誤的問題,需要手動修改 Locator 類別中的 NSStatPort_address 變數,將其替換為正確的 IP 位址,確保 SOAP API 的正常運作。
管理裝置使用 SOAP API
在開始使用 SOAP API 管理裝置之前,必須先定義基本需求、程式碼結構、可組態專案以及錯誤處理和日誌記錄。這些步驟將有助於建立一個清晰的開發和需求規格檔案。
基本需求
定義基本需求是開發的第一步。這可以透過列出工具需要實作的功能來完成。例如:
- 蒐集 CPU 和記憶體使用率的統計資訊
- 蒐集系統概覽:請求率、資料率、已建立的連線數
- 蒐集所有虛擬伺服器的概覽:運作中/停止運作中以及每個虛擬伺服器中的服務狀態
- 能夠啟用/停用所有虛擬伺服器的服務
- 能夠啟用/停用個別服務
- 能夠啟用/停用一組服務(可能跨越多個虛擬伺服器)
- 重複使用定義的函式在其他指令碼中
- 程式碼應該易於修改和新增功能
程式碼結構
根據基本需求,可以定義程式碼結構。這包括:
- 建立一個名為
NSLib.py的函式庫,包含以下定義:NSLibError例外類別,用於處理不可還原的錯誤NSSoapApi類別,實作與 Netscaler SOAP API 物件相關的方法:初始化和登入NSStatApi類別,繼承NSSoapApi,實作與統計資訊蒐集和監控相關的方法NSConfigApi類別,繼承NSSoapApi,實作與負載平衡器組態相關的方法
- 建立
ns_stat.py指令碼,使用NSStatApi實作統計資訊蒐集任務 - 建立
ns_conf.py指令碼,使用NSConfigApi實作負載平衡器組態任務 - 建立
ns_config.py組態檔案,包含與負載平衡器通訊所需的定義
組態檔案
組態檔案 ns_config.py 包含多個負載平衡器的定義,包括登入詳細資訊和服務群組。例如:
netscalers = {
'default': 'primary',
'primary': {
'USERNAME': 'nstest',
'PASSWORD': 'nstest',
'NS_ADDR': '192.168.1.1',
'groups': {},
},
'secondary': {
'USERNAME': 'nstest',
'PASSWORD': 'nstest',
'NS_ADDR': '192.168.1.2',
'groups': {},
},
}
存取 Citrix Netscaler 負載平衡器使用 SOAP API
在使用 SOAP API 存取 Citrix Netscaler 負載平衡器之前,需要解決 WSDL 中的一個小問題。 Locator 類別中的 NSStatPort_address 變數需要被修改為正確的 IP 位址。
修復 Citrix Netscaler WSDL 中的問題
Locator 類別定義如下:
class NSStatServiceLocator:
NSStatPort_address = "http://netscaler_ip/soap/"
def getNSStatPortAddress(self):
return NSStatServiceLocator.NSStatPort_address
def getNSStatPort(self, url=None, **kw):
return NSStatBindingSOAP(url or NSStatServiceLocator.NSStatPort_address, **kw)
需要將 netscaler_ip 修改為正確的 IP 位址,例如 192.168.1.1。
修改後的 Locator 類別
class NSStatServiceLocator:
NSStatPort_address = "http://192.168.1.1/soap/"
def getNSStatPortAddress(self):
return NSStatServiceLocator.NSStatPort_address
def getNSStatPort(self, url=None, **kw):
return NSStatBindingSOAP(url or NSStatServiceLocator.NSStatPort_address, **kw)
內容解密:
此段落程式碼主要修改了 Locator 類別中的 NSStatPort_address 變數,將其修改為正確的 IP 位址。這樣做的目的是為了正確地存取 Citrix Netscaler 負載平衡器的 SOAP API。修改後的 Locator 類別可以正確地傳回 SOAP 連線埠的位址。
此修改是必要的,因為原始的 WSDL 檔案中包含了一個無效的 IP 位址。透過修改這個位址,可以確保 SOAP API 的正確使用。
此修改只需要在 WSDL 檔案被更新時再次進行,通常這只會在主要作業系統升級期間發生。
使用SOAP API管理裝置
建立與Netscaler的連線
在與Citrix Netscaler進行互動之前,需要先處理由wsdl2py工具生成的輔助模組。這些模組需要進行一些手動修改,以確保它們能夠正確地與Netscaler的SOAP API進行互動。
修改Locator類別
首先,觀察NSStatServiceLocator類別的原始碼,如下所示:
# Locator
class NSStatServiceLocator:
NSStatPort_address = "http://192.168.1.1/soap/"
def getNSStatPortAddress(self):
return NSStatServiceLocator.NSStatPort_address
def getNSStatPort(self, url=None, **kw):
return NSStatBindingSOAP(url or NSStatServiceLocator.NSStatPort_address, **kw)
內容解密:
NSStatServiceLocator類別:這個類別負責提供Netscaler的SOAP服務位置和建立連線。NSStatPort_address:預設的服務位址,這裡需要根據實際情況進行修改。getNSStatPortAddress方法:傳回服務位址。getNSStatPort方法:根據提供的URL(或預設URL)傳回一個SOAP連線物件。
建立連線物件
為了與Netscaler進行通訊,需要初始化Locator和服務存取物件。這可以透過以下兩行程式碼實作:
locator = NSStat_services.NSStatServiceLocator()
soap = locator.getNSStatPort()
內容解密:
locator物件:包含Web服務的位置資訊。soap物件:透過locator獲得的binding物件,包含了所有可用的API方法。
處理Netscaler無效URL問題
由於自動生成的模組可能包含無效的URL,需要手動替換。以下程式碼展示瞭如何實作這一點:
MY_NS_IP = '192.168.1.1'
locator = NSStat_services.NSStatServiceLocator()
bad_url = locator.getNSStatPortAddress()
good_url = re.sub('netscaler_ip', MY_NS_IP, bad_url)
soap = locator.getNSStatPort(url=good_url)
內容解密:
MY_NS_IP:定義了Netscaler的實際IP地址。bad_url和good_url:透過正規表示式替換無效的URL部分,生成正確的URL。soap物件:使用正確的URL初始化。
設計通用類別
為了提高程式碼的可重用性,設計了一個通用的NSSoapApi類別,可以根據不同的模組(例如統計或組態)進行初始化。
class NSSoapApi(object):
def __init__(self, module=None, hostname=None, username=None, password=None):
# 初始化引數
self.module = module
if self.module.__name__ == 'NSStat_services':
self.locator = self.module.NSStatServiceLocator()
# URL處理邏輯
self.soap = self.locator.getNSStatPort(url=good_url)
elif self.module.__name__ == 'NSConfig_services':
# 類別似的邏輯處理不同的模組
內容解密:
NSSoapApi類別:通用的基礎類別,能夠根據傳入的模組進行相應的初始化。- 模組特定處理:根據不同的模組名稱,執行特定的邏輯來初始化
locator和soap物件。
實作登入功能
在完成初始化後,第一個需要執行的API呼叫是登入。
def login(self):
req = self.module.login()
req._username = self.username
req._password = self.password
res = self.soap.login(req)._return
內容解密:
login方法:負責向Netscaler傳送登入請求。req物件:包含了登入所需的使用者名稱和密碼。res物件:儲存了登入操作的傳回結果。
使用SOAP API管理裝置
SOAP請求處理流程
使用產生的輔助程式函式庫(helper library)執行SOAP請求時,總是遵循相同的模式:
- 建立一個Request物件。
- 使用引數初始化Request物件,這些引數是傳遞給SOAP函式的引數列表。
- 呼叫代表適當SOAP方法的binder方法,並將Request物件傳遞給它。
- binder方法傳回API回應(如果無法連繫Web服務,則引發例外)。
登入功能的實作
由Locator傳回的binding物件屬於NSStatBindingSOAP類別。該類別的方法代表了Web服務上可用的所有功能。其中之一是登入功能,如Listing 2-12所示,我們將使用它來向負載平衡器進行身份驗證。
Listing 2-12:登入方法的定義
def login(self, request):
if isinstance(request, login) is False:
raise TypeError, "%s incorrect request type" % (request.__class__)
kw = {}
# 無輸入wsaction
self.binding.Send(None, None, request, soapaction="urn:NSConfigAction",
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/",
**kw)
# 無輸出wsaction
typecode = Struct(pname=None, ofwhat=loginResponse.typecode.ofwhat,
pyclass=loginResponse.typecode.pyclass)
response = self.binding.Receive(typecode)
return response
建立和初始化Request物件
Request物件必須從login類別建構,該類別可從相同的輔助模組中獲得。找出Request物件必須包含什麼內容的最簡單方法是檢視其定義;Listing 2-13顯示了我們例項中的內容。
Listing 2-13:登入請求類別
class login:
def __init__(self):
self._username = None
self._password = None
return
因此,在初始化新的Request物件時,我們必須在將其傳遞給binding物件之前設定_username和_password。
發出登入SOAP呼叫
Listing 2-14顯示了建立這些物件並發出登入SOAP呼叫的程式碼。
Listing 2-14:預設登入方法的包裝器
class NSSoapApi(object):
[...]
def login(self):
# 建立請求物件並賦予預設值
req = self.module.login()
req._username = self.username
req._password = self.password
[...]
res = self.soap.login(req)._return
if res._rc != 0:
# 發生錯誤
發出SOAP登入呼叫是一個兩步驟過程:
- 建立和初始化請求物件;該物件包含我們要傳送到Web服務的資料。
- 從binding物件呼叫適當的代理函式,並將Request物件傳遞給它。
程式碼解密:
req = self.module.login():建立一個新的登入請求物件。req._username = self.username和req._password = self.password:初始化請求物件,設定使用者名稱和密碼。res = self.soap.login(req)._return:呼叫binding物件的登入方法,傳遞請求物件,並接收回應。
瞭解回應內容
要了解我們從Web服務接收到的回應內容,需要檢視loginResponse類別。從Listing 2-16中,我們發現它只包含一個變數_return。
Listing 2-16:LoginResponse類別的內容
class loginResponse:
def __init__(self):
self._return = None
return
進一步檢視simpleResult類別的定義(Listing 2-17),我們可以瞭解_return物件的結構。
Listing 2-17:simpleResult類別的定義
# simpleResult類別的定義位於NSStat_services_types.py模組中
這個類別定義可能看起來有些複雜,但我們不需要了解其具體實作細節;只需檢視Holder類別的定義即可。