動態外掛程式是可為任何支援的傳輸節點 (例如 ESXi 主機) 建立的自訂外掛程式,用來檢查節點的健全狀況。
動態外掛程式可在執行階段安裝。它會執行以下功能:
- 為受影響的傳輸節點寫入系統記錄。
- 透過
run_command()
函數執行命令或 CLI。 - 讀取現有度量。
- 將資料匯出至 Wavefront (僅限 VMware Cloud 環境中)。
如果您具有管理 NSX 的專業技能,則可以建立動態外掛程式。VMware 支援團隊還可以建立動態外掛程式。
安全性管理
建立外掛程式後,必須將其提交給執行外掛程式程式碼檢閱的 VMware 工程團隊。檢閱完成後,工程團隊將在 GIT 存放庫中提交外掛程式、檢閱測試結果和程式碼變更,以進行驗證。如果動態外掛程式通過驗證,則會提交該外掛程式,並在 GIT 存放庫上觸發產品組建以建立可發佈所有動態外掛程式的新組建。使用以下 GIT 存放庫詳細資料:
- GitLab:https://gitlab.eng.vmware.com/core-build/nsbu-sha-plugin
- 產品:nsx-sha-plugins
- Gitreview 支援:由 VMware 團隊執行
您可以從組建的已發佈檔案取得所需的外掛程式。當您將已簽署的外掛程式上傳至管理平面時,管理平面會使用公開金鑰來驗證簽章,並確認此外掛程式有效。在管理平面驗證外掛程式後,會透過管理平面與中央控制平面 (CCP) 之間的安全通道,以及 CCP 與主機之間的安全通道,將外掛程式檔推送到目的地主機。
當您重新啟動系統健全狀況代理程式 (SHA) 執行個體時,它會再次從管理平面取得外掛程式檔案。由於所有檔案皆透過安全通道發佈,並且不使用任何暫存檔案,因此可以防止駭客修改指令碼的風險。
此外,為了防止有害程式碼的風險,SHA 會先使用 RestrictedPython 來檢查外掛程式 python 指令碼,然後再執行該指令碼。
版本管理
外掛程式可能會基於較新版本 NSX 中不支援的命令或工具,因此每個動態外掛程式必須在 manifest.yml 檔案中定義支援的 NSX 版本。對於所有支援的版本,版本應為 REGEX 字串。主機端上的 SHA 會檢查動態外掛程式的版本,並僅執行 REGEX 符合的版本。
-
定義主要版本支援的 NSX 版本。
假設多數命令和工具在相同主要版本中的次要版本之間不會變更,則下列方法是為所有次要版本定義版本的建議方式。
例如,
version: ^2\.5\.[0-9.]+ <== The custom plugin supporting all NSX 2.5 releases
- 發佈新的主要版本時,VMware 工程團隊必須檢閱提交的所有動態外掛程式。
- 當相關的命令或工具變更時,外掛程式寫入器必須更新指令碼。
安裝動態外掛程式
已安裝外掛程式的傳輸節點或 Edge 節點必須至少有 30 MB 的記憶體空間。此外,請注意,您最多僅能安裝 10 個外掛程式。外掛程式計數到達 10 個後,任何外掛程式的進一步安裝都會失敗。
- 在 GIT 存放庫中建立動態外掛程式檔案。如需有關外掛程式檔案的詳細資訊,請參閱〈動態外掛程式檔案〉一節。
- 在 GIT 存放庫中觸發產品組建,以產生動態外掛程式檔案的壓縮套件並下載該套件。
- 透過使用下列 API 搭配 POST 方法來建立動態外掛程式。
https://<manager_ip>/api/v1/systemhealth/plugins
- 使用下列 API 搭配 POST 方法,將外掛程式壓縮的套件上傳至管理平面。管理平面會擷壓縮上傳的檔案,並執行所需的驗證。
/systemhealth/plugins/<plugin-id>/files/<file-name>/data
備註: 外掛程式壓縮檔案的大小上限為 500k。 - 透過使用下列 API 搭配 POST 方法,來建立具有所需傳輸節點作為成員的節點群組。
/<manager_ip>/api/v1/ns-groups
- 透過使用下列 API 來建立新的服務組態,將外掛程式設定檔套用至節點群組。服務組態架構會將外掛程式內容傳送至節點群組。
https://<manager_ip>/api/v1/service-configs
如需有關 API 的詳細資訊,請參閱《NSX API 指南》說明文件。
取得外掛程式狀態
動態外掛程式執行後,它會透過現有的訊息通道自動將狀態上傳至管理平面。管理平面會彙總外掛程式狀態資訊,並將其儲存至資料庫。若要取得每個節點上所有外掛程式的狀態,請使用下列 API 搭配 GET 方法。
https://<manager_ip>/api/v1/systemhealth/plugins/status/<transport_node_id>
要求範例:
GET https://<manager_ip>/api/v1/systemhealth/plugins/status/a257b981-1a1c-4b95-b16c-8646
{ "result_count":1, "results": [ { "id": "72e1bd4b-6df6-42d0-9c59-a1c31312c9f1", "name": "health-check-compute", "status": "NORMAL", "detail": "" } ] }
解除安裝動態外掛程式
若要解除安裝外掛程式,請使用下列 API 移除服務組態。
https://<manager_ip>/api/v1/service-configs/<service_config_id>
用於管理外掛程式的其他 API
下表列出用於管理動態外掛程式的 API。如需有關 API 的詳細資訊,請參閱《NSX API 指南》說明文件。
工作 | 方法 | API |
---|---|---|
刪除外掛程式 | 刪除 | /systemhealth/plugins/<plugin-id> |
建立系統健全狀況設定檔 | POST | /systemhealth/profiles |
監控外掛程式狀態 |
GET | /systemhealth/plugins/status/<node-id> |
啟用外掛程式 | 啟用外掛程式為兩個步驟的程序,如下所示:
|
|
變更外掛程式間隔 | POST | 變更外掛程式間隔為兩個步驟的程序,如下所示:
|
動態外掛程式檔案
動態外掛程式包含下列檔案:
- 安裝規格檔案
安裝規格檔案 manifest.yml,包含系統健全狀況代理程式的下列資訊:
- 外掛程式結構
- 限制 (如果有)
- 如何安裝和使用外掛程式
- 健全狀況檢查指令碼的安全性限制。例如,指令碼具有的權限和指令碼可存取的檔案。
下表列出 manifest.yml 檔案中指定的欄位。名稱 說明 必要/選用 範例 classes 指定外掛程式指令碼中所需的類別。 類別必須以下列格式指定。「<module_name>.<class_name>」
選擇性 classes: ['datetime.datetime','datetime.date']
modules 指定外掛程式指令碼中所需的模組。 選擇性 modules: ['random', 'math'] plugin 指定外掛程式結構,如下所示:
config: 組態檔案名稱
script: 指令碼檔案名稱
必要 plugin:
config: plugin.cfg.yml
script: plugin.py
version 指定可在其上安裝此外掛程式的 NSX 版本。 必要 version: '^3\.1\.[0-9.]+'
node_type 指定可在其中安裝此外掛程式的 NSX 節點類型。可用節點類型為:
- nsx-esx
- nsx-bms
- nsx-edge
必要 node_type: ['nsx-esx']
metrics 指定可在外掛程式指令碼中使用的度量。 選擇性 metrics: ['nsx.host.host-metrics']
precondition 指定外掛程式的先決條件。可用的先決條件為 Wavefront。
備註: 此欄位僅適用於 VMware Cloud 環境。選擇性 precondition: ['wavefront']
請勿使用下列內建模組:-
os
-
subprocess
-
sys
-
multiprocessing
-
importlib
下表列出您必須使用的介面,以取代個別模組的內建函數。這些介面是由系統提供。您可以直接使用它們,而不需在 manifest.yml 檔案中指定其模組/類別。manifest.yml 檔案的範例。模組 內建函數 替代介面 datetime datetime.date.strftime(self, fmt) datetime_date_strftime(dt, fmt)
:param dt: 日期執行個體
:param fmt: 格式字串
datetime datetime.date.today() datetime_date_today() sys sys.getrecursionlimit() sys_getrecursionlimit() sys sys.getrefcount(object) sys_getrefcount(object) sys sys.getsizeof(object, default) sys_getsizeof(object, default) sys sys.maxsize sys_maxsize sys sys.path sys_path # specify classes needed in plugin script classes: ['datetime.datetime','datetime.date'] # specify modules needed in plugin script modules: ['random', 'math'] # plugin structure plugin: config: plugin.cfg.yml script: plugin.py # specify nsx versions on which this plugin can be installed version: '^3\.1\.[0-9.]+' # specify nsx node type where this plugin can be installed node_type: ['nsx-esx'] # specify metrics which can be consumed in plugin script metrics: ['nsx.host.host-metrics'] # specify precondition for plugin precondition: ['wavefront']
- 預設設定檔檔案
預設設定檔檔案 plugin.cfg.yml 可用來設定外掛程式行為,例如健全狀況檢查指令碼的執行頻率。若要變更預設組態,您可以為特定動態外掛程式建立 SHA 設定檔,並透過 NS 群組將其套用至傳輸節點,方法是使用管理平面到 CCP 到 NestDB 通道。
下表列出 plugin.cfg.yml 檔案中指定的欄位。名稱 說明 必要/選用 範例 CHECK_INTERVAL 指定外掛程式指令碼執行的預設間隔 (以秒為單位)。 必要 CHECK_INTERVAL: 20 ENABLE 指定是否依預設啟用外掛程式。 必要 ENABLE: true plugin.cfg.yml 檔案的範例。# Required field - default interval (unit: second) between plugin script executions. CHECK_INTERVAL: 20 # Required field - whether plugin is enabled by default ENABLE: true # Plugin user can add other fields as below if needed to control plugin script logic. EXPORT_DATA: true
- 健全狀況檢查指令碼
健全狀況檢查指令碼檔案 plugin.py 包含 python 指令碼,用於檢查傳輸節點的健全狀況狀態。
下表列出可供使用的系統定義變數和函數,以及可在 plugin.py 檔案中讀取的資料。變數/資料/函數 說明 類型 範例 logger 在 Syslog 中寫入記錄資訊。現有的系統定義變數 logger 可直接用於外掛程式指令碼。 輸出記錄的首碼會是外掛程式名稱和識別碼,如下列範例輸出所示。
2020-10-28T10:47:43Z nsx-sha: NSX 2101378 - [nsx@6876 comp="nsx-esx" subcomp="nsx-sha" username="root" level="INFO"] [name:hl-esx-002-04][id:a3eb14f1-d185-4bc7-bfaa-6cf888bbeb22] dynamic plugin - not export data
變數 logger.info("this is a demo log")
data_store 用於擷取系統所提供資料的現有系統定義字典。例如,profile、metric 和 host_id。
變數 profile = data_store['profile']
profile 設定檔資料是從預設設定檔 (plugin.cfg.yml) 或從 data_store 所讀取有效 SHA 設定檔 (使用者透過 Manager API 套用) 剖析的字典。它具有下列格式:
{'ENABLE': True, 'CHECK_INTERVAL': 20, 'EXPORT_DATA': True}
資料 profile = data_store['profile']
metric 度量是從 data_store 讀取、具有「value」和「timestamp」的字典。它具有下列格式:
data_store['metrics'][<metric_name>]
其中,
第一個索引鍵必須為「metrics」。
第二個索引鍵是現有的度量名稱。
資料 metric = data_store['metrics']['nsx.host.host-metrics']
metric is: {
‘value’:XXX, <== the collected data of the metric
‘timestamp’: XXX <== timestamp of the data collected
}
附註:外掛程式的第一次執行可能不會傳回度量,由於目前收集度量與外掛程式執行並非同步進行,因此可能無法在外掛程式第一次執行時收集度量。
host_id host_id 是從 data_store 所讀取類別 uuid.UUID 的執行個體。 資料 host_id = data_store['host_id']
run_command 此函數會以清單格式執行命令。它具有下列格式。 run_command(cmd, timeout=4)
其中,
- cmd:要執行的命令。必須採用如範例所示的清單格式。
- timeout:等待命令結果的逾時。預設逾時為 4 秒。不應將逾時設定為大於 20 秒。
此函數會傳回命令執行結果。
函數 cmd = ['nsxdp-cli', 'ipfix', 'settings', 'granular', 'get', '--dvs-alias', 'nsxvswitch', '--dvport=dafa09ca-33ed-4e04-ae3d-1c53305d5fe6']
res = run_command(cmd)
Exportdata 此函數會將資料匯出至 Wavefront。目前,動態外掛程式僅支援匯出至 Wavefront。 備註: 此函數僅適用於 VMware Cloud 環境。Exportdata: ExportData(data={}, exports=[], source=host_uuid)
其中,
data:要匯出的資料;資料應採用如範例所示的字典格式。
exports:匯出的目的地清單。在 HL 中,目的地僅支援 Wavefront。必要。
source:匯出的來源字串。這僅適用 Wavefront 目的地。此為選用,預設值為 NSX host_uuid。
此函數不會傳回任何值。
函數 Exportdata(data={'esx.plugin.stats': {'stats': {'gc-esx-001': data}}}, exports=['wavefront'])
plugin.py 檔案的範例。def report_test_data(edge_service_status): if edge_service_status == 'running': data = 2 else: data = 3 # examples on how to report data to wavefront. Exportdata(data={'esx.plugin.stats': {'stats': {'esx-dynamic-plugin-001': data}}}, exports=['wavefront']) def run(): # examples on how to write log. logger.debug("this is a debug message!") logger.info("this is a demo message!") # examples on how to use specified module in manifest. Take 'random' as an example. s_res = random.randint(1,10) logger.warn("random.randint(1,10)=%s", s_res) # examples on how to use specified class in manifest. Take 'datetime' and 'date' as an example. logger.info('date.ctime(datetime.now()):{}'.format(date.ctime(datetime.now()))) # examples on how to run cmd via interface run_command cmd = ['nsxdp-cli', 'ipfix', 'settings', 'granular', 'get', '--dvs-alias', 'nsxvswitch', '--dvport=dafa09ca-33ed-4e04-ae3d-1c53305d5fe6'] c_res = run_command(cmd) logger.error("run_command(cmd) res:%s", c_res) # examples on how to read existing metrics from data_store m_res = data_store['metrics']['nsx.host.host-metrics'] # examples on how to read effective profile from data_store profile = data_store['profile'] logger.error("data_store['metrics']['nsx.host.host-metrics']:%s, profile:%s", m_res, profile) # examples on how to read host_id from data_store host_id = data_store['host_id'] logger.info('host_id:{}'.format(host_id)) if profile['EXPORT_DATA']: report_test_data('running') logger.info("dynamic plugin - exported data to wavefront") else: logger.info("dynamic plugin - not export data ") # examples on how to use substitute interfaces for sys. logger.info("sys_path:{}".format(sys_path)) logger.info("sys_getsizeof(1):{}".format(sys_getsizeof(1))) logger.info("sys_getrefcount(cmd):{}".format(sys_getrefcount(cmd))) logger.info("sys_maxsize:{}".format(sys_maxsize)) logger.info("sys_getrecursionlimit():{}".format(sys_getrecursionlimit())) # examples on how to use substitute interfaces for datetime. today = datetime_date_today() logger.info("datetime today:{}".format(today)) logger.info("datetime_date_strftime now:{}".format(datetime_date_strftime(datetime.now(), '%H:%M'))) logger.info('date.ctime(today):{}'.format(date.ctime(today))) run()